xref: /reactos/dll/directx/dsound_new/misc.c (revision 1734f297)
1 /*
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
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "precomp.h"
11 
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}};
15 
16 
17 VOID
18 PerformChannelConversion(
19     PUCHAR Buffer,
20     ULONG BufferLength,
21     PULONG BytesRead,
22     ULONG OldChannels,
23     ULONG NewChannels,
24     ULONG BitsPerSample,
25     PUCHAR Result,
26     ULONG ResultLength,
27     PULONG BytesWritten)
28 {
29     DWORD NewIndex, OldIndex;
30     DWORD NewLength, Skip;
31 
32     if (NewChannels > OldChannels)
33     {
34         UNIMPLEMENTED;
35         ASSERT(0);
36     }
37 
38     /* setup index */
39     NewIndex = 0;
40     OldIndex = 0;
41 
42     /* calculate offsets */
43     NewLength = NewChannels * (BitsPerSample/8);
44     Skip = OldChannels * (BitsPerSample/8);
45 
46     do
47     {
48         if (NewIndex + NewLength>= ResultLength)
49         {
50             NewIndex = ResultLength;
51             break;
52         }
53 
54         if (OldIndex + Skip >= BufferLength)
55         {
56             OldIndex = BufferLength;
57             break;
58         }
59 
60         /* copy first channel */
61         RtlMoveMemory(&Result[NewIndex], &Buffer[OldIndex], NewLength);
62 
63         /* skip other channels */
64         OldIndex += Skip;
65 
66         /* increment offset */
67         NewIndex += NewLength;
68 
69     }while(TRUE);
70 
71     *BytesRead = OldIndex;
72     *BytesWritten = NewIndex;
73 }
74 
75 
76 BOOL
77 SetPinFormat(
78     IN HANDLE hPin,
79     IN LPWAVEFORMATEX WaveFormatEx)
80 {
81     DWORD dwResult;
82     KSPROPERTY Property;
83     KSDATAFORMAT_WAVEFORMATEX DataFormat;
84 
85     /* setup connection request */
86     Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT;
87     Property.Set = KSPROPSETID_Connection;
88     Property.Flags = KSPROPERTY_TYPE_SET;
89 
90     /* setup data format */
91     DataFormat.WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
92     DataFormat.WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
93     DataFormat.WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
94     DataFormat.WaveFormatEx.cbSize = 0;
95     DataFormat.DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
96     DataFormat.DataFormat.Flags = 0;
97     DataFormat.DataFormat.Reserved = 0;
98     DataFormat.DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
99     DataFormat.DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
100     DataFormat.DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
101     DataFormat.DataFormat.SampleSize = 4;
102     DataFormat.WaveFormatEx.nChannels = WaveFormatEx->nChannels;
103     DataFormat.WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
104     DataFormat.WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
105 
106     dwResult = SyncOverlappedDeviceIoControl(hPin, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSPROPERTY),(LPVOID)&DataFormat, sizeof(KSDATAFORMAT_WAVEFORMATEX), NULL);
107 
108     if (dwResult == ERROR_SUCCESS)
109         return TRUE;
110     else
111         return FALSE;
112 }
113 
114 
115 BOOL
116 DoDataIntersection(
117     HANDLE hFilter,
118     DWORD PinId,
119     DWORD SampleFrequency,
120     LPWAVEFORMATEX WaveFormatEx,
121     DWORD MinimumBitsPerSample,
122     DWORD MaximumBitsPerSample,
123     DWORD MaximumChannels,
124     LPWAVEFORMATEX WaveFormatOut)
125 {
126     DWORD nChannels, nBitsPerSample;
127     KSDATAFORMAT_WAVEFORMATEX WaveFormat;
128     PKSP_PIN Pin;
129     PKSMULTIPLE_ITEM Item;
130     PKSDATAFORMAT_WAVEFORMATEX DataFormat;
131     DWORD dwResult;
132 
133     /* allocate request */
134     Pin = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEX));
135     if (!Pin)
136     {
137         /* no memory */
138         return FALSE;
139     }
140 
141     Item = (PKSMULTIPLE_ITEM)(Pin + 1);
142     DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)(Item + 1);
143 
144     /* setup request */
145     Pin->PinId = PinId;
146     Pin->Property.Flags = KSPROPERTY_TYPE_GET;
147     Pin->Property.Set = KSPROPSETID_Pin;
148     Pin->Property.Id = KSPROPERTY_PIN_DATAINTERSECTION;
149     Item->Count = 1;
150     Item->Size = sizeof(KSDATAFORMAT_WAVEFORMATEX);
151 
152 
153     DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
154     DataFormat->WaveFormatEx.nSamplesPerSec = SampleFrequency;
155     DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
156     DataFormat->WaveFormatEx.cbSize = 0;
157     DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
158     DataFormat->DataFormat.Flags = 0;
159     DataFormat->DataFormat.Reserved = 0;
160     DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
161     DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
162     DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
163     DataFormat->DataFormat.SampleSize = 4;
164 
165     for(nChannels = 1; nChannels <= 2; nChannels++)
166     {
167         for(nBitsPerSample = MinimumBitsPerSample; nBitsPerSample <= MaximumBitsPerSample; nBitsPerSample += 8)
168         {
169             DataFormat->WaveFormatEx.nChannels = nChannels;
170             DataFormat->WaveFormatEx.nAvgBytesPerSec = (nBitsPerSample / 8) * nChannels * SampleFrequency;
171             DataFormat->WaveFormatEx.wBitsPerSample = nBitsPerSample;
172 
173             DPRINT("CurrentFormat: InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\n",
174                    nChannels, nBitsPerSample, SampleFrequency);
175 
176             dwResult = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)Pin, sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEX),
177                                                      (LPVOID)&WaveFormat, sizeof(KSDATAFORMAT_WAVEFORMATEX), NULL);
178 
179             DPRINT("dwResult %x\n", dwResult);
180 
181 
182             if (dwResult == ERROR_SUCCESS)
183             {
184                 /* found a compatible audio range */
185                 WaveFormatOut->cbSize = 0;
186                 WaveFormatOut->nBlockAlign = WaveFormatEx->nBlockAlign;
187                 WaveFormatOut->wFormatTag = WaveFormatEx->wFormatTag;
188                 WaveFormatOut->nAvgBytesPerSec = (nBitsPerSample / 8) * nChannels * SampleFrequency;
189                 WaveFormatOut->wBitsPerSample = nBitsPerSample;
190                 WaveFormatOut->nSamplesPerSec = SampleFrequency;
191                 WaveFormatOut->nChannels = nChannels;
192 
193                 /* free buffer */
194                 HeapFree(GetProcessHeap(), 0, Pin);
195 
196                 DPRINT("InFormat  nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n",
197                        WaveFormatEx->nChannels, WaveFormatEx->wBitsPerSample, WaveFormatEx->nSamplesPerSec,
198                        WaveFormatOut->nChannels, WaveFormatOut->wBitsPerSample, WaveFormatOut->nSamplesPerSec);
199 
200                 return TRUE;
201             }
202         }
203     }
204 
205     /* free buffer */
206     HeapFree(GetProcessHeap(), 0, Pin);
207     ASSERT(0);
208     return FALSE;
209 }
210 
211 DWORD
212 OpenPin(
213     HANDLE hFilter,
214     ULONG PinId,
215     LPWAVEFORMATEX WaveFormatEx,
216     PHANDLE hPin,
217     BOOL bLoop)
218 {
219     DWORD Size, Result;
220     PKSPIN_CONNECT PinConnect;
221     PKSDATAFORMAT_WAVEFORMATEX DataFormat;
222 
223     /* calculate request size */
224     Size = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
225 
226     PinConnect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
227     if (!PinConnect)
228     {
229         /* not enough memory */
230         return DSERR_OUTOFMEMORY;
231     }
232     /* build pin request */
233     PinConnect->Interface.Set = KSINTERFACESETID_Standard;
234 
235     if (bLoop)
236         PinConnect->Interface.Id = KSINTERFACE_STANDARD_LOOPED_STREAMING;
237     else
238         PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
239 
240     PinConnect->Interface.Flags = 0;
241     PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
242     PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
243     PinConnect->Medium.Flags = 0;
244     PinConnect->PinToHandle = NULL;
245     PinConnect->PinId = PinId;
246     PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
247     PinConnect->Priority.PrioritySubClass = 1;
248 
249     DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
250 
251     /* initialize data format */
252     DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
253     DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels;
254     DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
255     DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
256     DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
257     DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
258     DataFormat->WaveFormatEx.cbSize = 0;
259     DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
260     DataFormat->DataFormat.Flags = 0;
261     DataFormat->DataFormat.Reserved = 0;
262     DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
263 
264     DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
265     DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
266     DataFormat->DataFormat.SampleSize = 4;
267 
268     Result = KsCreatePin(hFilter, PinConnect, GENERIC_READ | GENERIC_WRITE, hPin);
269 
270     HeapFree(GetProcessHeap(), 0, PinConnect);
271 
272     return Result;
273 }
274 
275 
276 DWORD
277 OpenFilter(
278     IN LPCWSTR lpFileName,
279     IN PHANDLE OutHandle)
280 {
281     HANDLE Handle;
282 
283     /* open the filter */
284     Handle = CreateFileW(lpFileName, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
285 
286     /* check for success */
287     if (Handle == INVALID_HANDLE_VALUE)
288     {
289         DPRINT("Failed to open Filter %ws\n", lpFileName);
290         return GetLastError();
291     }
292 
293     *OutHandle = Handle;
294     return ERROR_SUCCESS;
295 }
296 
297 DWORD
298 SyncOverlappedDeviceIoControl(
299     IN  HANDLE Handle,
300     IN  DWORD IoControlCode,
301     IN  LPVOID InBuffer,
302     IN  DWORD InBufferSize,
303     OUT LPVOID OutBuffer,
304     IN  DWORD OutBufferSize,
305     OUT LPDWORD BytesTransferred OPTIONAL)
306 {
307     OVERLAPPED Overlapped;
308     BOOLEAN IoResult;
309     DWORD Transferred = 0;
310 
311     /* Overlapped I/O is done here - this is used for waiting for completion */
312     ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
313     Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
314 
315     if (!Overlapped.hEvent)
316         return GetLastError();
317 
318     /* Talk to the device */
319     IoResult = DeviceIoControl(Handle,
320                                IoControlCode,
321                                InBuffer,
322                                InBufferSize,
323                                OutBuffer,
324                                OutBufferSize,
325                                BytesTransferred,
326                                &Overlapped);
327 
328     /* If failure occurs, make sure it's not just due to the overlapped I/O */
329     if (!IoResult)
330     {
331         if ( GetLastError() != ERROR_IO_PENDING )
332         {
333             CloseHandle(Overlapped.hEvent);
334             return GetLastError();
335         }
336     }
337 
338     /* Wait for the I/O to complete */
339     IoResult = GetOverlappedResult(Handle,
340                                    &Overlapped,
341                                    &Transferred,
342                                    TRUE);
343 
344     /* Don't need this any more */
345     CloseHandle(Overlapped.hEvent);
346 
347     if (!IoResult)
348         return GetLastError();
349 
350     if ( BytesTransferred )
351         *BytesTransferred = Transferred;
352 
353     return ERROR_SUCCESS;
354 }
355 
356 DWORD
357 GetFilterPinCount(
358     IN HANDLE hFilter,
359     OUT PULONG NumPins)
360 {
361     KSPROPERTY Pin;
362 
363     *NumPins = 0;
364 
365     /* setup the pin request */
366     Pin.Flags = KSPROPERTY_TYPE_GET;
367     Pin.Set = KSPROPSETID_Pin;
368     Pin.Id = KSPROPERTY_PIN_CTYPES;
369 
370     /* query the device */
371     return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Pin, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), NULL);
372 }
373 
374 DWORD
375 GetFilterNodeProperty(
376     IN HANDLE hFilter,
377     IN ULONG PropertyId,
378     OUT PKSMULTIPLE_ITEM *OutMultipleItem)
379 {
380     DWORD Status, BytesReturned;
381     PKSMULTIPLE_ITEM MultipleItem;
382     KSPROPERTY Property;
383 
384     /* setup query request */
385     Property.Id = PropertyId;
386     Property.Flags = KSPROPERTY_TYPE_GET;
387     Property.Set = KSPROPSETID_Topology;
388 
389     /* query the size */
390     Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
391 
392     if (Status != ERROR_MORE_DATA)
393     {
394         /* failed */
395         DPRINT("Failed to query PropertyId %lu ErrorCode %lx\n", PropertyId, Status);
396         return Status;
397     }
398 
399     MultipleItem = HeapAlloc(GetProcessHeap(), 0, BytesReturned);
400     if (!MultipleItem)
401     {
402         /* not enough memory */
403         DPRINT("Failed to allocate %u Bytes\n", BytesReturned);
404         return ERROR_OUTOFMEMORY;
405     }
406 
407     /* retrieve data ranges */
408     Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)MultipleItem, BytesReturned, &BytesReturned);
409 
410 
411     if (Status != ERROR_SUCCESS)
412     {
413         /* failed to get data ranges */
414         DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status);
415 
416         HeapFree(GetProcessHeap(), 0, MultipleItem);
417         return Status;
418     }
419 
420     /* save result */
421     *OutMultipleItem = MultipleItem;
422     return Status;
423 
424 }
425 
426 DWORD
427 GetFilterPinCommunication(
428     IN HANDLE hFilter,
429     IN ULONG PinId,
430     OUT PKSPIN_COMMUNICATION Communication)
431 {
432     KSP_PIN Property;
433 
434     Property.Property.Flags = KSPROPERTY_TYPE_GET;
435     Property.Property.Set = KSPROPSETID_Pin;
436     Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
437     Property.PinId = PinId;
438     Property.Reserved = 0;
439 
440     return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)Communication, sizeof(KSPIN_COMMUNICATION), NULL);
441 }
442 
443 DWORD
444 GetFilterPinDataFlow(
445     IN HANDLE hFilter,
446     IN ULONG PinId,
447     OUT PKSPIN_DATAFLOW DataFlow)
448 {
449     KSP_PIN Property;
450 
451     Property.Property.Flags = KSPROPERTY_TYPE_GET;
452     Property.Property.Set = KSPROPSETID_Pin;
453     Property.Property.Id = KSPROPERTY_PIN_DATAFLOW;
454     Property.PinId = PinId;
455     Property.Reserved = 0;
456 
457     return SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)DataFlow, sizeof(KSPIN_DATAFLOW), NULL);
458 }
459 
460 DWORD
461 GetFilterPinDataRanges(
462     IN HANDLE hFilter,
463     IN ULONG PinId,
464     IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
465 {
466     KSP_PIN Property;
467     ULONG BytesReturned = 0;
468     DWORD Status;
469     PKSMULTIPLE_ITEM MultipleItem;
470 
471     /* prepare request */
472     Property.Reserved = 0;
473     Property.PinId = PinId;
474     Property.Property.Set = KSPROPSETID_Pin;
475     Property.Property.Id = KSPROPERTY_PIN_DATARANGES;
476     Property.Property.Flags = KSPROPERTY_TYPE_GET;
477 
478     /* retrieve size of data ranges buffer */
479     Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
480 
481 #if 0
482     if (Status != ERROR_MORE_DATA)
483     {
484         DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status);
485         return Status;
486     }
487 #endif
488 
489     ASSERT(BytesReturned);
490     MultipleItem = HeapAlloc(GetProcessHeap(), 0, BytesReturned);
491     if (!MultipleItem)
492     {
493         /* not enough memory */
494         DPRINT("Failed to allocate %u Bytes\n", BytesReturned);
495         return ERROR_OUTOFMEMORY;
496     }
497 
498     /* retrieve data ranges */
499     Status = SyncOverlappedDeviceIoControl(hFilter, IOCTL_KS_PROPERTY, (LPVOID)&Property, sizeof(KSP_PIN), (LPVOID)MultipleItem, BytesReturned, &BytesReturned);
500 
501 
502     if (Status != ERROR_SUCCESS)
503     {
504         /* failed to get data ranges */
505         DPRINT("SyncOverlappedDeviceIoControl failed with %lx\n", Status);
506 
507         HeapFree(GetProcessHeap(), 0, MultipleItem);
508         return Status;
509     }
510 
511     /* save result */
512     *OutMultipleItem = MultipleItem;
513     return Status;
514 }
515 
516 BOOL
517 CreateCompatiblePin(
518     IN HANDLE hFilter,
519     IN DWORD PinId,
520     IN BOOL bLoop,
521     IN LPWAVEFORMATEX WaveFormatEx,
522     OUT LPWAVEFORMATEX WaveFormatOut,
523     OUT PHANDLE hPin)
524 {
525     PKSMULTIPLE_ITEM Item = NULL;
526     PKSDATARANGE_AUDIO AudioRange;
527     DWORD dwResult;
528     DWORD dwIndex, nChannels;
529 
530     dwResult = GetFilterPinDataRanges(hFilter, PinId, &Item);
531 
532     if (dwResult != ERROR_SUCCESS)
533     {
534         /* failed to get data ranges */
535          return FALSE;
536     }
537 
538     CopyMemory(WaveFormatOut, WaveFormatEx, sizeof(WAVEFORMATEX));
539 
540     /* iterate through all dataranges */
541     AudioRange = (PKSDATARANGE_AUDIO)(Item + 1);
542     for(dwIndex = 0; dwIndex < Item->Count; dwIndex++)
543     {
544         if (AudioRange->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
545         {
546             UNIMPLEMENTED;
547             AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
548             continue;
549         }
550 
551         if (WaveFormatOut->nSamplesPerSec < AudioRange->MinimumSampleFrequency)
552             WaveFormatOut->nSamplesPerSec = AudioRange->MinimumSampleFrequency;
553         else if (WaveFormatOut->nSamplesPerSec > AudioRange->MaximumSampleFrequency)
554             WaveFormatOut->nSamplesPerSec = AudioRange->MaximumSampleFrequency;
555 
556         if (WaveFormatOut->wBitsPerSample < AudioRange->MinimumBitsPerSample)
557             WaveFormatOut->wBitsPerSample = AudioRange->MinimumBitsPerSample;
558         else if (WaveFormatOut->wBitsPerSample > AudioRange->MaximumBitsPerSample)
559             WaveFormatOut->wBitsPerSample = AudioRange->MaximumBitsPerSample;
560 
561         DPRINT("MinimumBitsPerSample %u MaximumBitsPerSample %u MinimumSampleFrequency %u MaximumSampleFrequency %u\n",
562             AudioRange->MinimumBitsPerSample, AudioRange->MaximumBitsPerSample, AudioRange->MinimumSampleFrequency, AudioRange->MaximumSampleFrequency);
563 
564         for(nChannels = 1; nChannels <= AudioRange->MaximumChannels; nChannels++)
565         {
566             WaveFormatOut->nChannels = nChannels;
567 
568             dwResult = OpenPin(hFilter, PinId, WaveFormatOut, hPin, TRUE);
569             if (dwResult == ERROR_SUCCESS)
570             {
571                 DPRINT("InFormat  nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n",
572                        WaveFormatEx->nChannels, WaveFormatEx->wBitsPerSample, WaveFormatEx->nSamplesPerSec,
573                        WaveFormatOut->nChannels, WaveFormatOut->wBitsPerSample, WaveFormatOut->nSamplesPerSec);
574 
575 
576                 /* free buffer */
577                 HeapFree(GetProcessHeap(), 0, Item);
578                 return TRUE;
579             }
580         }
581         AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
582     }
583 
584     /* free buffer */
585     HeapFree(GetProcessHeap(), 0, Item);
586     return FALSE;
587 }
588 
589