1 /* 2 * PROJECT: ReactOS Sound System "MME Buddy" Library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: lib/drivers/sound/mmebuddy/deviceinstance.c 5 * 6 * PURPOSE: Manages instances of sound devices. 7 * 8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) 9 */ 10 11 #include "precomp.h" 12 13 /* 14 Restrain ourselves from flooding the kernel device! 15 */ 16 17 #define SOUND_KERNEL_BUFFER_COUNT 10 18 #define SOUND_KERNEL_BUFFER_SIZE 16384 19 20 MMRESULT 21 AllocateSoundDeviceInstance( 22 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance) 23 { 24 PSOUND_DEVICE_INSTANCE NewInstance; 25 26 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance ); 27 28 /* Allocate memory for the new instance */ 29 NewInstance = AllocateStruct(SOUND_DEVICE_INSTANCE); 30 31 if ( ! NewInstance ) 32 return MMSYSERR_NOMEM; 33 34 /* Use default frame size */ 35 NewInstance->FrameSize = SOUND_KERNEL_BUFFER_SIZE; 36 /* Use default buffer count */ 37 NewInstance->BufferCount = SOUND_KERNEL_BUFFER_COUNT; 38 39 /* Provide the caller with the new instance pointer */ 40 *SoundDeviceInstance = NewInstance; 41 42 return MMSYSERR_NOERROR; 43 } 44 45 VOID 46 FreeSoundDeviceInstance( 47 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) 48 { 49 /* 50 Device is marked as invalid by now, but we can still do some sanity 51 checking. 52 */ 53 SND_ASSERT( SoundDeviceInstance->Thread == NULL ); 54 55 ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE)); 56 FreeMemory(SoundDeviceInstance); 57 } 58 59 BOOLEAN 60 IsValidSoundDeviceInstance( 61 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) 62 { 63 PSOUND_DEVICE SoundDevice; 64 PSOUND_DEVICE_INSTANCE CurrentInstance; 65 66 if ( ! SoundDeviceInstance ) 67 return FALSE; 68 69 /* GetSoundDeviceFromInstance would send us into a recursive loop... */ 70 SoundDevice = SoundDeviceInstance->Device; 71 SND_ASSERT(SoundDevice); 72 73 CurrentInstance = SoundDevice->HeadInstance; 74 75 while ( CurrentInstance ) 76 { 77 if ( CurrentInstance == SoundDeviceInstance ) 78 return TRUE; 79 80 CurrentInstance = CurrentInstance->Next; 81 } 82 83 return FALSE; 84 } 85 86 MMRESULT 87 ListSoundDeviceInstance( 88 IN PSOUND_DEVICE SoundDevice, 89 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) 90 { 91 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); 92 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance ); 93 94 SND_TRACE(L"Listing sound device instance\n"); 95 96 if ( ! SoundDevice->HeadInstance ) 97 { 98 /* First entry - assign to head and tail */ 99 SoundDevice->HeadInstance = SoundDeviceInstance; 100 SoundDevice->TailInstance = SoundDeviceInstance; 101 } 102 else 103 { 104 /* Attach to the end */ 105 SoundDevice->TailInstance->Next = SoundDeviceInstance; 106 SoundDevice->TailInstance = SoundDeviceInstance; 107 } 108 109 return MMSYSERR_NOERROR; 110 } 111 112 MMRESULT 113 UnlistSoundDeviceInstance( 114 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) 115 { 116 MMRESULT Result; 117 PSOUND_DEVICE SoundDevice; 118 PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance; 119 120 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 121 122 SND_TRACE(L"Unlisting sound device instance\n"); 123 124 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 125 SND_ASSERT( MMSUCCESS(Result) ); 126 if ( ! MMSUCCESS(Result) ) 127 return TranslateInternalMmResult(Result); 128 129 PreviousInstance = NULL; 130 CurrentInstance = SoundDevice->HeadInstance; 131 132 while ( CurrentInstance ) 133 { 134 if ( CurrentInstance == SoundDeviceInstance ) 135 { 136 if ( ! PreviousInstance ) 137 { 138 /* This is the head node */ 139 SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next; 140 } 141 else 142 { 143 /* There are nodes before this one - cut ours out */ 144 PreviousInstance->Next = CurrentInstance->Next; 145 } 146 147 if ( ! CurrentInstance->Next ) 148 { 149 /* This is the tail node */ 150 SoundDevice->TailInstance = PreviousInstance; 151 } 152 } 153 154 PreviousInstance = CurrentInstance; 155 CurrentInstance = CurrentInstance->Next; 156 } 157 158 return MMSYSERR_NOERROR; 159 } 160 161 MMRESULT 162 CreateSoundDeviceInstance( 163 IN PSOUND_DEVICE SoundDevice, 164 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance) 165 { 166 MMRESULT Result; 167 PMMFUNCTION_TABLE FunctionTable; 168 169 SND_TRACE(L"Creating a sound device instance\n"); 170 171 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); 172 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL ); 173 174 Result = AllocateSoundDeviceInstance(SoundDeviceInstance); 175 176 if ( ! MMSUCCESS(Result) ) 177 return TranslateInternalMmResult(Result); 178 179 /* Get the "open" routine from the function table, and validate it */ 180 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 181 if ( ! MMSUCCESS(Result) ) 182 { 183 FreeSoundDeviceInstance(*SoundDeviceInstance); 184 return TranslateInternalMmResult(Result); 185 } 186 187 if ( FunctionTable->Open == NULL ) 188 { 189 FreeSoundDeviceInstance(*SoundDeviceInstance); 190 return MMSYSERR_NOTSUPPORTED; 191 } 192 193 /* Set up the members of the structure */ 194 (*SoundDeviceInstance)->Next = NULL; 195 (*SoundDeviceInstance)->Device = SoundDevice; 196 (*SoundDeviceInstance)->Handle = NULL; 197 (*SoundDeviceInstance)->Thread = NULL; 198 199 (*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE; 200 (*SoundDeviceInstance)->WinMM.ClientCallback = 0; 201 (*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0; 202 (*SoundDeviceInstance)->WinMM.Flags = 0; 203 204 /* Initialise the members of the struct used by the sound thread */ 205 (*SoundDeviceInstance)->HeadWaveHeader = NULL; 206 (*SoundDeviceInstance)->TailWaveHeader = NULL; 207 208 (*SoundDeviceInstance)->OutstandingBuffers = 0; 209 210 (*SoundDeviceInstance)->LoopsRemaining = 0; 211 212 /* Create the streaming thread (TODO - is this for wave only?) */ 213 Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread); 214 if ( ! MMSUCCESS(Result) ) 215 { 216 FreeSoundDeviceInstance(*SoundDeviceInstance); 217 return TranslateInternalMmResult(Result); 218 } 219 220 /* Add the instance to the list */ 221 Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance); 222 if ( ! MMSUCCESS(Result) ) 223 { 224 FreeSoundDeviceInstance(*SoundDeviceInstance); 225 return TranslateInternalMmResult(Result); 226 } 227 228 /* Try and open the device */ 229 Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle)); 230 if ( ! MMSUCCESS(Result) ) 231 { 232 UnlistSoundDeviceInstance(*SoundDeviceInstance); 233 FreeSoundDeviceInstance(*SoundDeviceInstance); 234 return TranslateInternalMmResult(Result); 235 } 236 237 return MMSYSERR_NOERROR; 238 } 239 240 MMRESULT 241 DestroySoundDeviceInstance( 242 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) 243 { 244 MMRESULT Result; 245 PMMFUNCTION_TABLE FunctionTable; 246 PSOUND_DEVICE SoundDevice; 247 PVOID Handle; 248 249 SND_TRACE(L"Destroying a sound device instance\n"); 250 251 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 252 253 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 254 if ( ! MMSUCCESS(Result) ) 255 return TranslateInternalMmResult(Result); 256 257 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); 258 if ( ! MMSUCCESS(Result) ) 259 return TranslateInternalMmResult(Result); 260 261 /* Get the "close" routine from the function table, and validate it */ 262 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 263 if ( ! MMSUCCESS(Result) ) 264 return TranslateInternalMmResult(Result); 265 266 SND_ASSERT( FunctionTable->Close ); 267 if ( FunctionTable->Close == NULL ) 268 { 269 /* This indicates bad practice, really! If you can open, why not close?! */ 270 return MMSYSERR_NOTSUPPORTED; 271 } 272 273 /* Stop the streaming thread */ 274 if ( SoundDeviceInstance->Thread ) 275 { 276 Result = DestroySoundThread(SoundDeviceInstance->Thread); 277 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ 278 if ( ! MMSUCCESS(Result ) ) 279 { 280 return TranslateInternalMmResult(Result); 281 } 282 } 283 284 /* Blank this out here */ 285 SoundDeviceInstance->Thread = NULL; 286 287 /* Try and close the device */ 288 Result = FunctionTable->Close(SoundDeviceInstance, Handle); 289 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ 290 if ( ! MMSUCCESS(Result) ) 291 return TranslateInternalMmResult(Result); 292 293 /* Drop it from the list */ 294 Result = UnlistSoundDeviceInstance(SoundDeviceInstance); 295 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ 296 if ( ! MMSUCCESS(Result) ) 297 return TranslateInternalMmResult(Result); 298 299 FreeSoundDeviceInstance(SoundDeviceInstance); 300 301 return MMSYSERR_NOERROR; 302 } 303 304 MMRESULT 305 DestroyAllSoundDeviceInstances( 306 IN PSOUND_DEVICE SoundDevice) 307 { 308 MMRESULT Result; 309 PSOUND_DEVICE_INSTANCE SoundDeviceInstance, NextDeviceInstance; 310 311 SoundDeviceInstance = SoundDevice->HeadInstance; 312 313 while ( SoundDeviceInstance ) 314 { 315 NextDeviceInstance = SoundDeviceInstance->Next; 316 Result = DestroySoundDeviceInstance(SoundDeviceInstance); 317 SND_ASSERT( MMSUCCESS(Result) ); 318 SoundDeviceInstance = NextDeviceInstance; 319 } 320 321 return MMSYSERR_NOERROR; 322 } 323 324 MMRESULT 325 GetSoundDeviceFromInstance( 326 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 327 OUT PSOUND_DEVICE* SoundDevice) 328 { 329 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 330 VALIDATE_MMSYS_PARAMETER( SoundDevice ); 331 332 *SoundDevice = SoundDeviceInstance->Device; 333 334 return MMSYSERR_NOERROR; 335 } 336 337 MMRESULT 338 GetSoundDeviceInstanceHandle( 339 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 340 OUT PVOID* Handle) 341 { 342 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 343 VALIDATE_MMSYS_PARAMETER( Handle ); 344 345 *Handle = SoundDeviceInstance->Handle; 346 347 return MMSYSERR_NOERROR; 348 } 349 350 MMRESULT 351 SetSoundDeviceInstanceMmeData( 352 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 353 IN HDRVR MmeHandle, 354 IN DWORD_PTR ClientCallback, 355 IN DWORD_PTR ClientCallbackData, 356 IN DWORD Flags) 357 { 358 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 359 360 SND_TRACE(L"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n", 361 MmeHandle, ClientCallback, ClientCallbackData, Flags); 362 363 SoundDeviceInstance->WinMM.Handle = MmeHandle; 364 SoundDeviceInstance->WinMM.ClientCallback = ClientCallback; 365 SoundDeviceInstance->WinMM.ClientCallbackInstanceData = ClientCallbackData; 366 SoundDeviceInstance->WinMM.Flags = Flags; 367 368 return MMSYSERR_NOERROR; 369 } 370