MMRESULT SetNt4WaveDeviceFormat( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN DWORD DeviceId, IN LPWAVEFORMATEX Format, IN DWORD FormatSize) { MMRESULT Result; HANDLE Handle; VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); VALIDATE_MMSYS_PARAMETER( Format ); VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) ); Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); SND_TRACE(L"Setting wave device format on handle %x\n", Handle); Result = SyncOverlappedDeviceIoControl(Handle, IOCTL_WAVE_SET_FORMAT, (LPVOID) Format, FormatSize, NULL, 0, NULL); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); return MMSYSERR_NOERROR; }
MMRESULT MmeGetLineInfo( IN UINT DeviceId, IN UINT Message, IN DWORD_PTR PrivateHandle, IN DWORD_PTR Parameter1, IN DWORD_PTR Parameter2) { MMRESULT Result; PSOUND_DEVICE_INSTANCE SoundDeviceInstance; PSOUND_DEVICE SoundDevice; PMMFUNCTION_TABLE FunctionTable; //SND_TRACE(L"Getting mixer info %u\n", Message); if ( PrivateHandle == 0 ) { Result = GetSoundDevice(MIXER_DEVICE_TYPE, DeviceId, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = FunctionTable->QueryMixerInfo(NULL, DeviceId, Message, (LPVOID)Parameter1, Parameter2); return Result; } VALIDATE_MMSYS_PARAMETER( PrivateHandle ); SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( ! FunctionTable->QueryMixerInfo ) return MMSYSERR_NOTSUPPORTED; Result = FunctionTable->QueryMixerInfo(SoundDeviceInstance, DeviceId, Message, (LPVOID)Parameter1, Parameter2); return Result; }
MMRESULT WdmAudGetNumWdmDevsByLegacy( IN MMDEVICE_TYPE DeviceType, OUT DWORD* DeviceCount) { MMRESULT Result; WDMAUD_DEVICE_INFO DeviceInfo; VALIDATE_MMSYS_PARAMETER( KernelHandle != INVALID_HANDLE_VALUE ); VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) ); VALIDATE_MMSYS_PARAMETER( DeviceCount ); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_GETNUMDEVS_TYPE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS( Result ) ) { SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n"); *DeviceCount = 0; return TranslateInternalMmResult(Result); } *DeviceCount = DeviceInfo.DeviceCount; return MMSYSERR_NOERROR; }
MMRESULT QueryWaveDeviceFormatSupport( IN PSOUND_DEVICE SoundDevice, IN LPWAVEFORMATEX Format, IN DWORD FormatSize) { MMRESULT Result; MMDEVICE_TYPE DeviceType; PMMFUNCTION_TABLE FunctionTable; SND_TRACE(L"Querying wave format support\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( Format ); VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) ); Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); /* Ensure we have a wave device (TODO: check if this applies to wavein as well) */ VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* Obtain the function table */ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); SND_ASSERT( Result == MMSYSERR_NOERROR ); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( ! FunctionTable->QueryWaveFormatSupport ) return MMSYSERR_NOTSUPPORTED; return FunctionTable->QueryWaveFormatSupport(SoundDevice, Format, FormatSize); }
MMRESULT WdmAudGetWavePositionByLegacy( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN MMTIME* Time) { MMRESULT Result; PSOUND_DEVICE SoundDevice; WDMAUD_DEVICE_INFO DeviceInfo; MMDEVICE_TYPE DeviceType; HANDLE Handle; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); SND_ASSERT( Result == MMSYSERR_NOERROR ); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.hDevice = Handle; DeviceInfo.DeviceType = DeviceType; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_OPEN_WDMAUD, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Time->wType = TIME_BYTES; Time->u.cb = (DWORD)DeviceInfo.u.Position; return MMSYSERR_NOERROR; }
MMRESULT WdmAudCommitWaveBufferByMMixer( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID OffsetPtr, IN DWORD Length, IN PSOUND_OVERLAPPED Overlap, IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine) { PSOUND_DEVICE SoundDevice; MMDEVICE_TYPE DeviceType; MMRESULT Result; LPIO_PACKET Packet; HANDLE hThread; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); Packet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IO_PACKET)); if ( ! Packet ) { /* no memory */ return MMSYSERR_NOMEM; } /* setup stream packet */ Packet->Header.Size = sizeof(KSSTREAM_HEADER); Packet->Header.PresentationTime.Numerator = 1; Packet->Header.PresentationTime.Denominator = 1; Packet->Header.Data = OffsetPtr; Packet->Header.FrameExtent = Length; Packet->hDevice = SoundDeviceInstance->Handle; Packet->Overlap = Overlap; Packet->CompletionRoutine = CompletionRoutine; Packet->IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); if (DeviceType == WAVE_OUT_DEVICE_TYPE) { Packet->Header.DataUsed = Length; } hThread = CreateThread(NULL, 0, IoStreamingThread, (LPVOID)Packet, 0, NULL); if (hThread == NULL) { /* error */ return MMSYSERR_ERROR; } CloseHandle(hThread); return MMSYSERR_NOERROR; }
/* Querying/setting the format of a wave device. Querying format support requires us to first open the device, whereas setting format is done on an already opened device. */ MMRESULT QueryNt4WaveDeviceFormatSupport( IN PSOUND_DEVICE SoundDevice, IN LPWAVEFORMATEX Format, IN DWORD FormatSize) { MMRESULT Result; HANDLE Handle; SND_TRACE(L"NT4 wave format support querying routine called\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( Format ); VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) ); /* Get the device path */ Result = OpenNt4KernelSoundDevice(SoundDevice, FALSE, &Handle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Unable to open kernel sound device\n"); return TranslateInternalMmResult(Result); } Result = SyncOverlappedDeviceIoControl(Handle, IOCTL_WAVE_QUERY_FORMAT, (LPVOID) Format, FormatSize, NULL, 0, NULL); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Sync overlapped I/O failed - MMSYS_ERROR %d\n", Result); Result = TranslateInternalMmResult(Result); } CloseKernelSoundDevice(Handle); return MMSYSERR_NOERROR; }
MMRESULT WdmAudSetMixerDeviceFormatByLegacy( IN PSOUND_DEVICE_INSTANCE Instance, IN DWORD DeviceId, IN PWAVEFORMATEX WaveFormat, IN DWORD WaveFormatSize) { MMRESULT Result; WDMAUD_DEVICE_INFO DeviceInfo; HANDLE hThread; Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if ( ! Instance->hNotifyEvent ) return MMSYSERR_NOMEM; if (Instance->Handle != NULL) { /* device is already open */ return MMSYSERR_NOERROR; } Instance->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if ( ! Instance->hStopEvent ) return MMSYSERR_NOMEM; ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = MIXER_DEVICE_TYPE; DeviceInfo.DeviceIndex = DeviceId; DeviceInfo.u.hNotifyEvent = Instance->hNotifyEvent; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_OPEN_WDMAUD, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS(Result) ) { CloseHandle(Instance->hNotifyEvent); CloseHandle(Instance->hStopEvent); return TranslateInternalMmResult(Result); } hThread = CreateThread(NULL, 0, MixerEventThreadRoutine, (LPVOID)Instance, 0, NULL); if ( hThread ) { CloseHandle(hThread); } /* Store sound device handle instance handle */ Instance->Handle = (PVOID)DeviceInfo.hDevice; return MMSYSERR_NOERROR; }
MMRESULT SetWaveDeviceFormat( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN DWORD DeviceId, IN LPWAVEFORMATEX Format, IN DWORD FormatSize) { MMRESULT Result; MMDEVICE_TYPE DeviceType; PMMFUNCTION_TABLE FunctionTable; PSOUND_DEVICE SoundDevice; SND_TRACE(L"Setting wave format\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) { VALIDATE_MMSYS_PARAMETER( Format ); VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) ); } /* Ensure we have a wave device (TODO: check if this applies to wavein as well) */ VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) || IS_MIDI_DEVICE_TYPE(DeviceType) || IS_MIXER_DEVICE_TYPE(DeviceType)); /* Obtain the function table */ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); SND_ASSERT( Result == MMSYSERR_NOERROR ); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); if ( ! FunctionTable->SetWaveFormat ) return MMSYSERR_NOTSUPPORTED; return FunctionTable->SetWaveFormat(SoundDeviceInstance, DeviceId, Format, FormatSize); }
MMRESULT UnlistSoundDeviceInstance( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) { MMRESULT Result; PSOUND_DEVICE SoundDevice; PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance; VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); SND_TRACE(L"Unlisting sound device instance\n"); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); SND_ASSERT( MMSUCCESS(Result) ); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); PreviousInstance = NULL; CurrentInstance = SoundDevice->HeadInstance; while ( CurrentInstance ) { if ( CurrentInstance == SoundDeviceInstance ) { if ( ! PreviousInstance ) { /* This is the head node */ SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next; } else { /* There are nodes before this one - cut ours out */ PreviousInstance->Next = CurrentInstance->Next; } if ( ! CurrentInstance->Next ) { /* This is the tail node */ SoundDevice->TailInstance = PreviousInstance; } } PreviousInstance = CurrentInstance; CurrentInstance = CurrentInstance->Next; } return MMSYSERR_NOERROR; }
MMRESULT WdmAudSetWaveStateByLegacy( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN BOOL bStart) { MMRESULT Result; PSOUND_DEVICE SoundDevice; WDMAUD_DEVICE_INFO DeviceInfo; MMDEVICE_TYPE DeviceType; HANDLE Handle; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); SND_ASSERT( Result == MMSYSERR_NOERROR ); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.hDevice = Handle; DeviceInfo.DeviceType = DeviceType; if (bStart) DeviceInfo.u.State = KSSTATE_RUN; else DeviceInfo.u.State = KSSTATE_PAUSE; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); return Result; }
MMRESULT WdmAudCloseSoundDeviceByMMixer( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN PVOID Handle) { MMDEVICE_TYPE DeviceType; PSOUND_DEVICE SoundDevice; MMRESULT Result; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if (DeviceType == MIXER_DEVICE_TYPE) { /* no op */ return MMSYSERR_NOERROR; } else if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) { /* make sure the pin is stopped */ MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP); CloseHandle(Handle); return MMSYSERR_NOERROR; } /* midi is not supported */ return MMSYSERR_ERROR; }
/* Convenience routine for getting the path of a device and opening it. */ MMRESULT OpenNt4KernelSoundDevice( IN PSOUND_DEVICE SoundDevice, IN BOOLEAN ReadOnly, OUT PHANDLE Handle) { PWSTR Path; MMRESULT Result; VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( Handle ); Result = GetSoundDeviceIdentifier(SoundDevice, (PVOID*) &Path); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Unable to get sound device path"); return TranslateInternalMmResult(Result); } SND_ASSERT( Path ); return OpenKernelSoundDeviceByName(Path, ReadOnly, Handle); }
MMRESULT WdmAudSetWaveDeviceFormatByMMixer( IN PSOUND_DEVICE_INSTANCE Instance, IN DWORD DeviceId, IN PWAVEFORMATEX WaveFormat, IN DWORD WaveFormatSize) { MMDEVICE_TYPE DeviceType; PSOUND_DEVICE SoundDevice; MMRESULT Result; BOOL bWaveIn; Result = GetSoundDeviceFromInstance(Instance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); bWaveIn = (DeviceType == WAVE_IN_DEVICE_TYPE ? TRUE : FALSE); if (MMixerOpenWave(&MixerContext, DeviceId, bWaveIn, WaveFormat, NULL, NULL, &Instance->Handle) == MM_STATUS_SUCCESS) { if (DeviceType == WAVE_OUT_DEVICE_TYPE) { MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_ACQUIRE); MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_PAUSE); MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_RUN); } return MMSYSERR_NOERROR; } return MMSYSERR_ERROR; }
MMRESULT CreateSoundThread( OUT PSOUND_THREAD* Thread) { MMRESULT Result; PSOUND_THREAD NewThread; VALIDATE_MMSYS_PARAMETER( Thread ); NewThread = AllocateStruct(SOUND_THREAD); if ( ! NewThread ) return MMSYSERR_NOMEM; /* Prepare the events we'll be using to sync. everything */ Result = CreateSoundThreadEvents(&NewThread->Events.Ready, &NewThread->Events.Request, &NewThread->Events.Done); if ( ! MMSUCCESS(Result) ) { FreeMemory(NewThread); return TranslateInternalMmResult(Result); } SND_TRACE(L"Creating a sound thread\n"); NewThread->Handle = CreateThread(NULL, 0, &SoundThreadMain, (LPVOID) NewThread, CREATE_SUSPENDED, NULL); /* Something went wrong, bail out! */ if ( NewThread->Handle == INVALID_HANDLE_VALUE ) { SND_ERR(L"Sound thread creation failed!\n"); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* Wake the thread up */ if ( ResumeThread(NewThread->Handle) == -1 ) { SND_ERR(L"Failed to resume thread!\n"); CloseHandle(NewThread->Handle); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* If all is well we can now give the thread to the caller */ *Thread = NewThread; return MMSYSERR_NOERROR; }
MMRESULT WdmAudGetCapabilitiesByLegacy( IN PSOUND_DEVICE SoundDevice, IN DWORD DeviceId, OUT PVOID Capabilities, IN DWORD CapabilitiesSize) { MMRESULT Result; MMDEVICE_TYPE DeviceType; WDMAUD_DEVICE_INFO DeviceInfo; SND_ASSERT( SoundDevice ); SND_ASSERT( Capabilities ); Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if ( ! MMSUCCESS(Result) ) return Result; SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities DeviceType %u DeviceId %u\n", DeviceType, DeviceId); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; DeviceInfo.DeviceIndex = DeviceId; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_GETCAPABILITIES, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } /* This is pretty much a big hack right now */ switch ( DeviceType ) { case MIXER_DEVICE_TYPE: { LPMIXERCAPSW MixerCaps = (LPMIXERCAPSW) Capabilities; DeviceInfo.u.MixCaps.szPname[MAXPNAMELEN-1] = L'\0'; CopyWideString(MixerCaps->szPname, DeviceInfo.u.MixCaps.szPname); MixerCaps->cDestinations = DeviceInfo.u.MixCaps.cDestinations; MixerCaps->fdwSupport = DeviceInfo.u.MixCaps.fdwSupport; MixerCaps->vDriverVersion = DeviceInfo.u.MixCaps.vDriverVersion; MixerCaps->wMid = DeviceInfo.u.MixCaps.wMid; MixerCaps->wPid = DeviceInfo.u.MixCaps.wPid; break; } case WAVE_OUT_DEVICE_TYPE : { LPWAVEOUTCAPSW WaveOutCaps = (LPWAVEOUTCAPSW) Capabilities; DeviceInfo.u.WaveOutCaps.szPname[MAXPNAMELEN-1] = L'\0'; WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid; WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid; WaveOutCaps->vDriverVersion = DeviceInfo.u.WaveOutCaps.vDriverVersion; CopyWideString(WaveOutCaps->szPname, DeviceInfo.u.WaveOutCaps.szPname); WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats; WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels; WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport; break; } case WAVE_IN_DEVICE_TYPE : { LPWAVEINCAPSW WaveInCaps = (LPWAVEINCAPSW) Capabilities; DeviceInfo.u.WaveInCaps.szPname[MAXPNAMELEN-1] = L'\0'; WaveInCaps->wMid = DeviceInfo.u.WaveInCaps.wMid; WaveInCaps->wPid = DeviceInfo.u.WaveInCaps.wPid; WaveInCaps->vDriverVersion = DeviceInfo.u.WaveInCaps.vDriverVersion; CopyWideString(WaveInCaps->szPname, DeviceInfo.u.WaveInCaps.szPname); WaveInCaps->dwFormats = DeviceInfo.u.WaveInCaps.dwFormats; WaveInCaps->wChannels = DeviceInfo.u.WaveInCaps.wChannels; WaveInCaps->wReserved1 = 0; break; } case MIDI_IN_DEVICE_TYPE : { LPMIDIINCAPSW MidiInCaps = (LPMIDIINCAPSW)Capabilities; DeviceInfo.u.MidiInCaps.szPname[MAXPNAMELEN-1] = L'\0'; MidiInCaps->vDriverVersion = DeviceInfo.u.MidiInCaps.vDriverVersion; MidiInCaps->wMid = DeviceInfo.u.MidiInCaps.wMid; MidiInCaps->wPid = DeviceInfo.u.MidiInCaps.wPid; MidiInCaps->dwSupport = DeviceInfo.u.MidiInCaps.dwSupport; CopyWideString(MidiInCaps->szPname, DeviceInfo.u.MidiInCaps.szPname); break; } case MIDI_OUT_DEVICE_TYPE : { LPMIDIOUTCAPSW MidiOutCaps = (LPMIDIOUTCAPSW)Capabilities; DeviceInfo.u.MidiOutCaps.szPname[MAXPNAMELEN-1] = L'\0'; MidiOutCaps->vDriverVersion = DeviceInfo.u.MidiOutCaps.vDriverVersion; MidiOutCaps->wMid = DeviceInfo.u.MidiOutCaps.wMid; MidiOutCaps->wPid = DeviceInfo.u.MidiOutCaps.wPid; MidiOutCaps->dwSupport = DeviceInfo.u.MidiOutCaps.dwSupport; CopyWideString(MidiOutCaps->szPname, DeviceInfo.u.MidiOutCaps.szPname); break; } } return MMSYSERR_NOERROR; }
MMRESULT WdmAudCloseSoundDeviceByLegacy( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN PVOID Handle) { WDMAUD_DEVICE_INFO DeviceInfo; MMRESULT Result; MMDEVICE_TYPE DeviceType; PSOUND_DEVICE SoundDevice; Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } if ( OpenCount == 0 ) { return MMSYSERR_NOERROR; } SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE ); Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if (SoundDeviceInstance->Handle != (PVOID)KernelHandle) { ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; DeviceInfo.hDevice = SoundDeviceInstance->Handle; /* First stop the stream */ if (DeviceType != MIXER_DEVICE_TYPE) { DeviceInfo.u.State = KSSTATE_PAUSE; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); DeviceInfo.u.State = KSSTATE_ACQUIRE; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); DeviceInfo.u.State = KSSTATE_STOP; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); } SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_CLOSE_WDMAUD, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); } if (DeviceType == MIXER_DEVICE_TYPE) { SetEvent(SoundDeviceInstance->hStopEvent); CloseHandle(SoundDeviceInstance->hStopEvent); CloseHandle(SoundDeviceInstance->hNotifyEvent); } --OpenCount; if ( OpenCount < 1 ) { CloseHandle(KernelHandle); KernelHandle = INVALID_HANDLE_VALUE; } return MMSYSERR_NOERROR; }
/* Provides an implementation for the "get capabilities" request, using the standard IOCTLs used by NT4 sound drivers. */ MMRESULT GetNt4SoundDeviceCapabilities( IN PSOUND_DEVICE SoundDevice, OUT PVOID Capabilities, IN DWORD CapabilitiesSize) { MMRESULT Result; MMDEVICE_TYPE DeviceType; DWORD IoCtl; HANDLE DeviceHandle; /* If these are bad there's an internal error with MME-Buddy! */ SND_ASSERT( SoundDevice ); SND_ASSERT( Capabilities ); SND_ASSERT( CapabilitiesSize > 0 ); SND_TRACE(L"NT4 get-capabilities routine called\n"); /* Get the device type */ Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Choose the appropriate IOCTL */ if ( IS_WAVE_DEVICE_TYPE(DeviceType) ) { IoCtl = IOCTL_WAVE_GET_CAPABILITIES; } else if ( IS_MIDI_DEVICE_TYPE(DeviceType) ) { IoCtl = IOCTL_MIDI_GET_CAPABILITIES; } else { /* FIXME - need to support AUX and mixer devices */ SND_ASSERT( FALSE ); IoCtl = 0; } /* Get the capabilities information from the driver */ Result = OpenNt4KernelSoundDevice(SoundDevice, TRUE, &DeviceHandle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Failed to open device"); return TranslateInternalMmResult(Result); } Result = SyncOverlappedDeviceIoControl(DeviceHandle, IoCtl, Capabilities, CapabilitiesSize, NULL, 0, NULL); CloseKernelSoundDevice(DeviceHandle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Retrieval of capabilities information failed\n"); Result = TranslateInternalMmResult(Result); } return Result; }
MMRESULT WdmAudSetWaveDeviceFormatByLegacy( IN PSOUND_DEVICE_INSTANCE Instance, IN DWORD DeviceId, IN PWAVEFORMATEX WaveFormat, IN DWORD WaveFormatSize) { MMRESULT Result; PSOUND_DEVICE SoundDevice; PVOID Identifier; WDMAUD_DEVICE_INFO DeviceInfo; MMDEVICE_TYPE DeviceType; Result = GetSoundDeviceFromInstance(Instance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } if (Instance->Handle != NULL) { /* device is already open */ return MMSYSERR_NOERROR; } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; DeviceInfo.DeviceIndex = DeviceId; DeviceInfo.u.WaveFormatEx.cbSize = sizeof(WAVEFORMATEX); //WaveFormat->cbSize; DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag; #ifdef USERMODE_MIXER DeviceInfo.u.WaveFormatEx.nChannels = 2; DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 44100; DeviceInfo.u.WaveFormatEx.nBlockAlign = 4; DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 176400; DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16; #else DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels; DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec; DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign; DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec; DeviceInfo.u.WaveFormatEx.wBitsPerSample = (DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec * 8) / (DeviceInfo.u.WaveFormatEx.nSamplesPerSec * DeviceInfo.u.WaveFormatEx.nChannels); #endif Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_OPEN_WDMAUD, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } if (WaveFormatSize >= sizeof(WAVEFORMAT)) { /* Store format */ Instance->WaveFormatEx.wFormatTag = WaveFormat->wFormatTag; Instance->WaveFormatEx.nChannels = WaveFormat->nChannels; Instance->WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec; Instance->WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign; Instance->WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec; } /* store details */ Instance->WaveFormatEx.cbSize = sizeof(WAVEFORMATEX); Instance->WaveFormatEx.wBitsPerSample = (DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec * 8) / (DeviceInfo.u.WaveFormatEx.nSamplesPerSec * DeviceInfo.u.WaveFormatEx.nChannels); /* Store sound device handle instance handle */ Instance->Handle = (PVOID)DeviceInfo.hDevice; /* Now determine framing requirements */ Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_GETFRAMESIZE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( MMSUCCESS(Result) ) { if (DeviceInfo.u.FrameSize) { Instance->FrameSize = DeviceInfo.u.FrameSize * 2; Instance->BufferCount = WaveFormat->nAvgBytesPerSec / Instance->FrameSize; SND_TRACE(L"FrameSize %u BufferCount %u\n", Instance->FrameSize, Instance->BufferCount); } } else { // use a default of 100 buffers Instance->BufferCount = 100; } /* Now acquire resources */ DeviceInfo.u.State = KSSTATE_ACQUIRE; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); /* pause the pin */ DeviceInfo.u.State = KSSTATE_PAUSE; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); /* start the pin */ DeviceInfo.u.State = KSSTATE_RUN; SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); return MMSYSERR_NOERROR; }
MMRESULT WdmAudCommitWaveBufferByLegacy( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID OffsetPtr, IN DWORD Length, IN PSOUND_OVERLAPPED Overlap, IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine) { HANDLE Handle; MMRESULT Result; PWDMAUD_DEVICE_INFO DeviceInfo; PSOUND_DEVICE SoundDevice; MMDEVICE_TYPE DeviceType; BOOL Ret; VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance ); VALIDATE_MMSYS_PARAMETER( OffsetPtr ); VALIDATE_MMSYS_PARAMETER( Overlap ); VALIDATE_MMSYS_PARAMETER( CompletionRoutine ); GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); SND_ASSERT(Handle); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); DeviceInfo = (PWDMAUD_DEVICE_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WDMAUD_DEVICE_INFO)); if (!DeviceInfo) { // no memory return MMSYSERR_NOMEM; } DeviceInfo->Header.FrameExtent = Length; if (DeviceType == WAVE_OUT_DEVICE_TYPE) { DeviceInfo->Header.DataUsed = Length; } DeviceInfo->Header.Data = OffsetPtr; DeviceInfo->Header.Size = sizeof(WDMAUD_DEVICE_INFO); DeviceInfo->Header.PresentationTime.Numerator = 1; DeviceInfo->Header.PresentationTime.Denominator = 1; DeviceInfo->hDevice = Handle; DeviceInfo->DeviceType = DeviceType; // create completion event Overlap->Standard.hEvent = Handle = CreateEventW(NULL, FALSE, FALSE, NULL); if (Overlap->Standard.hEvent == NULL) { // no memory HeapFree(GetProcessHeap(), 0, DeviceInfo); return MMSYSERR_NOMEM; } Overlap->OriginalCompletionRoutine = CompletionRoutine; Overlap->CompletionContext = (PVOID)DeviceInfo; if (DeviceType == WAVE_OUT_DEVICE_TYPE) { Ret = WriteFileEx(KernelHandle, DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, LegacyCompletionRoutine); if (Ret) WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE); } else if (DeviceType == WAVE_IN_DEVICE_TYPE) { Ret = ReadFileEx(KernelHandle, DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, LegacyCompletionRoutine); if (Ret) WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE); } // close event handle CloseHandle(Handle); return MMSYSERR_NOERROR; }
MMRESULT DestroySoundDeviceInstance( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) { MMRESULT Result; PMMFUNCTION_TABLE FunctionTable; PSOUND_DEVICE SoundDevice; PVOID Handle; SND_TRACE(L"Destroying a sound device instance\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Get the "close" routine from the function table, and validate it */ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); SND_ASSERT( FunctionTable->Close ); if ( FunctionTable->Close == NULL ) { /* This indicates bad practice, really! If you can open, why not close?! */ return MMSYSERR_NOTSUPPORTED; } /* Stop the streaming thread */ if ( SoundDeviceInstance->Thread ) { Result = DestroySoundThread(SoundDeviceInstance->Thread); SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ if ( ! MMSUCCESS(Result ) ) { return TranslateInternalMmResult(Result); } } /* Blank this out here */ SoundDeviceInstance->Thread = NULL; /* Try and close the device */ Result = FunctionTable->Close(SoundDeviceInstance, Handle); SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Drop it from the list */ Result = UnlistSoundDeviceInstance(SoundDeviceInstance); SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */ if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); FreeSoundDeviceInstance(SoundDeviceInstance); return MMSYSERR_NOERROR; }
MMRESULT CreateSoundDeviceInstance( IN PSOUND_DEVICE SoundDevice, OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance) { MMRESULT Result; PMMFUNCTION_TABLE FunctionTable; SND_TRACE(L"Creating a sound device instance\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL ); Result = AllocateSoundDeviceInstance(SoundDeviceInstance); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Get the "open" routine from the function table, and validate it */ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); if ( ! MMSUCCESS(Result) ) { FreeSoundDeviceInstance(*SoundDeviceInstance); return TranslateInternalMmResult(Result); } if ( FunctionTable->Open == NULL ) { FreeSoundDeviceInstance(*SoundDeviceInstance); return MMSYSERR_NOTSUPPORTED; } /* Set up the members of the structure */ (*SoundDeviceInstance)->Next = NULL; (*SoundDeviceInstance)->Device = SoundDevice; (*SoundDeviceInstance)->Handle = NULL; (*SoundDeviceInstance)->Thread = NULL; (*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE; (*SoundDeviceInstance)->WinMM.ClientCallback = 0; (*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0; (*SoundDeviceInstance)->WinMM.Flags = 0; /* Initialise the members of the struct used by the sound thread */ (*SoundDeviceInstance)->HeadWaveHeader = NULL; (*SoundDeviceInstance)->TailWaveHeader = NULL; (*SoundDeviceInstance)->OutstandingBuffers = 0; (*SoundDeviceInstance)->LoopsRemaining = 0; /* Create the streaming thread (TODO - is this for wave only?) */ Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread); if ( ! MMSUCCESS(Result) ) { FreeSoundDeviceInstance(*SoundDeviceInstance); return TranslateInternalMmResult(Result); } /* Add the instance to the list */ Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance); if ( ! MMSUCCESS(Result) ) { FreeSoundDeviceInstance(*SoundDeviceInstance); return TranslateInternalMmResult(Result); } /* Try and open the device */ Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle)); if ( ! MMSUCCESS(Result) ) { UnlistSoundDeviceInstance(*SoundDeviceInstance); FreeSoundDeviceInstance(*SoundDeviceInstance); return TranslateInternalMmResult(Result); } return MMSYSERR_NOERROR; }
MMRESULT WdmAudGetDeviceInterfaceStringByLegacy( IN MMDEVICE_TYPE DeviceType, IN DWORD DeviceId, IN LPWSTR Interface, IN DWORD InterfaceLength, OUT DWORD * InterfaceSize) { WDMAUD_DEVICE_INFO DeviceInfo; MMRESULT Result; ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; DeviceInfo.DeviceIndex = DeviceId; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_QUERYDEVICEINTERFACESTRING, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS(Result) ) { return TranslateInternalMmResult(Result); } if (!Interface) { SND_ASSERT(InterfaceSize); *InterfaceSize = DeviceInfo.u.Interface.DeviceInterfaceStringSize; return MMSYSERR_NOERROR; } if (InterfaceLength < DeviceInfo.u.Interface.DeviceInterfaceStringSize) { /* buffer is too small */ return MMSYSERR_MOREDATA; } DeviceInfo.u.Interface.DeviceInterfaceStringSize = InterfaceLength; DeviceInfo.u.Interface.DeviceInterfaceString = Interface; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_QUERYDEVICEINTERFACESTRING, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( MMSUCCESS(Result) && InterfaceLength > 2) { Interface[1] = L'\\'; Interface[InterfaceLength-1] = L'\0'; } return Result; }