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