/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Configuration of network devices * FILE: dll/directx/dsound_new/misc.c * PURPOSE: Misc support routines * * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "precomp.h" const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}}; const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}; VOID PerformChannelConversion( PUCHAR Buffer, ULONG BufferLength, PULONG BytesRead, ULONG OldChannels, ULONG NewChannels, ULONG BitsPerSample, PUCHAR Result, ULONG ResultLength, PULONG BytesWritten) { DWORD Samples; DWORD NewIndex, OldIndex; DWORD NewLength, Skip; Samples = BufferLength / (BitsPerSample / 8) / OldChannels; if (NewChannels > OldChannels) { UNIMPLEMENTED ASSERT(0); } /* setup index */ NewIndex = 0; OldIndex = 0; /* calculate offsets */ NewLength = NewChannels * (BitsPerSample/8); Skip = OldChannels * (BitsPerSample/8); do { if (NewIndex + NewLength>= ResultLength) { NewIndex = ResultLength; break; } if (OldIndex + Skip >= BufferLength) { OldIndex = BufferLength; break; } /* copy first channel */ RtlMoveMemory(&Result[NewIndex], &Buffer[OldIndex], NewLength); /* skip other channels */ OldIndex += Skip; /* increment offset */ NewIndex += NewLength; }while(TRUE); *BytesRead = OldIndex; *BytesWritten = NewIndex; } BOOL SetPinFormat( IN HANDLE hPin, IN LPWAVEFORMATEX WaveFormatEx) { DWORD dwResult; KSPROPERTY Property; KSDATAFORMAT_WAVEFORMATEX DataFormat; /* setup connection request */ Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT; Property.Set = KSPROPSETID_Connection; Property.Flags = KSPROPERTY_TYPE_SET; /* setup data format */ DataFormat.WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag; DataFormat.WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec; DataFormat.WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign; DataFormat.WaveFormatEx.cbSize = 0; DataFormat.DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX); DataFormat.DataFormat.Flags = 0; DataFormat.DataFormat.Reserved = 0; DataFormat.DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; DataFormat.DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; DataFormat.DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; DataFormat.DataFormat.SampleSize = 4; DataFormat.WaveFormatEx.nChannels = WaveFormatEx->nChannels; DataFormat.WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec; DataFormat.WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample; dwResult = SyncOverlappedDeviceIoControl(hPin, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSPROPERTY),(LPVOID)&DataFormat, sizeof(KSDATAFORMAT_WAVEFORMATEX), NULL); if (dwResult == ERROR_SUCCESS) return TRUE; else return FALSE; } BOOL DoDataIntersection( HANDLE hFilter, DWORD PinId, DWORD SampleFrequency, LPWAVEFORMATEX WaveFormatEx, DWORD MinimumBitsPerSample, DWORD MaximumBitsPerSample, DWORD MaximumChannels, LPWAVEFORMATEX WaveFormatOut) { DWORD nChannels, nBitsPerSample; KSDATAFORMAT_WAVEFORMATEX WaveFormat; PKSP_PIN Pin; PKSMULTIPLE_ITEM Item; PKSDATAFORMAT_WAVEFORMATEX DataFormat; DWORD dwResult; /* allocate request */ Pin = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEX)); if (!Pin) { /* no memory */ return FALSE; } Item = (PKSMULTIPLE_ITEM)(Pin + 1); DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)(Item + 1); /* setup request */ Pin->PinId = PinId; Pin->Property.Flags = KSPROPERTY_TYPE_GET; Pin->Property.Set = KSPROPSETID_Pin; Pin->Property.Id = KSPROPERTY_PIN_DATAINTERSECTION; Item->Count = 1; Item->Size = sizeof(KSDATAFORMAT_WAVEFORMATEX); DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag; DataFormat->WaveFormatEx.nSamplesPerSec = SampleFrequency; DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign; DataFormat->WaveFormatEx.cbSize = 0; DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX); DataFormat->DataFormat.Flags = 0; DataFormat->DataFormat.Reserved = 0; DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; DataFormat->DataFormat.SampleSize = 4; for(nChannels = 1; nChannels <= 2; nChannels++) { for(nBitsPerSample = MinimumBitsPerSample; nBitsPerSample <= MaximumBitsPerSample; nBitsPerSample += 8) { DataFormat->WaveFormatEx.nChannels = nChannels; DataFormat->WaveFormatEx.nAvgBytesPerSec = (nBitsPerSample / 8) * nChannels * SampleFrequency; DataFormat->WaveFormatEx.wBitsPerSample = nBitsPerSample; DPRINT("CurrentFormat: InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\n", nChannels, nBitsPerSample, SampleFrequency); dwResult = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)Pin, sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEX), (LPVOID)&WaveFormat, sizeof(KSDATAFORMAT_WAVEFORMATEX), NULL); DPRINT("dwResult %x\n", dwResult); if (dwResult == ERROR_SUCCESS) { /* found a compatible audio range */ WaveFormatOut->cbSize = 0; WaveFormatOut->nBlockAlign = WaveFormatEx->nBlockAlign; WaveFormatOut->wFormatTag = WaveFormatEx->wFormatTag; WaveFormatOut->nAvgBytesPerSec = (nBitsPerSample / 8) * nChannels * SampleFrequency; WaveFormatOut->wBitsPerSample = nBitsPerSample; WaveFormatOut->nSamplesPerSec = SampleFrequency; WaveFormatOut->nChannels = nChannels; /* free buffer */ HeapFree(GetProcessHeap(), 0, Pin); DPRINT("InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n", WaveFormatEx->nChannels, WaveFormatEx->wBitsPerSample, WaveFormatEx->nSamplesPerSec, WaveFormatOut->nChannels, WaveFormatOut->wBitsPerSample, WaveFormatOut->nSamplesPerSec); return TRUE; } } } /* free buffer */ HeapFree(GetProcessHeap(), 0, Pin); ASSERT(0); return FALSE; } DWORD OpenPin( HANDLE hFilter, ULONG PinId, LPWAVEFORMATEX WaveFormatEx, PHANDLE hPin, BOOL bLoop) { DWORD Size, Result; PKSPIN_CONNECT PinConnect; PKSDATAFORMAT_WAVEFORMATEX DataFormat; /* calculate request size */ Size = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX); PinConnect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size); if (!PinConnect) { /* not enough memory */ return DSERR_OUTOFMEMORY; } /* build pin request */ PinConnect->Interface.Set = KSINTERFACESETID_Standard; if (bLoop) PinConnect->Interface.Id = KSINTERFACE_STANDARD_LOOPED_STREAMING; else PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING; PinConnect->Interface.Flags = 0; PinConnect->Medium.Set = KSMEDIUMSETID_Standard; PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE; PinConnect->Medium.Flags = 0; PinConnect->PinToHandle = NULL; PinConnect->PinId = PinId; PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL; PinConnect->Priority.PrioritySubClass = 1; DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1); /* initialize data format */ DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag; DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels; DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec; DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign; DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec; DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample; DataFormat->WaveFormatEx.cbSize = 0; DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX); DataFormat->DataFormat.Flags = 0; DataFormat->DataFormat.Reserved = 0; DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; DataFormat->DataFormat.SampleSize = 4; Result = KsCreatePin(hFilter, PinConnect, GENERIC_READ | GENERIC_WRITE, hPin); HeapFree(GetProcessHeap(), 0, PinConnect); return Result; } DWORD OpenFilter( IN LPCWSTR lpFileName, IN PHANDLE OutHandle) { HANDLE Handle; /* open the filter */ Handle = CreateFileW(lpFileName, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); /* check for success */ if (Handle == INVALID_HANDLE_VALUE) { DPRINT("Failed to open Filter %ws\n", lpFileName); return GetLastError(); } *OutHandle = Handle; return ERROR_SUCCESS; } DWORD SyncOverlappedDeviceIoControl( IN HANDLE Handle, IN DWORD IoControlCode, IN LPVOID InBuffer, IN DWORD InBufferSize, OUT LPVOID OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesTransferred OPTIONAL) { OVERLAPPED Overlapped; BOOLEAN IoResult; DWORD Transferred = 0; /* Overlapped I/O is done here - this is used for waiting for completion */ ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!Overlapped.hEvent) return GetLastError(); /* Talk to the device */ IoResult = DeviceIoControl(Handle, IoControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesTransferred, &Overlapped); /* If failure occurs, make sure it's not just due to the overlapped I/O */ if (!IoResult) { if ( GetLastError() != ERROR_IO_PENDING ) { CloseHandle(Overlapped.hEvent); return GetLastError(); } } /* Wait for the I/O to complete */ IoResult = GetOverlappedResult(Handle, &Overlapped, &Transferred, TRUE); /* Don't need this any more */ CloseHandle(Overlapped.hEvent); if (!IoResult) return GetLastError(); if ( BytesTransferred ) *BytesTransferred = Transferred; return ERROR_SUCCESS; } DWORD GetFilterPinCount( IN HANDLE hFilter, OUT PULONG NumPins) { KSPROPERTY Pin; *NumPins = 0; /* setup the pin request */ Pin.Flags = KSPROPERTY_TYPE_GET; Pin.Set = KSPROPSETID_Pin; Pin.Id = KSPROPERTY_PIN_CTYPES; /* query the device */ return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Pin, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), NULL); } DWORD GetFilterNodeProperty( IN HANDLE hFilter, IN ULONG PropertyId, OUT PKSMULTIPLE_ITEM *OutMultipleItem) { DWORD Status, BytesReturned; PKSMULTIPLE_ITEM MultipleItem; KSPROPERTY Property; /* setup query request */ Property.Id = PropertyId; Property.Flags = KSPROPERTY_TYPE_GET; Property.Set = KSPROPSETID_Topology; /* query the size */ Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned); if (Status != ERROR_MORE_DATA) { /* failed */ DPRINT("Failed to query PropertyId %lu ErrorCode %lx\n", PropertyId, Status); return Status; } MultipleItem = HeapAlloc(GetProcessHeap(), 0, BytesReturned); if (!MultipleItem) { /* not enough memory */ DPRINT("Failed to allocate %u Bytes\n", BytesReturned); return ERROR_OUTOFMEMORY; } /* retrieve data ranges */ Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)MultipleItem, BytesReturned, &BytesReturned); if (Status != ERROR_SUCCESS) { /* failed to get data ranges */ DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status); HeapFree(GetProcessHeap(), 0, MultipleItem); return Status; } /* save result */ *OutMultipleItem = MultipleItem; return Status; } DWORD GetFilterPinCommunication( IN HANDLE hFilter, IN ULONG PinId, OUT PKSPIN_COMMUNICATION Communication) { KSP_PIN Property; Property.Property.Flags = KSPROPERTY_TYPE_GET; Property.Property.Set = KSPROPSETID_Pin; Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION; Property.PinId = PinId; Property.Reserved = 0; return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)Communication, sizeof(KSPIN_COMMUNICATION), NULL); } DWORD GetFilterPinDataFlow( IN HANDLE hFilter, IN ULONG PinId, OUT PKSPIN_DATAFLOW DataFlow) { KSP_PIN Property; Property.Property.Flags = KSPROPERTY_TYPE_GET; Property.Property.Set = KSPROPSETID_Pin; Property.Property.Id = KSPROPERTY_PIN_DATAFLOW; Property.PinId = PinId; Property.Reserved = 0; return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)DataFlow, sizeof(KSPIN_DATAFLOW), NULL); } DWORD GetFilterPinDataRanges( IN HANDLE hFilter, IN ULONG PinId, IN OUT PKSMULTIPLE_ITEM * OutMultipleItem) { KSP_PIN Property; ULONG BytesReturned = 0; DWORD Status; PKSMULTIPLE_ITEM MultipleItem; /* prepare request */ Property.Reserved = 0; Property.PinId = PinId; Property.Property.Set = KSPROPSETID_Pin; Property.Property.Id = KSPROPERTY_PIN_DATARANGES; Property.Property.Flags = KSPROPERTY_TYPE_GET; /* retrieve size of data ranges buffer */ Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned); #if 0 if (Status != ERROR_MORE_DATA) { DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status); return Status; } #endif ASSERT(BytesReturned); MultipleItem = HeapAlloc(GetProcessHeap(), 0, BytesReturned); if (!MultipleItem) { /* not enough memory */ DPRINT("Failed to allocate %u Bytes\n", BytesReturned); return ERROR_OUTOFMEMORY; } /* retrieve data ranges */ Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)MultipleItem, BytesReturned, &BytesReturned); if (Status != ERROR_SUCCESS) { /* failed to get data ranges */ DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status); HeapFree(GetProcessHeap(), 0, MultipleItem); return Status; } /* save result */ *OutMultipleItem = MultipleItem; return Status; } BOOL CreateCompatiblePin( IN HANDLE hFilter, IN DWORD PinId, IN BOOL bLoop, IN LPWAVEFORMATEX WaveFormatEx, OUT LPWAVEFORMATEX WaveFormatOut, OUT PHANDLE hPin) { PKSMULTIPLE_ITEM Item = NULL; PKSDATARANGE_AUDIO AudioRange; DWORD dwResult; DWORD dwIndex, nChannels; dwResult = GetFilterPinDataRanges(hFilter, PinId, &Item); if (dwResult != ERROR_SUCCESS) { /* failed to get data ranges */ return FALSE; } CopyMemory(WaveFormatOut, WaveFormatEx, sizeof(WAVEFORMATEX)); /* iterate through all dataranges */ AudioRange = (PKSDATARANGE_AUDIO)(Item + 1); for(dwIndex = 0; dwIndex < Item->Count; dwIndex++) { if (AudioRange->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO)) { UNIMPLEMENTED AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize); continue; } if (WaveFormatOut->nSamplesPerSec < AudioRange->MinimumSampleFrequency) WaveFormatOut->nSamplesPerSec = AudioRange->MinimumSampleFrequency; else if (WaveFormatOut->nSamplesPerSec > AudioRange->MaximumSampleFrequency) WaveFormatOut->nSamplesPerSec = AudioRange->MaximumSampleFrequency; if (WaveFormatOut->wBitsPerSample < AudioRange->MinimumBitsPerSample) WaveFormatOut->wBitsPerSample = AudioRange->MinimumBitsPerSample; else if (WaveFormatOut->wBitsPerSample > AudioRange->MaximumBitsPerSample) WaveFormatOut->wBitsPerSample = AudioRange->MaximumBitsPerSample; DPRINT("MinimumBitsPerSample %u MaximumBitsPerSample %u MinimumSampleFrequency %u MaximumSampleFrequency %u\n", AudioRange->MinimumBitsPerSample, AudioRange->MaximumBitsPerSample, AudioRange->MinimumSampleFrequency, AudioRange->MaximumSampleFrequency); for(nChannels = 1; nChannels <= AudioRange->MaximumChannels; nChannels++) { WaveFormatOut->nChannels = nChannels; dwResult = OpenPin(hFilter, PinId, WaveFormatOut, hPin, TRUE); if (dwResult == ERROR_SUCCESS) { DPRINT("InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n", WaveFormatEx->nChannels, WaveFormatEx->wBitsPerSample, WaveFormatEx->nSamplesPerSec, WaveFormatOut->nChannels, WaveFormatOut->wBitsPerSample, WaveFormatOut->nSamplesPerSec); /* free buffer */ HeapFree(GetProcessHeap(), 0, Item); return TRUE; } } AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize); } /* free buffer */ HeapFree(GetProcessHeap(), 0, Item); return FALSE; }