2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/mmixer.c
6 * PURPOSE: WDM Audio Mixer API (User-mode part)
7 * PROGRAMMERS: Johannes Anderwald
14 KSSTREAM_HEADER Header
;
16 PSOUND_OVERLAPPED Overlap
;
17 LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
;
18 }IO_PACKET
, *LPIO_PACKET
;
20 PVOID
Alloc(ULONG NumBytes
);
21 MIXER_STATUS
Close(HANDLE hDevice
);
22 VOID
Free(PVOID Block
);
23 VOID
Copy(PVOID Src
, PVOID Dst
, ULONG NumBytes
);
24 MIXER_STATUS
Open(IN LPWSTR DevicePath
, OUT PHANDLE hDevice
);
25 MIXER_STATUS
Control(IN HANDLE hMixer
, IN ULONG dwIoControlCode
, IN PVOID lpInBuffer
, IN ULONG nInBufferSize
, OUT PVOID lpOutBuffer
, ULONG nOutBufferSize
, PULONG lpBytesReturned
);
26 MIXER_STATUS
Enum(IN PVOID EnumContext
, IN ULONG DeviceIndex
, OUT LPWSTR
* DeviceName
, OUT PHANDLE OutHandle
, OUT PHANDLE OutKey
);
27 MIXER_STATUS
OpenKey(IN HANDLE hKey
, IN LPWSTR SubKey
, IN ULONG DesiredAccess
, OUT PHANDLE OutKey
);
28 MIXER_STATUS
CloseKey(IN HANDLE hKey
);
29 MIXER_STATUS
QueryKeyValue(IN HANDLE hKey
, IN LPWSTR KeyName
, OUT PVOID
* ResultBuffer
, OUT PULONG ResultLength
, OUT PULONG KeyType
);
30 PVOID
AllocEventData(IN ULONG ExtraSize
);
31 VOID
FreeEventData(IN PVOID EventData
);
33 MIXER_CONTEXT MixerContext
=
35 sizeof(MIXER_CONTEXT
),
50 GUID CategoryGuid
= {STATIC_KSCATEGORY_AUDIO
};
56 OUT PVOID
* ResultBuffer
,
57 OUT PULONG ResultLength
,
60 if (RegQueryValueExW((HKEY
)hKey
, KeyName
, NULL
, KeyType
, NULL
, ResultLength
) == ERROR_FILE_NOT_FOUND
)
61 return MM_STATUS_UNSUCCESSFUL
;
63 *ResultBuffer
= HeapAlloc(GetProcessHeap(), 0, *ResultLength
);
64 if (*ResultBuffer
== NULL
)
65 return MM_STATUS_NO_MEMORY
;
67 if (RegQueryValueExW((HKEY
)hKey
, KeyName
, NULL
, KeyType
, *ResultBuffer
, ResultLength
) != ERROR_SUCCESS
)
69 HeapFree(GetProcessHeap(), 0, *ResultBuffer
);
70 return MM_STATUS_UNSUCCESSFUL
;
72 return MM_STATUS_SUCCESS
;
79 IN ULONG DesiredAccess
,
82 if (RegOpenKeyExW((HKEY
)hKey
, SubKey
, 0, DesiredAccess
, (PHKEY
)OutKey
) == ERROR_SUCCESS
)
83 return MM_STATUS_SUCCESS
;
85 return MM_STATUS_UNSUCCESSFUL
;
92 RegCloseKey((HKEY
)hKey
);
93 return MM_STATUS_SUCCESS
;
97 PVOID
Alloc(ULONG NumBytes
)
99 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, NumBytes
);
103 Close(HANDLE hDevice
)
105 if (CloseHandle(hDevice
))
106 return MM_STATUS_SUCCESS
;
108 return MM_STATUS_UNSUCCESSFUL
;
114 HeapFree(GetProcessHeap(), 0, Block
);
118 Copy(PVOID Src
, PVOID Dst
, ULONG NumBytes
)
120 CopyMemory(Src
, Dst
, NumBytes
);
125 IN LPWSTR DevicePath
,
128 DevicePath
[1] = L
'\\';
129 *hDevice
= CreateFileW(DevicePath
,
130 GENERIC_READ
| GENERIC_WRITE
,
134 FILE_FLAG_OVERLAPPED
,
136 if (*hDevice
== INVALID_HANDLE_VALUE
)
138 return MM_STATUS_UNSUCCESSFUL
;
141 return MM_STATUS_SUCCESS
;
147 IN ULONG dwIoControlCode
,
149 IN ULONG nInBufferSize
,
150 OUT PVOID lpOutBuffer
,
151 ULONG nOutBufferSize
,
152 PULONG lpBytesReturned
)
154 OVERLAPPED Overlapped
;
156 DWORD Transferred
= 0;
158 /* Overlapped I/O is done here - this is used for waiting for completion */
159 ZeroMemory(&Overlapped
, sizeof(OVERLAPPED
));
160 Overlapped
.hEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
162 if ( ! Overlapped
.hEvent
)
163 return MM_STATUS_NO_MEMORY
;
165 /* Talk to the device */
166 IoResult
= DeviceIoControl(hMixer
,
175 /* If failure occurs, make sure it's not just due to the overlapped I/O */
178 if ( GetLastError() != ERROR_IO_PENDING
)
180 CloseHandle(Overlapped
.hEvent
);
182 if (GetLastError() == ERROR_MORE_DATA
|| GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
184 if ( lpBytesReturned
)
185 *lpBytesReturned
= Transferred
;
186 return MM_STATUS_MORE_ENTRIES
;
189 return MM_STATUS_UNSUCCESSFUL
;
193 /* Wait for the I/O to complete */
194 IoResult
= GetOverlappedResult(hMixer
,
199 /* Don't need this any more */
200 CloseHandle(Overlapped
.hEvent
);
203 return MM_STATUS_UNSUCCESSFUL
;
205 if ( lpBytesReturned
)
206 *lpBytesReturned
= Transferred
;
208 return MM_STATUS_SUCCESS
;
213 IN PVOID EnumContext
,
214 IN ULONG DeviceIndex
,
215 OUT LPWSTR
* DeviceName
,
216 OUT PHANDLE OutHandle
,
219 SP_DEVICE_INTERFACE_DATA InterfaceData
;
220 SP_DEVINFO_DATA DeviceData
;
221 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData
;
226 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
228 InterfaceData
.cbSize
= sizeof(InterfaceData
);
229 InterfaceData
.Reserved
= 0;
231 Result
= SetupDiEnumDeviceInterfaces(EnumContext
,
239 if (GetLastError() == ERROR_NO_MORE_ITEMS
)
241 return MM_STATUS_NO_MORE_DEVICES
;
243 return MM_STATUS_UNSUCCESSFUL
;
246 Length
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
) + MAX_PATH
* sizeof(WCHAR
);
247 DetailData
= (PSP_DEVICE_INTERFACE_DETAIL_DATA_W
)HeapAlloc(GetProcessHeap(),
250 DetailData
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
251 DeviceData
.cbSize
= sizeof(DeviceData
);
252 DeviceData
.Reserved
= 0;
254 Result
= SetupDiGetDeviceInterfaceDetailW(EnumContext
,
263 DPRINT("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError());
264 return MM_STATUS_UNSUCCESSFUL
;
268 *OutKey
= SetupDiOpenDeviceInterfaceRegKey(EnumContext
, &InterfaceData
, 0, KEY_READ
);
269 if ((HKEY
)*OutKey
== INVALID_HANDLE_VALUE
)
271 HeapFree(GetProcessHeap(), 0, DetailData
);
272 return MM_STATUS_UNSUCCESSFUL
;
275 Status
= Open(DetailData
->DevicePath
, OutHandle
);
277 if (Status
!= MM_STATUS_SUCCESS
)
279 RegCloseKey((HKEY
)*OutKey
);
280 HeapFree(GetProcessHeap(), 0, DetailData
);
284 *DeviceName
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData
->DevicePath
)+1) * sizeof(WCHAR
));
285 if (*DeviceName
== NULL
)
287 CloseHandle(*OutHandle
);
288 RegCloseKey((HKEY
)*OutKey
);
289 HeapFree(GetProcessHeap(), 0, DetailData
);
290 return MM_STATUS_NO_MEMORY
;
292 DPRINT1("DeviceName %S\n", DetailData
->DevicePath
);
293 wcscpy(*DeviceName
, DetailData
->DevicePath
);
294 HeapFree(GetProcessHeap(), 0, DetailData
);
303 PKSEVENTDATA Data
= (PKSEVENTDATA
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(KSEVENTDATA
) + ExtraSize
);
307 Data
->EventHandle
.Event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
308 if (!Data
->EventHandle
.Event
)
310 HeapFree(GetProcessHeap(), 0, Data
);
314 Data
->NotificationType
= KSEVENTF_EVENT_HANDLE
;
319 FreeEventData(IN PVOID EventData
)
321 PKSEVENTDATA Data
= (PKSEVENTDATA
)EventData
;
323 CloseHandle(Data
->EventHandle
.Event
);
324 HeapFree(GetProcessHeap(), 0, Data
);
329 WdmAudInitUserModeMixer()
331 HDEVINFO DeviceHandle
;
334 /* create a device list */
335 DeviceHandle
= SetupDiGetClassDevs(&CategoryGuid
,
338 DIGCF_DEVICEINTERFACE
/* FIXME |DIGCF_PRESENT*/);
340 if (DeviceHandle
== INVALID_HANDLE_VALUE
)
342 /* failed to create a device list */
347 /* initialize the mixer library */
348 Status
= MMixerInitialize(&MixerContext
, Enum
, (PVOID
)DeviceHandle
);
350 /* free device list */
351 SetupDiDestroyDeviceInfoList(DeviceHandle
);
353 if (Status
!= MM_STATUS_SUCCESS
)
355 /* failed to initialize mixer library */
356 DPRINT1("Failed to initialize mixer library with %x\n", Status
);
360 /* completed successfully */
365 WdmAudCleanupByMMixer()
368 return MMSYSERR_NOERROR
;
372 WdmAudGetMixerCapabilties(
374 LPMIXERCAPSW Capabilities
)
376 if (MMixerGetCapabilities(&MixerContext
, DeviceId
, Capabilities
) == MM_STATUS_SUCCESS
)
377 return MMSYSERR_NOERROR
;
379 return MMSYSERR_BADDEVICEID
;
385 IN LPMIXERLINEW MixLine
,
388 if (MMixerGetLineInfo(&MixerContext
, hMixer
, Flags
, MixLine
) == MM_STATUS_SUCCESS
)
389 return MMSYSERR_NOERROR
;
391 return MMSYSERR_ERROR
;
395 WdmAudGetLineControls(
397 IN LPMIXERLINECONTROLSW MixControls
,
400 if (MMixerGetLineControls(&MixerContext
, hMixer
, Flags
, MixControls
) == MM_STATUS_SUCCESS
)
401 return MMSYSERR_NOERROR
;
403 return MMSYSERR_ERROR
;
407 WdmAudSetControlDetails(
409 IN LPMIXERCONTROLDETAILS MixDetails
,
412 if (MMixerSetControlDetails(&MixerContext
, hMixer
, Flags
, MixDetails
) == MM_STATUS_SUCCESS
)
413 return MMSYSERR_NOERROR
;
415 return MMSYSERR_ERROR
;
420 WdmAudGetControlDetails(
422 IN LPMIXERCONTROLDETAILS MixDetails
,
425 if (MMixerGetControlDetails(&MixerContext
, hMixer
, Flags
, MixDetails
) == MM_STATUS_SUCCESS
)
426 return MMSYSERR_NOERROR
;
428 return MMSYSERR_ERROR
;
432 WdmAudGetWaveOutCapabilities(
434 LPWAVEOUTCAPSW Capabilities
)
436 if (MMixerWaveOutCapabilities(&MixerContext
, DeviceId
, Capabilities
) == MM_STATUS_SUCCESS
)
437 return MMSYSERR_NOERROR
;
439 return MMSYSERR_ERROR
;
444 WdmAudGetWaveInCapabilities(
446 LPWAVEINCAPSW Capabilities
)
448 if (MMixerWaveInCapabilities(&MixerContext
, DeviceId
, Capabilities
) == MM_STATUS_SUCCESS
)
449 return MMSYSERR_NOERROR
;
451 return MMSYSERR_ERROR
;
455 WdmAudSetWaveDeviceFormatByMMixer(
456 IN PSOUND_DEVICE_INSTANCE Instance
,
458 IN PWAVEFORMATEX WaveFormat
,
459 IN DWORD WaveFormatSize
)
461 MMDEVICE_TYPE DeviceType
;
462 PSOUND_DEVICE SoundDevice
;
466 Result
= GetSoundDeviceFromInstance(Instance
, &SoundDevice
);
468 if ( ! MMSUCCESS(Result
) )
470 return TranslateInternalMmResult(Result
);
473 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
474 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
476 bWaveIn
= (DeviceType
== WAVE_IN_DEVICE_TYPE
? TRUE
: FALSE
);
478 if (MMixerOpenWave(&MixerContext
, DeviceId
, bWaveIn
, WaveFormat
, NULL
, NULL
, &Instance
->Handle
) == MM_STATUS_SUCCESS
)
480 if (DeviceType
== WAVE_OUT_DEVICE_TYPE
)
482 MMixerSetWaveStatus(&MixerContext
, Instance
->Handle
, KSSTATE_ACQUIRE
);
483 MMixerSetWaveStatus(&MixerContext
, Instance
->Handle
, KSSTATE_PAUSE
);
484 MMixerSetWaveStatus(&MixerContext
, Instance
->Handle
, KSSTATE_RUN
);
486 return MMSYSERR_NOERROR
;
488 return MMSYSERR_ERROR
;
493 WdmAudGetCapabilitiesByMMixer(
494 IN PSOUND_DEVICE SoundDevice
,
496 OUT PVOID Capabilities
,
497 IN DWORD CapabilitiesSize
)
499 MMDEVICE_TYPE DeviceType
;
502 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
503 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
505 if (DeviceType
== MIXER_DEVICE_TYPE
)
507 return WdmAudGetMixerCapabilties(DeviceId
, (LPMIXERCAPSW
)Capabilities
);
509 else if (DeviceType
== WAVE_OUT_DEVICE_TYPE
)
511 return WdmAudGetWaveOutCapabilities(DeviceId
, (LPWAVEOUTCAPSW
)Capabilities
);
513 else if (DeviceType
== WAVE_IN_DEVICE_TYPE
)
515 return WdmAudGetWaveInCapabilities(DeviceId
, (LPWAVEINCAPSW
)Capabilities
);
520 return MMSYSERR_ERROR
;
525 WdmAudOpenSoundDeviceByMMixer(
526 IN
struct _SOUND_DEVICE
* SoundDevice
,
529 if (WdmAudInitUserModeMixer())
530 return MMSYSERR_NOERROR
;
532 return MMSYSERR_ERROR
;
536 WdmAudCloseSoundDeviceByMMixer(
537 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
540 MMDEVICE_TYPE DeviceType
;
541 PSOUND_DEVICE SoundDevice
;
544 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
546 if ( ! MMSUCCESS(Result
) )
548 return TranslateInternalMmResult(Result
);
551 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
552 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
554 if (DeviceType
== MIXER_DEVICE_TYPE
)
557 return MMSYSERR_NOERROR
;
559 else if (DeviceType
== WAVE_IN_DEVICE_TYPE
|| DeviceType
== WAVE_OUT_DEVICE_TYPE
)
561 /* make sure the pin is stopped */
562 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_PAUSE
);
563 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_ACQUIRE
);
564 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_STOP
);
567 return MMSYSERR_NOERROR
;
570 /* midi is not supported */
571 return MMSYSERR_ERROR
;
575 WdmAudGetNumWdmDevsByMMixer(
576 IN MMDEVICE_TYPE DeviceType
,
577 OUT DWORD
* DeviceCount
)
581 case MIXER_DEVICE_TYPE
:
582 *DeviceCount
= MMixerGetCount(&MixerContext
);
584 case WAVE_OUT_DEVICE_TYPE
:
585 *DeviceCount
= MMixerGetWaveOutCount(&MixerContext
);
587 case WAVE_IN_DEVICE_TYPE
:
588 *DeviceCount
= MMixerGetWaveInCount(&MixerContext
);
593 return MMSYSERR_NOERROR
;
597 WdmAudQueryMixerInfoByMMixer(
598 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
603 LPMIXERLINEW MixLine
;
604 LPMIXERLINECONTROLSW MixControls
;
605 LPMIXERCONTROLDETAILS MixDetails
;
607 MixLine
= (LPMIXERLINEW
)Parameter
;
608 MixControls
= (LPMIXERLINECONTROLSW
)Parameter
;
609 MixDetails
= (LPMIXERCONTROLDETAILS
)Parameter
;
611 /* FIXME param checks */
615 case MXDM_GETLINEINFO
:
616 return WdmAudGetLineInfo(SoundDeviceInstance
->Handle
, MixLine
, Flags
);
617 case MXDM_GETLINECONTROLS
:
618 return WdmAudGetLineControls(SoundDeviceInstance
->Handle
, MixControls
, Flags
);
619 case MXDM_SETCONTROLDETAILS
:
620 return WdmAudSetControlDetails(SoundDeviceInstance
->Handle
, MixDetails
, Flags
);
622 case MXDM_GETCONTROLDETAILS
:
623 return WdmAudGetControlDetails(SoundDeviceInstance
->Handle
, MixDetails
, Flags
);
627 return MMSYSERR_NOTSUPPORTED
;
632 WdmAudGetDeviceInterfaceStringByMMixer(
633 IN MMDEVICE_TYPE DeviceType
,
636 IN DWORD InterfaceLength
,
637 OUT DWORD
* InterfaceSize
)
640 return MMSYSERR_NOTSUPPORTED
;
644 WdmAudSetMixerDeviceFormatByMMixer(
645 IN PSOUND_DEVICE_INSTANCE Instance
,
647 IN PWAVEFORMATEX WaveFormat
,
648 IN DWORD WaveFormatSize
)
650 Instance
->hNotifyEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
651 if ( ! Instance
->hNotifyEvent
)
652 return MMSYSERR_NOMEM
;
654 if (MMixerOpen(&MixerContext
, DeviceId
, Instance
->hNotifyEvent
, NULL
/* FIXME */, &Instance
->Handle
) == MM_STATUS_SUCCESS
)
655 return MMSYSERR_NOERROR
;
657 return MMSYSERR_BADDEVICEID
;
661 WdmAudSetWaveStateByMMixer(
662 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
665 MMDEVICE_TYPE DeviceType
;
666 PSOUND_DEVICE SoundDevice
;
669 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
670 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
673 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
674 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
676 if (DeviceType
== WAVE_IN_DEVICE_TYPE
|| DeviceType
== WAVE_OUT_DEVICE_TYPE
)
680 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_ACQUIRE
);
681 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_PAUSE
);
682 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_RUN
);
686 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_PAUSE
);
687 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_ACQUIRE
);
688 MMixerSetWaveStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_STOP
);
691 else if (DeviceType
== MIDI_IN_DEVICE_TYPE
|| DeviceType
== MIDI_OUT_DEVICE_TYPE
)
695 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_ACQUIRE
);
696 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_PAUSE
);
697 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_RUN
);
701 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_PAUSE
);
702 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_ACQUIRE
);
703 MMixerSetMidiStatus(&MixerContext
, SoundDeviceInstance
->Handle
, KSSTATE_STOP
);
707 return MMSYSERR_NOERROR
;
711 WdmAudResetStreamByMMixer(
712 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
713 IN MMDEVICE_TYPE DeviceType
,
714 IN BOOLEAN bStartReset
)
717 return MMSYSERR_NOTSUPPORTED
;
721 WdmAudGetWavePositionByMMixer(
722 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
726 return MMSYSERR_NOTSUPPORTED
;
736 LPIO_PACKET Packet
= (LPIO_PACKET
)lpParameter
;
738 Result
= SyncOverlappedDeviceIoControl(Packet
->hDevice
,
739 IOCTL_KS_WRITE_STREAM
, //FIXME IOCTL_KS_READ_STREAM
743 sizeof(KSSTREAM_HEADER
),
747 * don't call completion routine directly
750 Packet
->CompletionRoutine(ERROR_SUCCESS
, Packet
->Header
.DataUsed
, (LPOVERLAPPED
)Packet
->Overlap
);
752 HeapFree(GetProcessHeap(), 0, Packet
);
763 WdmAudCommitWaveBufferByMMixer(
764 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
767 IN PSOUND_OVERLAPPED Overlap
,
768 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
)
770 PSOUND_DEVICE SoundDevice
;
771 MMDEVICE_TYPE DeviceType
;
776 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
778 if ( ! MMSUCCESS(Result
) )
780 return TranslateInternalMmResult(Result
);
783 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
784 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
786 Packet
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IO_PACKET
));
790 return MMSYSERR_NOMEM
;
793 /* setup stream packet */
794 Packet
->Header
.Size
= sizeof(KSSTREAM_HEADER
);
795 Packet
->Header
.PresentationTime
.Numerator
= 1;
796 Packet
->Header
.PresentationTime
.Denominator
= 1;
797 Packet
->Header
.Data
= OffsetPtr
;
798 Packet
->Header
.FrameExtent
= Length
;
799 Packet
->hDevice
= SoundDeviceInstance
->Handle
;
800 Packet
->Overlap
= Overlap
;
801 Packet
->CompletionRoutine
= CompletionRoutine
;
803 if (DeviceType
== WAVE_OUT_DEVICE_TYPE
)
805 Packet
->Header
.DataUsed
= Length
;
808 hThread
= CreateThread(NULL
, 0, IoStreamingThread
, (LPVOID
)Packet
, 0, NULL
);
812 return MMSYSERR_ERROR
;
815 CloseHandle(hThread
);
817 return MMSYSERR_NOERROR
;