/* * PROJECT: ReactOS Sound System "MME Buddy" Library * LICENSE: GPL - See COPYING in the top level directory * FILE: lib/drivers/sound/mmebuddy/mmewrap.c * * PURPOSE: Interface between MME functions and MME Buddy's own. * * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) */ #include #include #include #include #include #include /* Sets the device into running or stopped state */ MMRESULT MmeSetState( IN DWORD_PTR PrivateHandle, IN BOOL bStart) { MMRESULT Result; PMMFUNCTION_TABLE FunctionTable; PSOUND_DEVICE SoundDevice; PSOUND_DEVICE_INSTANCE SoundDeviceInstance; VALIDATE_MMSYS_PARAMETER( PrivateHandle ); SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Get the function table, and validate it */ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); SND_ASSERT( FunctionTable->SetState ); if ( FunctionTable->SetState == NULL ) { /* FIXME */ return MMSYSERR_NOTSUPPORTED; } /* Try change state */ Result = FunctionTable->SetState(SoundDeviceInstance, bStart); return Result; } /* Call the client application when something interesting happens (MME API defines "interesting things" as device open, close, and buffer completion.) */ VOID NotifyMmeClient( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN UINT Message, IN DWORD_PTR Parameter) { SND_ASSERT( SoundDeviceInstance ); SND_TRACE(L"MME client callback - message %d, parameter %d\n", (int) Message, (int) Parameter); if ( SoundDeviceInstance->WinMM.ClientCallback ) { DriverCallback(SoundDeviceInstance->WinMM.ClientCallback, HIWORD(SoundDeviceInstance->WinMM.Flags), SoundDeviceInstance->WinMM.Handle, Message, SoundDeviceInstance->WinMM.ClientCallbackInstanceData, Parameter, 0); } } /* This is a helper function to alleviate some of the repetition involved with implementing the various MME message functions. */ MMRESULT MmeGetSoundDeviceCapabilities( IN MMDEVICE_TYPE DeviceType, IN DWORD DeviceId, IN PVOID Capabilities, IN DWORD CapabilitiesSize) { PSOUND_DEVICE SoundDevice; MMRESULT Result; SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType); /* FIXME: Validate device ID */ VALIDATE_MMSYS_PARAMETER( Capabilities ); VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) ); /* Our parameter checks are done elsewhere */ Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); if ( ! MMSUCCESS(Result) ) return Result; return GetSoundDeviceCapabilities(SoundDevice, DeviceId, Capabilities, CapabilitiesSize); } MMRESULT MmeOpenWaveDevice( IN MMDEVICE_TYPE DeviceType, IN UINT DeviceId, IN LPWAVEOPENDESC OpenParameters, IN DWORD Flags, OUT DWORD_PTR* PrivateHandle) { MMRESULT Result; PSOUND_DEVICE SoundDevice; PSOUND_DEVICE_INSTANCE SoundDeviceInstance; LPWAVEFORMATEX Format; SND_TRACE(L"Opening wave device (WIDM_OPEN / WODM_OPEN)"); VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */ VALIDATE_MMSYS_PARAMETER( OpenParameters ); Format = OpenParameters->lpFormat; Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Does this device support the format? */ Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX)); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Format not supported\n"); return TranslateInternalMmResult(Result); } /* If the caller just wanted to know if a format is supported, end here */ if ( Flags & WAVE_FORMAT_QUERY ) return MMSYSERR_NOERROR; /* Check that winmm gave us a private handle to fill */ VALIDATE_MMSYS_PARAMETER( PrivateHandle ); /* Create a sound device instance and open the sound device */ Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX)); if ( ! MMSUCCESS(Result) ) { /* TODO: Destroy sound instance */ return TranslateInternalMmResult(Result); } /* Store the device instance pointer in the private handle */ *PrivateHandle = (DWORD_PTR)SoundDeviceInstance; /* Store the additional information we were given - FIXME: Need flags! */ SetSoundDeviceInstanceMmeData(SoundDeviceInstance, (HDRVR)OpenParameters->hWave, OpenParameters->dwCallback, OpenParameters->dwInstance, Flags); /* Let the application know the device is open */ ReleaseEntrypointMutex(DeviceType); NotifyMmeClient(SoundDeviceInstance, DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_OPEN : WIM_OPEN, 0); AcquireEntrypointMutex(DeviceType); SND_TRACE(L"Wave device now open\n"); return MMSYSERR_NOERROR; } MMRESULT MmeCloseDevice( IN DWORD_PTR PrivateHandle) { MMRESULT Result; PSOUND_DEVICE_INSTANCE SoundDeviceInstance; PSOUND_DEVICE SoundDevice; MMDEVICE_TYPE DeviceType; SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n"); VALIDATE_MMSYS_PARAMETER( PrivateHandle ); SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) ) return MMSYSERR_INVALHANDLE; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceType(SoundDevice, &DeviceType); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* TODO: Check device is stopped! */ ReleaseEntrypointMutex(DeviceType); /* TODO: Work with MIDI devices too */ NotifyMmeClient(SoundDeviceInstance, DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE, 0); AcquireEntrypointMutex(DeviceType); Result = DestroySoundDeviceInstance(SoundDeviceInstance); return Result; } MMRESULT MmeResetWavePlayback( IN DWORD_PTR PrivateHandle) { PSOUND_DEVICE_INSTANCE SoundDeviceInstance; SND_TRACE(L"Resetting wave device (WODM_RESET)\n"); VALIDATE_MMSYS_PARAMETER( PrivateHandle ); SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; return StopStreaming(SoundDeviceInstance); } MMRESULT MmeGetDeviceInterfaceString( IN MMDEVICE_TYPE DeviceType, IN DWORD DeviceId, IN LPWSTR Interface, IN DWORD InterfaceLength, OUT DWORD * InterfaceSize) { MMRESULT Result; PSOUND_DEVICE SoundDevice; PMMFUNCTION_TABLE FunctionTable; Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( FunctionTable->GetDeviceInterfaceString == NULL ) { /* querying device interface string / size not supported */ return MMSYSERR_NOTSUPPORTED; } /* Call the driver */ Result = FunctionTable->GetDeviceInterfaceString(DeviceType, DeviceId, Interface, InterfaceLength, InterfaceSize); return Result; } MMRESULT MmeGetPosition( IN MMDEVICE_TYPE DeviceType, IN DWORD DeviceId, IN DWORD_PTR PrivateHandle, IN MMTIME* Time, IN DWORD Size) { MMRESULT Result; PSOUND_DEVICE_INSTANCE SoundDeviceInstance; PSOUND_DEVICE SoundDevice; PMMFUNCTION_TABLE FunctionTable; VALIDATE_MMSYS_PARAMETER( PrivateHandle ); SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) ) return MMSYSERR_INVALHANDLE; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( Size != sizeof(MMTIME) ) return MMSYSERR_INVALPARAM; Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( FunctionTable->GetPos == NULL ) { /* This indicates bad practice, really! If you can open, why not close?! */ return MMSYSERR_NOTSUPPORTED; } /* Call the driver */ Result = FunctionTable->GetPos(SoundDeviceInstance, Time); return Result; }