3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Multimedia
5 * FILE: dll/win32/mmdrv/session.c
6 * PURPOSE: Multimedia User Mode Driver (session management)
7 * PROGRAMMER: Andrew Greenwood
9 * Jan 14, 2007: Created
17 /* Each session is tracked, but the list must be locked when in use */
19 SessionInfo
* session_list
= NULL
;
20 CRITICAL_SECTION session_lock
;
24 Obtains a pointer to the session associated with a device type and ID.
25 If no session exists, returns NULL. This is mainly used to see if a
26 session already exists prior to creating a new one.
31 DeviceType device_type
,
34 SessionInfo
* session_info
;
36 EnterCriticalSection(&session_lock
);
37 session_info
= session_list
;
39 while ( session_info
)
41 if ( ( session_info
->device_type
== device_type
) &&
42 ( session_info
->device_id
== device_id
) )
44 LeaveCriticalSection(&session_lock
);
48 session_info
= session_info
->next
;
51 LeaveCriticalSection(&session_lock
);
57 Creates a new session, associated with the specified device type and ID.
58 Whilst the session list is locked, this also checks to see if an existing
59 session is associated with the device.
64 DeviceType device_type
,
66 SessionInfo
** session_info
)
68 HANDLE heap
= GetProcessHeap();
72 EnterCriticalSection(&session_lock
);
74 /* Ensure we're not creating a duplicate session */
76 if ( GetSession(device_type
, device_id
) )
78 DPRINT("Already allocated session\n");
79 LeaveCriticalSection(&session_lock
);
80 return MMSYSERR_ALLOCATED
;
83 *session_info
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, sizeof(SessionInfo
));
85 if ( ! *session_info
)
87 DPRINT("Failed to allocate mem for session info\n");
88 LeaveCriticalSection(&session_lock
);
89 return MMSYSERR_NOMEM
;
92 (*session_info
)->device_type
= device_type
;
93 (*session_info
)->device_id
= device_id
;
97 (*session_info
)->next
= session_list
;
98 session_list
= *session_info
;
100 LeaveCriticalSection(&session_lock
);
102 return MMSYSERR_NOERROR
;
107 Removes a session from the list and destroys it. This function does NOT
108 perform any additional cleanup. Think of it as a slightly more advanced
113 DestroySession(SessionInfo
* session
)
115 HANDLE heap
= GetProcessHeap();
116 SessionInfo
* session_node
;
117 SessionInfo
* session_prev
;
119 /* TODO: More cleanup stuff */
121 /* Remove from the list */
123 EnterCriticalSection(&session_lock
);
125 session_node
= session_list
;
128 while ( session_node
)
130 if ( session_node
== session
)
132 /* Bridge the gap for when we go */
133 session_prev
->next
= session
->next
;
137 /* Save the previous node, fetch the next */
138 session_prev
= session_node
;
139 session_node
= session_node
->next
;
142 LeaveCriticalSection(&session_lock
);
144 HeapFree(heap
, 0, session
);
149 Allocates events and other resources for the session thread, starts it,
150 and waits for it to announce that it is ready to work for us.
154 StartSessionThread(SessionInfo
* session_info
)
159 ASSERT(session_info
);
161 /* This is our "ready" event, sent when the thread is idle */
163 session_info
->thread
.ready_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
165 if ( ! session_info
->thread
.ready_event
)
167 DPRINT("Couldn't create thread_ready event\n");
168 return MMSYSERR_NOMEM
;
171 /* This is our "go" event, sent when we want the thread to do something */
173 session_info
->thread
.go_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
175 if ( ! session_info
->thread
.go_event
)
177 DPRINT("Couldn't create thread_go event\n");
178 CloseHandle(session_info
->thread
.ready_event
);
179 return MMSYSERR_NOMEM
;
182 /* TODO - other kinds of devices need attention, too */
183 task
= ( session_info
->device_type
== WaveOutDevice
)
184 ? (LPTASKCALLBACK
) WaveThread
: NULL
;
188 /* Effectively, this is a beefed-up CreateThread */
190 result
= mmTaskCreate(task
,
191 &session_info
->thread
.handle
,
192 (DWORD_PTR
)session_info
);
194 if ( result
!= MMSYSERR_NOERROR
)
196 DPRINT("Task creation failed\n");
197 CloseHandle(session_info
->thread
.ready_event
);
198 CloseHandle(session_info
->thread
.go_event
);
202 /* Wait for the thread to be ready before completing */
204 WaitForSingleObject(session_info
->thread
.ready_event
, INFINITE
);
206 return MMSYSERR_NOERROR
;
211 The session thread is pretty simple. Upon creation, it announces that it
212 is ready to do stuff for us. When we want it to perform an action, we use
213 CallSessionThread with an appropriate function and parameter, then tell
214 the thread we want it to do something. When it's finished, it announces
215 that it is ready once again.
220 SessionInfo
* session_info
,
221 ThreadFunction function
,
222 PVOID thread_parameter
)
224 ASSERT(session_info
);
226 session_info
->thread
.function
= function
;
227 session_info
->thread
.parameter
= thread_parameter
;
229 DPRINT("Calling session thread\n");
230 SetEvent(session_info
->thread
.go_event
);
232 DPRINT("Waiting for thread response\n");
233 WaitForSingleObject(session_info
->thread
.ready_event
, INFINITE
);
235 return session_info
->thread
.result
;
240 HandleBySessionThread(
241 DWORD_PTR private_handle
,
245 return CallSessionThread((SessionInfo
*) private_handle
,