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