2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of network devices
4 * FILE: dll/directx/dsound_new/misc.c
5 * PURPOSE: Misc support routines
7 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
12 const GUID KSPROPSETID_Pin
= {0x8C134960L
, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
13 const GUID KSPROPSETID_Topology
= {0x720D4AC0L
, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
14 const GUID KSPROPSETID_Audio
= {0x45FFAAA0L
, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
18 PerformChannelConversion(
30 DWORD NewIndex
, OldIndex
;
31 DWORD NewLength
, Skip
;
33 Samples
= BufferLength
/ (BitsPerSample
/ 8) / OldChannels
;
35 if (NewChannels
> OldChannels
)
45 /* calculate offsets */
46 NewLength
= NewChannels
* (BitsPerSample
/8);
47 Skip
= OldChannels
* (BitsPerSample
/8);
51 if (NewIndex
+ NewLength
>= ResultLength
)
53 NewIndex
= ResultLength
;
57 if (OldIndex
+ Skip
>= BufferLength
)
59 OldIndex
= BufferLength
;
63 /* copy first channel */
64 RtlMoveMemory(&Result
[NewIndex
], &Buffer
[OldIndex
], NewLength
);
66 /* skip other channels */
69 /* increment offset */
70 NewIndex
+= NewLength
;
74 *BytesRead
= OldIndex
;
75 *BytesWritten
= NewIndex
;
82 IN LPWAVEFORMATEX WaveFormatEx
)
86 KSDATAFORMAT_WAVEFORMATEX DataFormat
;
88 /* setup connection request */
89 Property
.Id
= KSPROPERTY_CONNECTION_DATAFORMAT
;
90 Property
.Set
= KSPROPSETID_Connection
;
91 Property
.Flags
= KSPROPERTY_TYPE_SET
;
93 /* setup data format */
94 DataFormat
.WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
95 DataFormat
.WaveFormatEx
.nSamplesPerSec
= WaveFormatEx
->nSamplesPerSec
;
96 DataFormat
.WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
97 DataFormat
.WaveFormatEx
.cbSize
= 0;
98 DataFormat
.DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
99 DataFormat
.DataFormat
.Flags
= 0;
100 DataFormat
.DataFormat
.Reserved
= 0;
101 DataFormat
.DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
102 DataFormat
.DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
103 DataFormat
.DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
104 DataFormat
.DataFormat
.SampleSize
= 4;
105 DataFormat
.WaveFormatEx
.nChannels
= WaveFormatEx
->nChannels
;
106 DataFormat
.WaveFormatEx
.nAvgBytesPerSec
= WaveFormatEx
->nAvgBytesPerSec
;
107 DataFormat
.WaveFormatEx
.wBitsPerSample
= WaveFormatEx
->wBitsPerSample
;
109 dwResult
= SyncOverlappedDeviceIoControl(hPin
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSPROPERTY
),(LPVOID
)&DataFormat
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), NULL
);
111 if (dwResult
== ERROR_SUCCESS
)
122 DWORD SampleFrequency
,
123 LPWAVEFORMATEX WaveFormatEx
,
124 DWORD MinimumBitsPerSample
,
125 DWORD MaximumBitsPerSample
,
126 DWORD MaximumChannels
,
127 LPWAVEFORMATEX WaveFormatOut
)
129 DWORD nChannels
, nBitsPerSample
;
130 KSDATAFORMAT_WAVEFORMATEX WaveFormat
;
132 PKSMULTIPLE_ITEM Item
;
133 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
136 /* allocate request */
137 Pin
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(KSP_PIN
) + sizeof(KSMULTIPLE_ITEM
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
144 Item
= (PKSMULTIPLE_ITEM
)(Pin
+ 1);
145 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(Item
+ 1);
149 Pin
->Property
.Flags
= KSPROPERTY_TYPE_GET
;
150 Pin
->Property
.Set
= KSPROPSETID_Pin
;
151 Pin
->Property
.Id
= KSPROPERTY_PIN_DATAINTERSECTION
;
153 Item
->Size
= sizeof(KSDATAFORMAT_WAVEFORMATEX
);
156 DataFormat
->WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
157 DataFormat
->WaveFormatEx
.nSamplesPerSec
= SampleFrequency
;
158 DataFormat
->WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
159 DataFormat
->WaveFormatEx
.cbSize
= 0;
160 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
161 DataFormat
->DataFormat
.Flags
= 0;
162 DataFormat
->DataFormat
.Reserved
= 0;
163 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
164 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
165 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
166 DataFormat
->DataFormat
.SampleSize
= 4;
168 for(nChannels
= 1; nChannels
<= 2; nChannels
++)
170 for(nBitsPerSample
= MinimumBitsPerSample
; nBitsPerSample
<= MaximumBitsPerSample
; nBitsPerSample
+= 8)
172 DataFormat
->WaveFormatEx
.nChannels
= nChannels
;
173 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= (nBitsPerSample
/ 8) * nChannels
* SampleFrequency
;
174 DataFormat
->WaveFormatEx
.wBitsPerSample
= nBitsPerSample
;
176 DPRINT("CurrentFormat: InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\n",
177 nChannels
, nBitsPerSample
, SampleFrequency
);
179 dwResult
= SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)Pin
, sizeof(KSP_PIN
) + sizeof(KSMULTIPLE_ITEM
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
),
180 (LPVOID
)&WaveFormat
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), NULL
);
182 DPRINT("dwResult %x\n", dwResult
);
185 if (dwResult
== ERROR_SUCCESS
)
187 /* found a compatible audio range */
188 WaveFormatOut
->cbSize
= 0;
189 WaveFormatOut
->nBlockAlign
= WaveFormatEx
->nBlockAlign
;
190 WaveFormatOut
->wFormatTag
= WaveFormatEx
->wFormatTag
;
191 WaveFormatOut
->nAvgBytesPerSec
= (nBitsPerSample
/ 8) * nChannels
* SampleFrequency
;
192 WaveFormatOut
->wBitsPerSample
= nBitsPerSample
;
193 WaveFormatOut
->nSamplesPerSec
= SampleFrequency
;
194 WaveFormatOut
->nChannels
= nChannels
;
197 HeapFree(GetProcessHeap(), 0, Pin
);
199 DPRINT("InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n",
200 WaveFormatEx
->nChannels
, WaveFormatEx
->wBitsPerSample
, WaveFormatEx
->nSamplesPerSec
,
201 WaveFormatOut
->nChannels
, WaveFormatOut
->wBitsPerSample
, WaveFormatOut
->nSamplesPerSec
);
209 HeapFree(GetProcessHeap(), 0, Pin
);
218 LPWAVEFORMATEX WaveFormatEx
,
223 PKSPIN_CONNECT PinConnect
;
224 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
226 /* calculate request size */
227 Size
= sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
);
229 PinConnect
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Size
);
232 /* not enough memory */
233 return DSERR_OUTOFMEMORY
;
235 /* build pin request */
236 PinConnect
->Interface
.Set
= KSINTERFACESETID_Standard
;
239 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_LOOPED_STREAMING
;
241 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_STREAMING
;
243 PinConnect
->Interface
.Flags
= 0;
244 PinConnect
->Medium
.Set
= KSMEDIUMSETID_Standard
;
245 PinConnect
->Medium
.Id
= KSMEDIUM_TYPE_ANYINSTANCE
;
246 PinConnect
->Medium
.Flags
= 0;
247 PinConnect
->PinToHandle
= NULL
;
248 PinConnect
->PinId
= PinId
;
249 PinConnect
->Priority
.PriorityClass
= KSPRIORITY_NORMAL
;
250 PinConnect
->Priority
.PrioritySubClass
= 1;
252 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
) (PinConnect
+ 1);
254 /* initialize data format */
255 DataFormat
->WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
256 DataFormat
->WaveFormatEx
.nChannels
= WaveFormatEx
->nChannels
;
257 DataFormat
->WaveFormatEx
.nSamplesPerSec
= WaveFormatEx
->nSamplesPerSec
;
258 DataFormat
->WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
259 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= WaveFormatEx
->nAvgBytesPerSec
;
260 DataFormat
->WaveFormatEx
.wBitsPerSample
= WaveFormatEx
->wBitsPerSample
;
261 DataFormat
->WaveFormatEx
.cbSize
= 0;
262 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
263 DataFormat
->DataFormat
.Flags
= 0;
264 DataFormat
->DataFormat
.Reserved
= 0;
265 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
267 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
268 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
269 DataFormat
->DataFormat
.SampleSize
= 4;
271 Result
= KsCreatePin(hFilter
, PinConnect
, GENERIC_READ
| GENERIC_WRITE
, hPin
);
273 HeapFree(GetProcessHeap(), 0, PinConnect
);
281 IN LPCWSTR lpFileName
,
282 IN PHANDLE OutHandle
)
286 /* open the filter */
287 Handle
= CreateFileW(lpFileName
, GENERIC_WRITE
| GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
, NULL
);
289 /* check for success */
290 if (Handle
== INVALID_HANDLE_VALUE
)
292 DPRINT("Failed to open Filter %ws\n", lpFileName
);
293 return GetLastError();
297 return ERROR_SUCCESS
;
301 SyncOverlappedDeviceIoControl(
303 IN DWORD IoControlCode
,
305 IN DWORD InBufferSize
,
306 OUT LPVOID OutBuffer
,
307 IN DWORD OutBufferSize
,
308 OUT LPDWORD BytesTransferred OPTIONAL
)
310 OVERLAPPED Overlapped
;
312 DWORD Transferred
= 0;
314 /* Overlapped I/O is done here - this is used for waiting for completion */
315 ZeroMemory(&Overlapped
, sizeof(OVERLAPPED
));
316 Overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
318 if (!Overlapped
.hEvent
)
319 return GetLastError();
321 /* Talk to the device */
322 IoResult
= DeviceIoControl(Handle
,
331 /* If failure occurs, make sure it's not just due to the overlapped I/O */
334 if ( GetLastError() != ERROR_IO_PENDING
)
336 CloseHandle(Overlapped
.hEvent
);
337 return GetLastError();
341 /* Wait for the I/O to complete */
342 IoResult
= GetOverlappedResult(Handle
,
347 /* Don't need this any more */
348 CloseHandle(Overlapped
.hEvent
);
351 return GetLastError();
353 if ( BytesTransferred
)
354 *BytesTransferred
= Transferred
;
356 return ERROR_SUCCESS
;
368 /* setup the pin request */
369 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
370 Pin
.Set
= KSPROPSETID_Pin
;
371 Pin
.Id
= KSPROPERTY_PIN_CTYPES
;
373 /* query the device */
374 return SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)NumPins
, sizeof(ULONG
), NULL
);
378 GetFilterNodeProperty(
381 OUT PKSMULTIPLE_ITEM
*OutMultipleItem
)
383 DWORD Status
, BytesReturned
;
384 PKSMULTIPLE_ITEM MultipleItem
;
387 /* setup query request */
388 Property
.Id
= PropertyId
;
389 Property
.Flags
= KSPROPERTY_TYPE_GET
;
390 Property
.Set
= KSPROPSETID_Topology
;
393 Status
= SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &BytesReturned
);
395 if (Status
!= ERROR_MORE_DATA
)
398 DPRINT("Failed to query PropertyId %lu ErrorCode %lx\n", PropertyId
, Status
);
402 MultipleItem
= HeapAlloc(GetProcessHeap(), 0, BytesReturned
);
405 /* not enough memory */
406 DPRINT("Failed to allocate %u Bytes\n", BytesReturned
);
407 return ERROR_OUTOFMEMORY
;
410 /* retrieve data ranges */
411 Status
= SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSP_PIN
), (LPVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
414 if (Status
!= ERROR_SUCCESS
)
416 /* failed to get data ranges */
417 DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status
);
419 HeapFree(GetProcessHeap(), 0, MultipleItem
);
424 *OutMultipleItem
= MultipleItem
;
430 GetFilterPinCommunication(
433 OUT PKSPIN_COMMUNICATION Communication
)
437 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
438 Property
.Property
.Set
= KSPROPSETID_Pin
;
439 Property
.Property
.Id
= KSPROPERTY_PIN_COMMUNICATION
;
440 Property
.PinId
= PinId
;
441 Property
.Reserved
= 0;
443 return SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSP_PIN
), (LPVOID
)Communication
, sizeof(KSPIN_COMMUNICATION
), NULL
);
447 GetFilterPinDataFlow(
450 OUT PKSPIN_DATAFLOW DataFlow
)
454 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
455 Property
.Property
.Set
= KSPROPSETID_Pin
;
456 Property
.Property
.Id
= KSPROPERTY_PIN_DATAFLOW
;
457 Property
.PinId
= PinId
;
458 Property
.Reserved
= 0;
460 return SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSP_PIN
), (LPVOID
)DataFlow
, sizeof(KSPIN_DATAFLOW
), NULL
);
464 GetFilterPinDataRanges(
467 IN OUT PKSMULTIPLE_ITEM
* OutMultipleItem
)
470 ULONG BytesReturned
= 0;
472 PKSMULTIPLE_ITEM MultipleItem
;
474 /* prepare request */
475 Property
.Reserved
= 0;
476 Property
.PinId
= PinId
;
477 Property
.Property
.Set
= KSPROPSETID_Pin
;
478 Property
.Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
479 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
481 /* retrieve size of data ranges buffer */
482 Status
= SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
485 if (Status
!= ERROR_MORE_DATA
)
487 DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status
);
492 ASSERT(BytesReturned
);
493 MultipleItem
= HeapAlloc(GetProcessHeap(), 0, BytesReturned
);
496 /* not enough memory */
497 DPRINT("Failed to allocate %u Bytes\n", BytesReturned
);
498 return ERROR_OUTOFMEMORY
;
501 /* retrieve data ranges */
502 Status
= SyncOverlappedDeviceIoControl(hFilter
, IOCTL_KS_PROPERTY
, (LPVOID
)&Property
, sizeof(KSP_PIN
), (LPVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
505 if (Status
!= ERROR_SUCCESS
)
507 /* failed to get data ranges */
508 DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status
);
510 HeapFree(GetProcessHeap(), 0, MultipleItem
);
515 *OutMultipleItem
= MultipleItem
;
524 IN LPWAVEFORMATEX WaveFormatEx
,
525 OUT LPWAVEFORMATEX WaveFormatOut
,
528 PKSMULTIPLE_ITEM Item
= NULL
;
529 PKSDATARANGE_AUDIO AudioRange
;
531 DWORD dwIndex
, nChannels
;
533 dwResult
= GetFilterPinDataRanges(hFilter
, PinId
, &Item
);
535 if (dwResult
!= ERROR_SUCCESS
)
537 /* failed to get data ranges */
541 CopyMemory(WaveFormatOut
, WaveFormatEx
, sizeof(WAVEFORMATEX
));
543 /* iterate through all dataranges */
544 AudioRange
= (PKSDATARANGE_AUDIO
)(Item
+ 1);
545 for(dwIndex
= 0; dwIndex
< Item
->Count
; dwIndex
++)
547 if (AudioRange
->DataRange
.FormatSize
!= sizeof(KSDATARANGE_AUDIO
))
550 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
554 if (WaveFormatOut
->nSamplesPerSec
< AudioRange
->MinimumSampleFrequency
)
555 WaveFormatOut
->nSamplesPerSec
= AudioRange
->MinimumSampleFrequency
;
556 else if (WaveFormatOut
->nSamplesPerSec
> AudioRange
->MaximumSampleFrequency
)
557 WaveFormatOut
->nSamplesPerSec
= AudioRange
->MaximumSampleFrequency
;
559 if (WaveFormatOut
->wBitsPerSample
< AudioRange
->MinimumBitsPerSample
)
560 WaveFormatOut
->wBitsPerSample
= AudioRange
->MinimumBitsPerSample
;
561 else if (WaveFormatOut
->wBitsPerSample
> AudioRange
->MaximumBitsPerSample
)
562 WaveFormatOut
->wBitsPerSample
= AudioRange
->MaximumBitsPerSample
;
564 DPRINT("MinimumBitsPerSample %u MaximumBitsPerSample %u MinimumSampleFrequency %u MaximumSampleFrequency %u\n",
565 AudioRange
->MinimumBitsPerSample
, AudioRange
->MaximumBitsPerSample
, AudioRange
->MinimumSampleFrequency
, AudioRange
->MaximumSampleFrequency
);
567 for(nChannels
= 1; nChannels
<= AudioRange
->MaximumChannels
; nChannels
++)
569 WaveFormatOut
->nChannels
= nChannels
;
571 dwResult
= OpenPin(hFilter
, PinId
, WaveFormatOut
, hPin
, TRUE
);
572 if (dwResult
== ERROR_SUCCESS
)
574 DPRINT("InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n",
575 WaveFormatEx
->nChannels
, WaveFormatEx
->wBitsPerSample
, WaveFormatEx
->nSamplesPerSec
,
576 WaveFormatOut
->nChannels
, WaveFormatOut
->wBitsPerSample
, WaveFormatOut
->nSamplesPerSec
);
580 HeapFree(GetProcessHeap(), 0, Item
);
584 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
588 HeapFree(GetProcessHeap(), 0, Item
);