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