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
*DSpbuffer
;
65 IDirectSoundBuffer
*DSsbuffer
;
66 IDirectSoundNotify
*DSnotify
;
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
->DSsbuffer
, &DSBCaps
);
246 ERR("Failed to get buffer caps: 0x%lx\n", err
);
247 aluHandleDisconnect(Device
);
251 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
252 FragSize
= Device
->UpdateSize
* FrameSize
;
254 IDirectSoundBuffer_GetCurrentPosition(data
->DSsbuffer
, &LastCursor
, NULL
);
255 while(!data
->killNow
)
257 // Get current play cursor
258 IDirectSoundBuffer_GetCurrentPosition(data
->DSsbuffer
, &PlayCursor
, NULL
);
259 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
265 err
= IDirectSoundBuffer_Play(data
->DSsbuffer
, 0, 0, DSBPLAY_LOOPING
);
268 ERR("Failed to play buffer: 0x%lx\n", err
);
269 aluHandleDisconnect(Device
);
275 avail
= WaitForSingleObjectEx(data
->NotifyEvent
, 2000, FALSE
);
276 if(avail
!= WAIT_OBJECT_0
)
277 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
280 avail
-= avail
%FragSize
;
282 // Lock output buffer
285 err
= IDirectSoundBuffer_Lock(data
->DSsbuffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
287 // If the buffer is lost, restore it and lock
288 if(err
== DSERR_BUFFERLOST
)
290 WARN("Buffer lost, restoring...\n");
291 err
= IDirectSoundBuffer_Restore(data
->DSsbuffer
);
296 err
= IDirectSoundBuffer_Lock(data
->DSsbuffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
300 // Successfully locked the output buffer
303 // If we have an active context, mix data directly into output buffer otherwise fill with silence
304 aluMixData(Device
, WritePtr1
, WriteCnt1
/FrameSize
);
305 aluMixData(Device
, WritePtr2
, WriteCnt2
/FrameSize
);
307 // Unlock output buffer only when successfully locked
308 IDirectSoundBuffer_Unlock(data
->DSsbuffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
312 ERR("Buffer lock error: %#lx\n", err
);
313 aluHandleDisconnect(Device
);
317 // Update old write cursor location
318 LastCursor
+= WriteCnt1
+WriteCnt2
;
319 LastCursor
%= DSBCaps
.dwBufferBytes
;
325 static ALCenum
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
327 DSoundPlaybackData
*data
= NULL
;
331 if(!PlaybackDeviceList
)
333 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
335 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
338 if(!deviceName
&& NumPlaybackDevices
> 0)
340 deviceName
= PlaybackDeviceList
[0].name
;
341 guid
= &PlaybackDeviceList
[0].guid
;
347 for(i
= 0;i
< NumPlaybackDevices
;i
++)
349 if(strcmp(deviceName
, PlaybackDeviceList
[i
].name
) == 0)
351 guid
= &PlaybackDeviceList
[i
].guid
;
355 if(i
== NumPlaybackDevices
)
356 return ALC_INVALID_VALUE
;
359 //Initialise requested device
360 data
= calloc(1, sizeof(DSoundPlaybackData
));
362 return ALC_OUT_OF_MEMORY
;
365 data
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
366 if(data
->NotifyEvent
== NULL
)
369 //DirectSound Init code
371 hr
= DirectSoundCreate(guid
, &data
->DS
, NULL
);
373 hr
= IDirectSound_SetCooperativeLevel(data
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
377 IDirectSound_Release(data
->DS
);
378 if(data
->NotifyEvent
)
379 CloseHandle(data
->NotifyEvent
);
381 ERR("Device init failed: 0x%08lx\n", hr
);
382 return ALC_INVALID_VALUE
;
385 device
->DeviceName
= strdup(deviceName
);
386 device
->ExtraData
= data
;
390 static void DSoundClosePlayback(ALCdevice
*device
)
392 DSoundPlaybackData
*data
= device
->ExtraData
;
395 IDirectSoundNotify_Release(data
->DSnotify
);
396 data
->DSnotify
= NULL
;
398 IDirectSoundBuffer_Release(data
->DSsbuffer
);
399 data
->DSsbuffer
= NULL
;
400 if(data
->DSpbuffer
!= NULL
)
401 IDirectSoundBuffer_Release(data
->DSpbuffer
);
402 data
->DSpbuffer
= NULL
;
404 IDirectSound_Release(data
->DS
);
405 CloseHandle(data
->NotifyEvent
);
407 device
->ExtraData
= NULL
;
410 static ALCboolean
DSoundResetPlayback(ALCdevice
*device
)
412 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
413 DSBUFFERDESC DSBDescription
;
414 WAVEFORMATEXTENSIBLE OutputType
;
418 memset(&OutputType
, 0, sizeof(OutputType
));
421 IDirectSoundNotify_Release(data
->DSnotify
);
422 data
->DSnotify
= NULL
;
424 IDirectSoundBuffer_Release(data
->DSsbuffer
);
425 data
->DSsbuffer
= NULL
;
426 if(data
->DSpbuffer
!= NULL
)
427 IDirectSoundBuffer_Release(data
->DSpbuffer
);
428 data
->DSpbuffer
= NULL
;
430 switch(device
->FmtType
)
433 device
->FmtType
= DevFmtUByte
;
436 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
440 device
->FmtType
= DevFmtShort
;
443 device
->FmtType
= DevFmtInt
;
451 hr
= IDirectSound_GetSpeakerConfig(data
->DS
, &speakers
);
454 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
456 speakers
= DSSPEAKER_CONFIG(speakers
);
457 if(speakers
== DSSPEAKER_MONO
)
458 device
->FmtChans
= DevFmtMono
;
459 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
460 device
->FmtChans
= DevFmtStereo
;
461 else if(speakers
== DSSPEAKER_QUAD
)
462 device
->FmtChans
= DevFmtQuad
;
463 else if(speakers
== DSSPEAKER_5POINT1
)
464 device
->FmtChans
= DevFmtX51
;
465 else if(speakers
== DSSPEAKER_7POINT1
)
466 device
->FmtChans
= DevFmtX71
;
468 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
471 switch(device
->FmtChans
)
474 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
477 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
481 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
482 SPEAKER_FRONT_RIGHT
|
487 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
488 SPEAKER_FRONT_RIGHT
|
489 SPEAKER_FRONT_CENTER
|
490 SPEAKER_LOW_FREQUENCY
|
495 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
496 SPEAKER_FRONT_RIGHT
|
497 SPEAKER_FRONT_CENTER
|
498 SPEAKER_LOW_FREQUENCY
|
503 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
504 SPEAKER_FRONT_RIGHT
|
505 SPEAKER_FRONT_CENTER
|
506 SPEAKER_LOW_FREQUENCY
|
507 SPEAKER_BACK_CENTER
|
512 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
513 SPEAKER_FRONT_RIGHT
|
514 SPEAKER_FRONT_CENTER
|
515 SPEAKER_LOW_FREQUENCY
|
525 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
526 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
527 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
528 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
529 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
530 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
531 OutputType
.Format
.cbSize
= 0;
534 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
536 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
537 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
538 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
539 if(device
->FmtType
== DevFmtFloat
)
540 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
542 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
545 IDirectSoundBuffer_Release(data
->DSpbuffer
);
546 data
->DSpbuffer
= NULL
;
552 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
553 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
554 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
555 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->DSpbuffer
, NULL
);
558 hr
= IDirectSoundBuffer_SetFormat(data
->DSpbuffer
,&OutputType
.Format
);
563 if(device
->NumUpdates
> MAX_UPDATES
)
565 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
566 MAX_UPDATES
-1) / MAX_UPDATES
;
567 device
->NumUpdates
= MAX_UPDATES
;
570 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
571 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
572 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
573 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
574 OutputType
.Format
.nBlockAlign
;
575 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
576 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->DSsbuffer
, NULL
);
577 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
579 device
->FmtType
= DevFmtShort
;
586 hr
= IDirectSoundBuffer_QueryInterface(data
->DSsbuffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&data
->DSnotify
);
589 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
592 for(i
= 0;i
< device
->NumUpdates
;++i
)
594 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
595 OutputType
.Format
.nBlockAlign
;
596 notifies
[i
].hEventNotify
= data
->NotifyEvent
;
598 if(IDirectSoundNotify_SetNotificationPositions(data
->DSnotify
, device
->NumUpdates
, notifies
) != DS_OK
)
605 if(data
->DSnotify
!= NULL
)
606 IDirectSoundNotify_Release(data
->DSnotify
);
607 data
->DSnotify
= NULL
;
608 if(data
->DSsbuffer
!= NULL
)
609 IDirectSoundBuffer_Release(data
->DSsbuffer
);
610 data
->DSsbuffer
= NULL
;
611 if(data
->DSpbuffer
!= NULL
)
612 IDirectSoundBuffer_Release(data
->DSpbuffer
);
613 data
->DSpbuffer
= NULL
;
617 ResetEvent(data
->NotifyEvent
);
618 SetDefaultWFXChannelOrder(device
);
623 static ALCboolean
DSoundStartPlayback(ALCdevice
*device
)
625 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
627 data
->thread
= StartThread(DSoundPlaybackProc
, device
);
628 if(data
->thread
== NULL
)
634 static void DSoundStopPlayback(ALCdevice
*device
)
636 DSoundPlaybackData
*data
= device
->ExtraData
;
642 StopThread(data
->thread
);
646 IDirectSoundBuffer_Stop(data
->DSsbuffer
);
650 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
652 DSoundCaptureData
*data
= NULL
;
653 WAVEFORMATEXTENSIBLE InputType
;
654 DSCBUFFERDESC DSCBDescription
;
659 if(!CaptureDeviceList
)
661 /* Initialize COM to prevent name truncation */
662 hrcom
= CoInitialize(NULL
);
663 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
665 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
670 if(!deviceName
&& NumCaptureDevices
> 0)
672 deviceName
= CaptureDeviceList
[0].name
;
673 guid
= &CaptureDeviceList
[0].guid
;
679 for(i
= 0;i
< NumCaptureDevices
;i
++)
681 if(strcmp(deviceName
, CaptureDeviceList
[i
].name
) == 0)
683 guid
= &CaptureDeviceList
[i
].guid
;
687 if(i
== NumCaptureDevices
)
688 return ALC_INVALID_VALUE
;
691 switch(device
->FmtType
)
696 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
697 return ALC_INVALID_ENUM
;
706 //Initialise requested device
707 data
= calloc(1, sizeof(DSoundCaptureData
));
709 return ALC_OUT_OF_MEMORY
;
713 //DirectSoundCapture Init code
715 hr
= DirectSoundCaptureCreate(guid
, &data
->DSC
, NULL
);
718 memset(&InputType
, 0, sizeof(InputType
));
720 switch(device
->FmtChans
)
723 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
726 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
730 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
731 SPEAKER_FRONT_RIGHT
|
736 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
737 SPEAKER_FRONT_RIGHT
|
738 SPEAKER_FRONT_CENTER
|
739 SPEAKER_LOW_FREQUENCY
|
744 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
745 SPEAKER_FRONT_RIGHT
|
746 SPEAKER_FRONT_CENTER
|
747 SPEAKER_LOW_FREQUENCY
|
752 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
753 SPEAKER_FRONT_RIGHT
|
754 SPEAKER_FRONT_CENTER
|
755 SPEAKER_LOW_FREQUENCY
|
756 SPEAKER_BACK_CENTER
|
761 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
762 SPEAKER_FRONT_RIGHT
|
763 SPEAKER_FRONT_CENTER
|
764 SPEAKER_LOW_FREQUENCY
|
772 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
773 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
774 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
775 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
776 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
777 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
778 InputType
.Format
.cbSize
= 0;
780 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
782 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
783 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
784 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
785 if(device
->FmtType
== DevFmtFloat
)
786 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
788 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
791 samples
= device
->UpdateSize
* device
->NumUpdates
;
792 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
794 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
795 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
796 DSCBDescription
.dwFlags
= 0;
797 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
798 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
800 hr
= IDirectSoundCapture_CreateCaptureBuffer(data
->DSC
, &DSCBDescription
, &data
->DSCbuffer
, NULL
);
804 data
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
805 if(data
->Ring
== NULL
)
806 hr
= DSERR_OUTOFMEMORY
;
811 ERR("Device init failed: 0x%08lx\n", hr
);
813 DestroyRingBuffer(data
->Ring
);
815 if(data
->DSCbuffer
!= NULL
)
816 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
817 data
->DSCbuffer
= NULL
;
819 IDirectSoundCapture_Release(data
->DSC
);
823 return ALC_INVALID_VALUE
;
826 data
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
827 SetDefaultWFXChannelOrder(device
);
829 device
->DeviceName
= strdup(deviceName
);
830 device
->ExtraData
= data
;
835 static void DSoundCloseCapture(ALCdevice
*device
)
837 DSoundCaptureData
*data
= device
->ExtraData
;
839 DestroyRingBuffer(data
->Ring
);
842 if(data
->DSCbuffer
!= NULL
)
844 IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
845 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
846 data
->DSCbuffer
= NULL
;
849 IDirectSoundCapture_Release(data
->DSC
);
853 device
->ExtraData
= NULL
;
856 static void DSoundStartCapture(ALCdevice
*device
)
858 DSoundCaptureData
*data
= device
->ExtraData
;
861 hr
= IDirectSoundCaptureBuffer_Start(data
->DSCbuffer
, DSCBSTART_LOOPING
);
864 ERR("start failed: 0x%08lx\n", hr
);
865 aluHandleDisconnect(device
);
869 static void DSoundStopCapture(ALCdevice
*device
)
871 DSoundCaptureData
*data
= device
->ExtraData
;
874 hr
= IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
877 ERR("stop failed: 0x%08lx\n", hr
);
878 aluHandleDisconnect(device
);
882 static ALCenum
DSoundCaptureSamples(ALCdevice
*Device
, ALCvoid
*pBuffer
, ALCuint lSamples
)
884 DSoundCaptureData
*data
= Device
->ExtraData
;
885 ReadRingBuffer(data
->Ring
, pBuffer
, lSamples
);
889 static ALCuint
DSoundAvailableSamples(ALCdevice
*Device
)
891 DSoundCaptureData
*data
= Device
->ExtraData
;
892 DWORD ReadCursor
, LastCursor
, BufferBytes
, NumBytes
;
893 VOID
*ReadPtr1
, *ReadPtr2
;
894 DWORD ReadCnt1
, ReadCnt2
;
898 if(!Device
->Connected
)
901 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
902 BufferBytes
= data
->BufferBytes
;
903 LastCursor
= data
->Cursor
;
905 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(data
->DSCbuffer
, NULL
, &ReadCursor
);
908 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
911 hr
= IDirectSoundCaptureBuffer_Lock(data
->DSCbuffer
, LastCursor
, NumBytes
,
912 &ReadPtr1
, &ReadCnt1
,
913 &ReadPtr2
, &ReadCnt2
, 0);
917 WriteRingBuffer(data
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
919 WriteRingBuffer(data
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
920 hr
= IDirectSoundCaptureBuffer_Unlock(data
->DSCbuffer
,
923 data
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
928 ERR("update failed: 0x%08lx\n", hr
);
929 aluHandleDisconnect(Device
);
933 return RingBufferSize(data
->Ring
);
937 static const BackendFuncs DSoundFuncs
= {
947 DSoundCaptureSamples
,
948 DSoundAvailableSamples
,
949 ALCdevice_LockDefault
,
950 ALCdevice_UnlockDefault
,
951 ALCdevice_GetLatencyDefault
955 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
959 *FuncList
= DSoundFuncs
;
963 void alcDSoundDeinit(void)
967 for(i
= 0;i
< NumPlaybackDevices
;++i
)
968 free(PlaybackDeviceList
[i
].name
);
969 free(PlaybackDeviceList
);
970 PlaybackDeviceList
= NULL
;
971 NumPlaybackDevices
= 0;
973 for(i
= 0;i
< NumCaptureDevices
;++i
)
974 free(CaptureDeviceList
[i
].name
);
975 free(CaptureDeviceList
);
976 CaptureDeviceList
= NULL
;
977 NumCaptureDevices
= 0;
984 void alcDSoundProbe(enum DevProbe type
)
991 case ALL_DEVICE_PROBE
:
992 for(i
= 0;i
< NumPlaybackDevices
;++i
)
993 free(PlaybackDeviceList
[i
].name
);
994 free(PlaybackDeviceList
);
995 PlaybackDeviceList
= NULL
;
996 NumPlaybackDevices
= 0;
998 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
1000 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr
);
1003 for(i
= 0;i
< NumPlaybackDevices
;i
++)
1004 AppendAllDevicesList(PlaybackDeviceList
[i
].name
);
1008 case CAPTURE_DEVICE_PROBE
:
1009 for(i
= 0;i
< NumCaptureDevices
;++i
)
1010 free(CaptureDeviceList
[i
].name
);
1011 free(CaptureDeviceList
);
1012 CaptureDeviceList
= NULL
;
1013 NumCaptureDevices
= 0;
1015 /* Initialize COM to prevent name truncation */
1016 hrcom
= CoInitialize(NULL
);
1017 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
1019 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr
);
1022 for(i
= 0;i
< NumCaptureDevices
;i
++)
1023 AppendCaptureDeviceList(CaptureDeviceList
[i
].name
);
1025 if(SUCCEEDED(hrcom
))