2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
30 #ifndef _WAVEFORMATEXTENSIBLE_
38 #ifndef DSSPEAKER_5POINT1
39 #define DSSPEAKER_5POINT1 6
41 #ifndef DSSPEAKER_7POINT1
42 #define DSSPEAKER_7POINT1 7
45 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
49 static void *ds_handle
;
50 static HRESULT (WINAPI
*pDirectSoundCreate
)(LPCGUID pcGuidDevice
, IDirectSound
**ppDS
, IUnknown
*pUnkOuter
);
51 static HRESULT (WINAPI
*pDirectSoundEnumerateA
)(LPDSENUMCALLBACKA pDSEnumCallback
, void *pContext
);
52 static HRESULT (WINAPI
*pDirectSoundCaptureCreate
)(LPCGUID pcGuidDevice
, IDirectSoundCapture
**ppDSC
, IUnknown
*pUnkOuter
);
53 static HRESULT (WINAPI
*pDirectSoundCaptureEnumerateA
)(LPDSENUMCALLBACKA pDSEnumCallback
, void *pContext
);
55 #define DirectSoundCreate pDirectSoundCreate
56 #define DirectSoundEnumerateA pDirectSoundEnumerateA
57 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
58 #define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
62 // DirectSound Playback Device
64 IDirectSoundBuffer
*PrimaryBuffer
;
65 IDirectSoundBuffer
*Buffer
;
66 IDirectSoundNotify
*Notifies
;
74 // DirectSound Capture Device
75 IDirectSoundCapture
*DSC
;
76 IDirectSoundCaptureBuffer
*DSCbuffer
;
88 static DevMap
*PlaybackDeviceList
;
89 static ALuint NumPlaybackDevices
;
90 static DevMap
*CaptureDeviceList
;
91 static ALuint NumCaptureDevices
;
93 #define MAX_UPDATES 128
95 static ALCboolean
DSoundLoad(void)
99 ds_handle
= LoadLib("dsound.dll");
100 if(ds_handle
== NULL
)
102 ERR("Failed to load dsound.dll\n");
106 #define LOAD_FUNC(f) do { \
107 p##f = GetSymbol(ds_handle, #f); \
109 CloseLib(ds_handle); \
114 LOAD_FUNC(DirectSoundCreate
);
115 LOAD_FUNC(DirectSoundEnumerateA
);
116 LOAD_FUNC(DirectSoundCaptureCreate
);
117 LOAD_FUNC(DirectSoundCaptureEnumerateA
);
124 static BOOL CALLBACK
DSoundEnumPlaybackDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
126 LPOLESTR guidstr
= NULL
;
142 snprintf(str
, sizeof(str
), "%s", desc
);
144 snprintf(str
, sizeof(str
), "%s #%d", desc
, count
+1);
147 for(i
= 0;i
< NumPlaybackDevices
;i
++)
149 if(strcmp(str
, PlaybackDeviceList
[i
].name
) == 0)
152 } while(i
!= NumPlaybackDevices
);
154 hr
= StringFromCLSID(guid
, &guidstr
);
157 TRACE("Got device \"%s\", GUID \"%ls\"\n", str
, guidstr
);
158 CoTaskMemFree(guidstr
);
161 temp
= realloc(PlaybackDeviceList
, sizeof(DevMap
) * (NumPlaybackDevices
+1));
164 PlaybackDeviceList
= temp
;
165 PlaybackDeviceList
[NumPlaybackDevices
].name
= strdup(str
);
166 PlaybackDeviceList
[NumPlaybackDevices
].guid
= *guid
;
167 NumPlaybackDevices
++;
174 static BOOL CALLBACK
DSoundEnumCaptureDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
176 LPOLESTR guidstr
= NULL
;
192 snprintf(str
, sizeof(str
), "%s", desc
);
194 snprintf(str
, sizeof(str
), "%s #%d", desc
, count
+1);
197 for(i
= 0;i
< NumCaptureDevices
;i
++)
199 if(strcmp(str
, CaptureDeviceList
[i
].name
) == 0)
202 } while(i
!= NumCaptureDevices
);
204 hr
= StringFromCLSID(guid
, &guidstr
);
207 TRACE("Got device \"%s\", GUID \"%ls\"\n", str
, guidstr
);
208 CoTaskMemFree(guidstr
);
211 temp
= realloc(CaptureDeviceList
, sizeof(DevMap
) * (NumCaptureDevices
+1));
214 CaptureDeviceList
= temp
;
215 CaptureDeviceList
[NumCaptureDevices
].name
= strdup(str
);
216 CaptureDeviceList
[NumCaptureDevices
].guid
= *guid
;
224 static ALuint
DSoundPlaybackProc(ALvoid
*ptr
)
226 ALCdevice
*Device
= (ALCdevice
*)ptr
;
227 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)Device
->ExtraData
;
229 DWORD LastCursor
= 0;
231 VOID
*WritePtr1
, *WritePtr2
;
232 DWORD WriteCnt1
, WriteCnt2
;
233 BOOL Playing
= FALSE
;
241 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
242 DSBCaps
.dwSize
= sizeof(DSBCaps
);
243 err
= IDirectSoundBuffer_GetCaps(data
->Buffer
, &DSBCaps
);
246 ERR("Failed to get buffer caps: 0x%lx\n", err
);
247 ALCdevice_Lock(Device
);
248 aluHandleDisconnect(Device
);
249 ALCdevice_Unlock(Device
);
253 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
254 FragSize
= Device
->UpdateSize
* FrameSize
;
256 IDirectSoundBuffer_GetCurrentPosition(data
->Buffer
, &LastCursor
, NULL
);
257 while(!data
->killNow
)
259 // Get current play cursor
260 IDirectSoundBuffer_GetCurrentPosition(data
->Buffer
, &PlayCursor
, NULL
);
261 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
267 err
= IDirectSoundBuffer_Play(data
->Buffer
, 0, 0, DSBPLAY_LOOPING
);
270 ERR("Failed to play buffer: 0x%lx\n", err
);
271 ALCdevice_Lock(Device
);
272 aluHandleDisconnect(Device
);
273 ALCdevice_Unlock(Device
);
279 avail
= WaitForSingleObjectEx(data
->NotifyEvent
, 2000, FALSE
);
280 if(avail
!= WAIT_OBJECT_0
)
281 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
284 avail
-= avail
%FragSize
;
286 // Lock output buffer
289 err
= IDirectSoundBuffer_Lock(data
->Buffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
291 // If the buffer is lost, restore it and lock
292 if(err
== DSERR_BUFFERLOST
)
294 WARN("Buffer lost, restoring...\n");
295 err
= IDirectSoundBuffer_Restore(data
->Buffer
);
300 err
= IDirectSoundBuffer_Lock(data
->Buffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
304 // Successfully locked the output buffer
307 // If we have an active context, mix data directly into output buffer otherwise fill with silence
308 aluMixData(Device
, WritePtr1
, WriteCnt1
/FrameSize
);
309 aluMixData(Device
, WritePtr2
, WriteCnt2
/FrameSize
);
311 // Unlock output buffer only when successfully locked
312 IDirectSoundBuffer_Unlock(data
->Buffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
316 ERR("Buffer lock error: %#lx\n", err
);
317 ALCdevice_Lock(Device
);
318 aluHandleDisconnect(Device
);
319 ALCdevice_Unlock(Device
);
323 // Update old write cursor location
324 LastCursor
+= WriteCnt1
+WriteCnt2
;
325 LastCursor
%= DSBCaps
.dwBufferBytes
;
331 static ALCenum
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
333 DSoundPlaybackData
*data
= NULL
;
337 if(!PlaybackDeviceList
)
339 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
341 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
344 if(!deviceName
&& NumPlaybackDevices
> 0)
346 deviceName
= PlaybackDeviceList
[0].name
;
347 guid
= &PlaybackDeviceList
[0].guid
;
353 for(i
= 0;i
< NumPlaybackDevices
;i
++)
355 if(strcmp(deviceName
, PlaybackDeviceList
[i
].name
) == 0)
357 guid
= &PlaybackDeviceList
[i
].guid
;
361 if(i
== NumPlaybackDevices
)
362 return ALC_INVALID_VALUE
;
365 //Initialise requested device
366 data
= calloc(1, sizeof(DSoundPlaybackData
));
368 return ALC_OUT_OF_MEMORY
;
371 data
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
372 if(data
->NotifyEvent
== NULL
)
375 //DirectSound Init code
377 hr
= DirectSoundCreate(guid
, &data
->DS
, NULL
);
379 hr
= IDirectSound_SetCooperativeLevel(data
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
383 IDirectSound_Release(data
->DS
);
384 if(data
->NotifyEvent
)
385 CloseHandle(data
->NotifyEvent
);
387 ERR("Device init failed: 0x%08lx\n", hr
);
388 return ALC_INVALID_VALUE
;
391 device
->DeviceName
= strdup(deviceName
);
392 device
->ExtraData
= data
;
396 static void DSoundClosePlayback(ALCdevice
*device
)
398 DSoundPlaybackData
*data
= device
->ExtraData
;
401 IDirectSoundNotify_Release(data
->Notifies
);
402 data
->Notifies
= NULL
;
404 IDirectSoundBuffer_Release(data
->Buffer
);
406 if(data
->PrimaryBuffer
!= NULL
)
407 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
408 data
->PrimaryBuffer
= NULL
;
410 IDirectSound_Release(data
->DS
);
411 CloseHandle(data
->NotifyEvent
);
413 device
->ExtraData
= NULL
;
416 static ALCboolean
DSoundResetPlayback(ALCdevice
*device
)
418 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
419 DSBUFFERDESC DSBDescription
;
420 WAVEFORMATEXTENSIBLE OutputType
;
424 memset(&OutputType
, 0, sizeof(OutputType
));
427 IDirectSoundNotify_Release(data
->Notifies
);
428 data
->Notifies
= NULL
;
430 IDirectSoundBuffer_Release(data
->Buffer
);
432 if(data
->PrimaryBuffer
!= NULL
)
433 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
434 data
->PrimaryBuffer
= NULL
;
436 switch(device
->FmtType
)
439 device
->FmtType
= DevFmtUByte
;
442 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
446 device
->FmtType
= DevFmtShort
;
449 device
->FmtType
= DevFmtInt
;
457 hr
= IDirectSound_GetSpeakerConfig(data
->DS
, &speakers
);
460 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
462 speakers
= DSSPEAKER_CONFIG(speakers
);
463 if(speakers
== DSSPEAKER_MONO
)
464 device
->FmtChans
= DevFmtMono
;
465 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
466 device
->FmtChans
= DevFmtStereo
;
467 else if(speakers
== DSSPEAKER_QUAD
)
468 device
->FmtChans
= DevFmtQuad
;
469 else if(speakers
== DSSPEAKER_5POINT1
)
470 device
->FmtChans
= DevFmtX51
;
471 else if(speakers
== DSSPEAKER_7POINT1
)
472 device
->FmtChans
= DevFmtX71
;
474 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
477 switch(device
->FmtChans
)
480 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
483 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
487 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
488 SPEAKER_FRONT_RIGHT
|
493 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
494 SPEAKER_FRONT_RIGHT
|
495 SPEAKER_FRONT_CENTER
|
496 SPEAKER_LOW_FREQUENCY
|
501 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
502 SPEAKER_FRONT_RIGHT
|
503 SPEAKER_FRONT_CENTER
|
504 SPEAKER_LOW_FREQUENCY
|
509 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
510 SPEAKER_FRONT_RIGHT
|
511 SPEAKER_FRONT_CENTER
|
512 SPEAKER_LOW_FREQUENCY
|
513 SPEAKER_BACK_CENTER
|
518 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
519 SPEAKER_FRONT_RIGHT
|
520 SPEAKER_FRONT_CENTER
|
521 SPEAKER_LOW_FREQUENCY
|
531 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
532 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
533 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
534 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
535 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
536 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
537 OutputType
.Format
.cbSize
= 0;
540 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
542 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
543 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
544 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
545 if(device
->FmtType
== DevFmtFloat
)
546 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
548 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
550 if(data
->PrimaryBuffer
)
551 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
552 data
->PrimaryBuffer
= NULL
;
556 if(SUCCEEDED(hr
) && !data
->PrimaryBuffer
)
558 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
559 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
560 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
561 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->PrimaryBuffer
, NULL
);
564 hr
= IDirectSoundBuffer_SetFormat(data
->PrimaryBuffer
,&OutputType
.Format
);
569 if(device
->NumUpdates
> MAX_UPDATES
)
571 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
572 MAX_UPDATES
-1) / MAX_UPDATES
;
573 device
->NumUpdates
= MAX_UPDATES
;
576 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
577 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
578 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
579 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
580 OutputType
.Format
.nBlockAlign
;
581 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
582 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->Buffer
, NULL
);
583 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
585 device
->FmtType
= DevFmtShort
;
592 hr
= IDirectSoundBuffer_QueryInterface(data
->Buffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&data
->Notifies
);
595 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
598 for(i
= 0;i
< device
->NumUpdates
;++i
)
600 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
601 OutputType
.Format
.nBlockAlign
;
602 notifies
[i
].hEventNotify
= data
->NotifyEvent
;
604 if(IDirectSoundNotify_SetNotificationPositions(data
->Notifies
, device
->NumUpdates
, notifies
) != DS_OK
)
611 if(data
->Notifies
!= NULL
)
612 IDirectSoundNotify_Release(data
->Notifies
);
613 data
->Notifies
= NULL
;
614 if(data
->Buffer
!= NULL
)
615 IDirectSoundBuffer_Release(data
->Buffer
);
617 if(data
->PrimaryBuffer
!= NULL
)
618 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
619 data
->PrimaryBuffer
= NULL
;
623 ResetEvent(data
->NotifyEvent
);
624 SetDefaultWFXChannelOrder(device
);
629 static ALCboolean
DSoundStartPlayback(ALCdevice
*device
)
631 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
633 data
->thread
= StartThread(DSoundPlaybackProc
, device
);
634 if(data
->thread
== NULL
)
640 static void DSoundStopPlayback(ALCdevice
*device
)
642 DSoundPlaybackData
*data
= device
->ExtraData
;
648 StopThread(data
->thread
);
652 IDirectSoundBuffer_Stop(data
->Buffer
);
656 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
658 DSoundCaptureData
*data
= NULL
;
659 WAVEFORMATEXTENSIBLE InputType
;
660 DSCBUFFERDESC DSCBDescription
;
665 if(!CaptureDeviceList
)
667 /* Initialize COM to prevent name truncation */
668 hrcom
= CoInitialize(NULL
);
669 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
671 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
676 if(!deviceName
&& NumCaptureDevices
> 0)
678 deviceName
= CaptureDeviceList
[0].name
;
679 guid
= &CaptureDeviceList
[0].guid
;
685 for(i
= 0;i
< NumCaptureDevices
;i
++)
687 if(strcmp(deviceName
, CaptureDeviceList
[i
].name
) == 0)
689 guid
= &CaptureDeviceList
[i
].guid
;
693 if(i
== NumCaptureDevices
)
694 return ALC_INVALID_VALUE
;
697 switch(device
->FmtType
)
702 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
703 return ALC_INVALID_ENUM
;
712 //Initialise requested device
713 data
= calloc(1, sizeof(DSoundCaptureData
));
715 return ALC_OUT_OF_MEMORY
;
719 //DirectSoundCapture Init code
721 hr
= DirectSoundCaptureCreate(guid
, &data
->DSC
, NULL
);
724 memset(&InputType
, 0, sizeof(InputType
));
726 switch(device
->FmtChans
)
729 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
732 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
736 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
737 SPEAKER_FRONT_RIGHT
|
742 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
743 SPEAKER_FRONT_RIGHT
|
744 SPEAKER_FRONT_CENTER
|
745 SPEAKER_LOW_FREQUENCY
|
750 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
751 SPEAKER_FRONT_RIGHT
|
752 SPEAKER_FRONT_CENTER
|
753 SPEAKER_LOW_FREQUENCY
|
758 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
759 SPEAKER_FRONT_RIGHT
|
760 SPEAKER_FRONT_CENTER
|
761 SPEAKER_LOW_FREQUENCY
|
762 SPEAKER_BACK_CENTER
|
767 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
768 SPEAKER_FRONT_RIGHT
|
769 SPEAKER_FRONT_CENTER
|
770 SPEAKER_LOW_FREQUENCY
|
778 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
779 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
780 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
781 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
782 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
783 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
784 InputType
.Format
.cbSize
= 0;
786 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
788 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
789 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
790 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
791 if(device
->FmtType
== DevFmtFloat
)
792 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
794 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
797 samples
= device
->UpdateSize
* device
->NumUpdates
;
798 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
800 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
801 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
802 DSCBDescription
.dwFlags
= 0;
803 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
804 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
806 hr
= IDirectSoundCapture_CreateCaptureBuffer(data
->DSC
, &DSCBDescription
, &data
->DSCbuffer
, NULL
);
810 data
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
811 if(data
->Ring
== NULL
)
812 hr
= DSERR_OUTOFMEMORY
;
817 ERR("Device init failed: 0x%08lx\n", hr
);
819 DestroyRingBuffer(data
->Ring
);
821 if(data
->DSCbuffer
!= NULL
)
822 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
823 data
->DSCbuffer
= NULL
;
825 IDirectSoundCapture_Release(data
->DSC
);
829 return ALC_INVALID_VALUE
;
832 data
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
833 SetDefaultWFXChannelOrder(device
);
835 device
->DeviceName
= strdup(deviceName
);
836 device
->ExtraData
= data
;
841 static void DSoundCloseCapture(ALCdevice
*device
)
843 DSoundCaptureData
*data
= device
->ExtraData
;
845 DestroyRingBuffer(data
->Ring
);
848 if(data
->DSCbuffer
!= NULL
)
850 IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
851 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
852 data
->DSCbuffer
= NULL
;
855 IDirectSoundCapture_Release(data
->DSC
);
859 device
->ExtraData
= NULL
;
862 static void DSoundStartCapture(ALCdevice
*device
)
864 DSoundCaptureData
*data
= device
->ExtraData
;
867 hr
= IDirectSoundCaptureBuffer_Start(data
->DSCbuffer
, DSCBSTART_LOOPING
);
870 ERR("start failed: 0x%08lx\n", hr
);
871 aluHandleDisconnect(device
);
875 static void DSoundStopCapture(ALCdevice
*device
)
877 DSoundCaptureData
*data
= device
->ExtraData
;
880 hr
= IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
883 ERR("stop failed: 0x%08lx\n", hr
);
884 aluHandleDisconnect(device
);
888 static ALCenum
DSoundCaptureSamples(ALCdevice
*Device
, ALCvoid
*pBuffer
, ALCuint lSamples
)
890 DSoundCaptureData
*data
= Device
->ExtraData
;
891 ReadRingBuffer(data
->Ring
, pBuffer
, lSamples
);
895 static ALCuint
DSoundAvailableSamples(ALCdevice
*Device
)
897 DSoundCaptureData
*data
= Device
->ExtraData
;
898 DWORD ReadCursor
, LastCursor
, BufferBytes
, NumBytes
;
899 VOID
*ReadPtr1
, *ReadPtr2
;
900 DWORD ReadCnt1
, ReadCnt2
;
904 if(!Device
->Connected
)
907 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
908 BufferBytes
= data
->BufferBytes
;
909 LastCursor
= data
->Cursor
;
911 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(data
->DSCbuffer
, NULL
, &ReadCursor
);
914 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
917 hr
= IDirectSoundCaptureBuffer_Lock(data
->DSCbuffer
, LastCursor
, NumBytes
,
918 &ReadPtr1
, &ReadCnt1
,
919 &ReadPtr2
, &ReadCnt2
, 0);
923 WriteRingBuffer(data
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
925 WriteRingBuffer(data
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
926 hr
= IDirectSoundCaptureBuffer_Unlock(data
->DSCbuffer
,
929 data
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
934 ERR("update failed: 0x%08lx\n", hr
);
935 aluHandleDisconnect(Device
);
939 return RingBufferSize(data
->Ring
);
943 static const BackendFuncs DSoundFuncs
= {
953 DSoundCaptureSamples
,
954 DSoundAvailableSamples
,
955 ALCdevice_LockDefault
,
956 ALCdevice_UnlockDefault
,
957 ALCdevice_GetLatencyDefault
961 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
965 *FuncList
= DSoundFuncs
;
969 void alcDSoundDeinit(void)
973 for(i
= 0;i
< NumPlaybackDevices
;++i
)
974 free(PlaybackDeviceList
[i
].name
);
975 free(PlaybackDeviceList
);
976 PlaybackDeviceList
= NULL
;
977 NumPlaybackDevices
= 0;
979 for(i
= 0;i
< NumCaptureDevices
;++i
)
980 free(CaptureDeviceList
[i
].name
);
981 free(CaptureDeviceList
);
982 CaptureDeviceList
= NULL
;
983 NumCaptureDevices
= 0;
990 void alcDSoundProbe(enum DevProbe type
)
997 case ALL_DEVICE_PROBE
:
998 for(i
= 0;i
< NumPlaybackDevices
;++i
)
999 free(PlaybackDeviceList
[i
].name
);
1000 free(PlaybackDeviceList
);
1001 PlaybackDeviceList
= NULL
;
1002 NumPlaybackDevices
= 0;
1004 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
1006 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr
);
1009 for(i
= 0;i
< NumPlaybackDevices
;i
++)
1010 AppendAllDevicesList(PlaybackDeviceList
[i
].name
);
1014 case CAPTURE_DEVICE_PROBE
:
1015 for(i
= 0;i
< NumCaptureDevices
;++i
)
1016 free(CaptureDeviceList
[i
].name
);
1017 free(CaptureDeviceList
);
1018 CaptureDeviceList
= NULL
;
1019 NumCaptureDevices
= 0;
1021 /* Initialize COM to prevent name truncation */
1022 hrcom
= CoInitialize(NULL
);
1023 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
1025 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr
);
1028 for(i
= 0;i
< NumCaptureDevices
;i
++)
1029 AppendCaptureDeviceList(CaptureDeviceList
[i
].name
);
1031 if(SUCCEEDED(hrcom
))