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/mmewrap.c 5 * 6 * PURPOSE: Interface between MME functions and MME Buddy's own. 7 * 8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) 9 */ 10 11 #include "precomp.h" 12 13 14 /* 15 Sets the device into running or stopped state 16 */ 17 18 MMRESULT 19 MmeSetState( 20 IN DWORD_PTR PrivateHandle, 21 IN BOOL bStart) 22 { 23 MMRESULT Result; 24 PMMFUNCTION_TABLE FunctionTable; 25 PSOUND_DEVICE SoundDevice; 26 PSOUND_DEVICE_INSTANCE SoundDeviceInstance; 27 BOOL OldState; 28 29 VALIDATE_MMSYS_PARAMETER( PrivateHandle ); 30 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; 31 32 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 33 34 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 35 if ( ! MMSUCCESS(Result) ) 36 return TranslateInternalMmResult(Result); 37 38 /* Get the function table, and validate it */ 39 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 40 if ( ! MMSUCCESS(Result) ) 41 return TranslateInternalMmResult(Result); 42 43 SND_ASSERT( FunctionTable->SetState ); 44 if ( FunctionTable->SetState == NULL ) 45 { 46 /* FIXME */ 47 return MMSYSERR_NOTSUPPORTED; 48 } 49 /* Try change state */ 50 Result = FunctionTable->SetState(SoundDeviceInstance, bStart); 51 52 if ( MMSUCCESS(Result) ) 53 { 54 /* Get old audio stream state */ 55 OldState = SoundDeviceInstance->bPaused; 56 57 /* Store audio stream pause state */ 58 SoundDeviceInstance->bPaused = !bStart; 59 60 if (SoundDeviceInstance->bPaused == FALSE && OldState) 61 { 62 InitiateSoundStreaming(SoundDeviceInstance); 63 } 64 } 65 66 return Result; 67 } 68 69 /* 70 Call the client application when something interesting happens (MME API 71 defines "interesting things" as device open, close, and buffer 72 completion.) 73 */ 74 VOID 75 NotifyMmeClient( 76 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 77 IN UINT Message, 78 IN DWORD_PTR Parameter) 79 { 80 SND_ASSERT( SoundDeviceInstance ); 81 82 SND_TRACE(L"MME client callback - message %d, parameter %d\n", 83 (int) Message, 84 (int) Parameter); 85 86 if ( SoundDeviceInstance->WinMM.ClientCallback ) 87 { 88 DriverCallback(SoundDeviceInstance->WinMM.ClientCallback, 89 HIWORD(SoundDeviceInstance->WinMM.Flags), 90 SoundDeviceInstance->WinMM.Handle, 91 Message, 92 SoundDeviceInstance->WinMM.ClientCallbackInstanceData, 93 Parameter, 94 0); 95 } 96 } 97 98 /* 99 This is a helper function to alleviate some of the repetition involved with 100 implementing the various MME message functions. 101 */ 102 MMRESULT 103 MmeGetSoundDeviceCapabilities( 104 IN MMDEVICE_TYPE DeviceType, 105 IN DWORD DeviceId, 106 IN PVOID Capabilities, 107 IN DWORD CapabilitiesSize) 108 { 109 PSOUND_DEVICE SoundDevice; 110 MMRESULT Result; 111 112 SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType); 113 114 /* FIXME: Validate device ID */ 115 VALIDATE_MMSYS_PARAMETER( Capabilities ); 116 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) ); 117 118 /* Our parameter checks are done elsewhere */ 119 120 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); 121 122 if ( ! MMSUCCESS(Result) ) 123 return Result; 124 125 return GetSoundDeviceCapabilities(SoundDevice, 126 DeviceId, 127 Capabilities, 128 CapabilitiesSize); 129 } 130 131 MMRESULT 132 MmeOpenDevice( 133 IN MMDEVICE_TYPE DeviceType, 134 IN UINT DeviceId, 135 IN LPWAVEOPENDESC OpenParameters, 136 IN DWORD Flags, 137 OUT DWORD_PTR* PrivateHandle) 138 { 139 MMRESULT Result; 140 UINT Message; 141 PSOUND_DEVICE SoundDevice; 142 PSOUND_DEVICE_INSTANCE SoundDeviceInstance; 143 LPWAVEFORMATEX Format = NULL; 144 145 SND_TRACE(L"Opening device"); 146 147 VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) || IS_MIXER_DEVICE_TYPE(DeviceType) || IS_MIDI_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */ 148 VALIDATE_MMSYS_PARAMETER( OpenParameters ); 149 150 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); 151 if ( ! MMSUCCESS(Result) ) 152 return TranslateInternalMmResult(Result); 153 154 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) 155 { 156 Format = OpenParameters->lpFormat; 157 158 /* Does this device support the format? */ 159 Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX)); 160 if ( ! MMSUCCESS(Result) ) 161 { 162 SND_ERR(L"Format not supported\n"); 163 return TranslateInternalMmResult(Result); 164 } 165 166 /* If the caller just wanted to know if a format is supported, end here */ 167 if ( Flags & WAVE_FORMAT_QUERY ) 168 return MMSYSERR_NOERROR; 169 } 170 171 /* Check that winmm gave us a private handle to fill */ 172 VALIDATE_MMSYS_PARAMETER( PrivateHandle ); 173 174 /* Create a sound device instance and open the sound device */ 175 Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance); 176 if ( ! MMSUCCESS(Result) ) 177 return TranslateInternalMmResult(Result); 178 179 Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX)); 180 if ( ! MMSUCCESS(Result) ) 181 { 182 /* TODO: Destroy sound instance */ 183 return TranslateInternalMmResult(Result); 184 } 185 186 /* Store the device instance pointer in the private handle */ 187 *PrivateHandle = (DWORD_PTR)SoundDeviceInstance; 188 189 /* Store the additional information we were given - FIXME: Need flags! */ 190 SetSoundDeviceInstanceMmeData(SoundDeviceInstance, 191 (HDRVR)OpenParameters->hWave, /* works because LPMIXEROPENDESC/etc has also the handle as first member */ 192 OpenParameters->dwCallback, 193 OpenParameters->dwInstance, 194 Flags); 195 196 if (DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceType == WAVE_IN_DEVICE_TYPE || 197 DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceType == MIDI_IN_DEVICE_TYPE) 198 { 199 /* Let the application know the device is open */ 200 201 if (DeviceType == WAVE_OUT_DEVICE_TYPE) 202 Message = WOM_OPEN; 203 else if (DeviceType == WAVE_IN_DEVICE_TYPE) 204 Message = WIM_OPEN; 205 else if (DeviceType == MIDI_IN_DEVICE_TYPE) 206 Message = MIM_OPEN; 207 else 208 Message = MOM_OPEN; 209 210 ReleaseEntrypointMutex(DeviceType); 211 212 NotifyMmeClient(SoundDeviceInstance, 213 Message, 214 0); 215 216 AcquireEntrypointMutex(DeviceType); 217 } 218 219 SND_TRACE(L"device now open\n"); 220 221 return MMSYSERR_NOERROR; 222 } 223 224 MMRESULT 225 MmeCloseDevice( 226 IN DWORD_PTR PrivateHandle) 227 { 228 MMRESULT Result; 229 PSOUND_DEVICE_INSTANCE SoundDeviceInstance; 230 PSOUND_DEVICE SoundDevice; 231 MMDEVICE_TYPE DeviceType; 232 UINT Message = 0; 233 234 SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n"); 235 236 VALIDATE_MMSYS_PARAMETER( PrivateHandle ); 237 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; 238 239 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) ) 240 return MMSYSERR_INVALHANDLE; 241 242 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 243 if ( ! MMSUCCESS(Result) ) 244 return TranslateInternalMmResult(Result); 245 246 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 247 if ( ! MMSUCCESS(Result) ) 248 return TranslateInternalMmResult(Result); 249 250 251 /* TODO: Check device is stopped! */ 252 253 254 if (DeviceType != MIXER_DEVICE_TYPE) 255 { 256 ReleaseEntrypointMutex(DeviceType); 257 258 if (DeviceType == WAVE_OUT_DEVICE_TYPE) 259 Message = WOM_CLOSE; 260 else if (DeviceType == WAVE_IN_DEVICE_TYPE) 261 Message = WIM_CLOSE; 262 else if (DeviceType == MIDI_IN_DEVICE_TYPE) 263 Message = MIM_CLOSE; 264 else if (DeviceType == MIDI_OUT_DEVICE_TYPE) 265 Message = MOM_CLOSE; 266 267 /* TODO: Work with MIDI devices too */ 268 NotifyMmeClient(SoundDeviceInstance, 269 Message, 270 0); 271 AcquireEntrypointMutex(DeviceType); 272 } 273 274 Result = DestroySoundDeviceInstance(SoundDeviceInstance); 275 276 return Result; 277 } 278 279 MMRESULT 280 MmeResetWavePlayback( 281 IN DWORD_PTR PrivateHandle) 282 { 283 PSOUND_DEVICE_INSTANCE SoundDeviceInstance; 284 285 SND_TRACE(L"Resetting wave device (WODM_RESET)\n"); 286 287 VALIDATE_MMSYS_PARAMETER( PrivateHandle ); 288 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; 289 290 return StopStreaming(SoundDeviceInstance); 291 } 292 293 MMRESULT 294 MmeGetDeviceInterfaceString( 295 IN MMDEVICE_TYPE DeviceType, 296 IN DWORD DeviceId, 297 IN LPWSTR Interface, 298 IN DWORD InterfaceLength, 299 OUT DWORD * InterfaceSize) 300 { 301 MMRESULT Result; 302 PSOUND_DEVICE SoundDevice; 303 PMMFUNCTION_TABLE FunctionTable; 304 305 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); 306 if ( ! MMSUCCESS(Result) ) 307 return TranslateInternalMmResult(Result); 308 309 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 310 if ( ! MMSUCCESS(Result) ) 311 return TranslateInternalMmResult(Result); 312 313 if ( FunctionTable->GetDeviceInterfaceString == NULL ) 314 { 315 /* querying device interface string / size not supported */ 316 return MMSYSERR_NOTSUPPORTED; 317 } 318 319 /* Call the driver */ 320 Result = FunctionTable->GetDeviceInterfaceString(DeviceType, DeviceId, Interface, InterfaceLength, InterfaceSize); 321 322 return Result; 323 } 324 325 326 MMRESULT 327 MmeGetPosition( 328 IN MMDEVICE_TYPE DeviceType, 329 IN DWORD DeviceId, 330 IN DWORD_PTR PrivateHandle, 331 IN MMTIME* Time, 332 IN DWORD Size) 333 { 334 MMRESULT Result; 335 PSOUND_DEVICE_INSTANCE SoundDeviceInstance; 336 PSOUND_DEVICE SoundDevice; 337 PMMFUNCTION_TABLE FunctionTable; 338 339 VALIDATE_MMSYS_PARAMETER( PrivateHandle ); 340 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; 341 342 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) ) 343 return MMSYSERR_INVALHANDLE; 344 345 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 346 if ( ! MMSUCCESS(Result) ) 347 return TranslateInternalMmResult(Result); 348 349 if ( Size != sizeof(MMTIME) ) 350 return MMSYSERR_INVALPARAM; 351 352 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 353 if ( ! MMSUCCESS(Result) ) 354 return TranslateInternalMmResult(Result); 355 356 if ( FunctionTable->GetPos == NULL ) 357 { 358 /* This indicates bad practice, really! If you can open, why not close?! */ 359 return MMSYSERR_NOTSUPPORTED; 360 } 361 362 /* Call the driver */ 363 Result = FunctionTable->GetPos(SoundDeviceInstance, Time); 364 365 return Result; 366 } 367 368