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
14 /* Each session is tracked, but the list must be locked when in use */
16 SessionInfo
* session_list
= NULL
;
17 CRITICAL_SECTION session_lock
;
21 Obtains a pointer to the session associated with a device type and ID.
22 If no session exists, returns NULL. This is mainly used to see if a
23 session already exists prior to creating a new one.
28 DeviceType device_type
,
31 SessionInfo
* session_info
;
33 EnterCriticalSection(&session_lock
);
34 session_info
= session_list
;
36 while ( session_info
)
38 if ( ( session_info
->device_type
== device_type
) &&
39 ( session_info
->device_id
== device_id
) )
41 LeaveCriticalSection(&session_lock
);
45 session_info
= session_info
->next
;
48 LeaveCriticalSection(&session_lock
);
54 Creates a new session, associated with the specified device type and ID.
55 Whilst the session list is locked, this also checks to see if an existing
56 session is associated with the device.
61 DeviceType device_type
,
63 SessionInfo
** session_info
)
65 HANDLE heap
= GetProcessHeap();
69 EnterCriticalSection(&session_lock
);
71 /* Ensure we're not creating a duplicate session */
73 if ( GetSession(device_type
, device_id
) )
75 DPRINT("Already allocated session\n");
76 LeaveCriticalSection(&session_lock
);
77 return MMSYSERR_ALLOCATED
;
80 *session_info
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, sizeof(SessionInfo
));
82 if ( ! *session_info
)
84 DPRINT("Failed to allocate mem for session info\n");
85 LeaveCriticalSection(&session_lock
);
86 return MMSYSERR_NOMEM
;
89 (*session_info
)->device_type
= device_type
;
90 (*session_info
)->device_id
= device_id
;
94 (*session_info
)->next
= session_list
;
95 session_list
= *session_info
;
97 LeaveCriticalSection(&session_lock
);
99 return MMSYSERR_NOERROR
;
104 Removes a session from the list and destroys it. This function does NOT
105 perform any additional cleanup. Think of it as a slightly more advanced
110 DestroySession(SessionInfo
* session
)
112 HANDLE heap
= GetProcessHeap();
113 SessionInfo
* session_node
;
114 SessionInfo
* session_prev
;
116 /* TODO: More cleanup stuff */
118 /* Remove from the list */
120 EnterCriticalSection(&session_lock
);
122 session_node
= session_list
;
125 while ( session_node
)
127 if ( session_node
== session
)
129 /* Bridge the gap for when we go */
130 session_prev
->next
= session
->next
;
134 /* Save the previous node, fetch the next */
135 session_prev
= session_node
;
136 session_node
= session_node
->next
;
139 LeaveCriticalSection(&session_lock
);
141 HeapFree(heap
, 0, session
);
146 Allocates events and other resources for the session thread, starts it,
147 and waits for it to announce that it is ready to work for us.
151 StartSessionThread(SessionInfo
* session_info
)
156 ASSERT(session_info
);
158 /* This is our "ready" event, sent when the thread is idle */
160 session_info
->thread
.ready_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
162 if ( ! session_info
->thread
.ready_event
)
164 DPRINT("Couldn't create thread_ready event\n");
165 return MMSYSERR_NOMEM
;
168 /* This is our "go" event, sent when we want the thread to do something */
170 session_info
->thread
.go_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
172 if ( ! session_info
->thread
.go_event
)
174 DPRINT("Couldn't create thread_go event\n");
175 CloseHandle(session_info
->thread
.ready_event
);
176 return MMSYSERR_NOMEM
;
179 /* TODO - other kinds of devices need attention, too */
180 task
= ( session_info
->device_type
== WaveOutDevice
)
181 ? (LPTASKCALLBACK
) WaveThread
: NULL
;
185 /* Effectively, this is a beefed-up CreateThread */
187 result
= mmTaskCreate(task
,
188 &session_info
->thread
.handle
,
189 (DWORD_PTR
)session_info
);
191 if ( result
!= MMSYSERR_NOERROR
)
193 DPRINT("Task creation failed\n");
194 CloseHandle(session_info
->thread
.ready_event
);
195 CloseHandle(session_info
->thread
.go_event
);
199 /* Wait for the thread to be ready before completing */
201 WaitForSingleObject(session_info
->thread
.ready_event
, INFINITE
);
203 return MMSYSERR_NOERROR
;
208 The session thread is pretty simple. Upon creation, it announces that it
209 is ready to do stuff for us. When we want it to perform an action, we use
210 CallSessionThread with an appropriate function and parameter, then tell
211 the thread we want it to do something. When it's finished, it announces
212 that it is ready once again.
217 SessionInfo
* session_info
,
218 ThreadFunction function
,
219 PVOID thread_parameter
)
221 ASSERT(session_info
);
223 session_info
->thread
.function
= function
;
224 session_info
->thread
.parameter
= thread_parameter
;
226 DPRINT("Calling session thread\n");
227 SetEvent(session_info
->thread
.go_event
);
229 DPRINT("Waiting for thread response\n");
230 WaitForSingleObject(session_info
->thread
.ready_event
, INFINITE
);
232 return session_info
->thread
.result
;
237 HandleBySessionThread(
238 DWORD_PTR private_handle
,
242 return CallSessionThread((SessionInfo
*) private_handle
,