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_
39 #ifndef DSSPEAKER_5POINT1
40 #define DSSPEAKER_5POINT1 6
42 #ifndef DSSPEAKER_7POINT1
43 #define DSSPEAKER_7POINT1 7
46 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
47 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
50 static void *ds_handle
;
51 static HRESULT (WINAPI
*pDirectSoundCreate
)(LPCGUID pcGuidDevice
, IDirectSound
**ppDS
, IUnknown
*pUnkOuter
);
52 static HRESULT (WINAPI
*pDirectSoundEnumerateA
)(LPDSENUMCALLBACKA pDSEnumCallback
, void *pContext
);
53 static HRESULT (WINAPI
*pDirectSoundCaptureCreate
)(LPCGUID pcGuidDevice
, IDirectSoundCapture
**ppDSC
, IUnknown
*pUnkOuter
);
54 static HRESULT (WINAPI
*pDirectSoundCaptureEnumerateA
)(LPDSENUMCALLBACKA pDSEnumCallback
, void *pContext
);
56 #define DirectSoundCreate pDirectSoundCreate
57 #define DirectSoundEnumerateA pDirectSoundEnumerateA
58 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
59 #define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
63 // DirectSound Playback Device
65 IDirectSoundBuffer
*DSpbuffer
;
66 IDirectSoundBuffer
*DSsbuffer
;
67 IDirectSoundNotify
*DSnotify
;
75 // DirectSound Capture Device
76 IDirectSoundCapture
*DSC
;
77 IDirectSoundCaptureBuffer
*DSCbuffer
;
89 static DevMap
*PlaybackDeviceList
;
90 static ALuint NumPlaybackDevices
;
91 static DevMap
*CaptureDeviceList
;
92 static ALuint NumCaptureDevices
;
94 #define MAX_UPDATES 128
96 static ALCboolean
DSoundLoad(void)
100 ds_handle
= LoadLib("dsound.dll");
101 if(ds_handle
== NULL
)
103 ERR("Failed to load dsound.dll\n");
107 #define LOAD_FUNC(f) do { \
108 p##f = GetSymbol(ds_handle, #f); \
110 CloseLib(ds_handle); \
115 LOAD_FUNC(DirectSoundCreate
);
116 LOAD_FUNC(DirectSoundEnumerateA
);
117 LOAD_FUNC(DirectSoundCaptureCreate
);
118 LOAD_FUNC(DirectSoundCaptureEnumerateA
);
125 static BOOL CALLBACK
DSoundEnumPlaybackDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
127 LPOLESTR guidstr
= NULL
;
143 snprintf(str
, sizeof(str
), "%s", desc
);
145 snprintf(str
, sizeof(str
), "%s #%d", desc
, count
+1);
148 for(i
= 0;i
< NumPlaybackDevices
;i
++)
150 if(strcmp(str
, PlaybackDeviceList
[i
].name
) == 0)
153 } while(i
!= NumPlaybackDevices
);
155 hr
= StringFromCLSID(guid
, &guidstr
);
158 TRACE("Got device \"%s\", GUID \"%ls\"\n", str
, guidstr
);
159 CoTaskMemFree(guidstr
);
162 temp
= realloc(PlaybackDeviceList
, sizeof(DevMap
) * (NumPlaybackDevices
+1));
165 PlaybackDeviceList
= temp
;
166 PlaybackDeviceList
[NumPlaybackDevices
].name
= strdup(str
);
167 PlaybackDeviceList
[NumPlaybackDevices
].guid
= *guid
;
168 NumPlaybackDevices
++;
175 static BOOL CALLBACK
DSoundEnumCaptureDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
177 LPOLESTR guidstr
= NULL
;
193 snprintf(str
, sizeof(str
), "%s", desc
);
195 snprintf(str
, sizeof(str
), "%s #%d", desc
, count
+1);
198 for(i
= 0;i
< NumCaptureDevices
;i
++)
200 if(strcmp(str
, CaptureDeviceList
[i
].name
) == 0)
203 } while(i
!= NumCaptureDevices
);
205 hr
= StringFromCLSID(guid
, &guidstr
);
208 TRACE("Got device \"%s\", GUID \"%ls\"\n", str
, guidstr
);
209 CoTaskMemFree(guidstr
);
212 temp
= realloc(CaptureDeviceList
, sizeof(DevMap
) * (NumCaptureDevices
+1));
215 CaptureDeviceList
= temp
;
216 CaptureDeviceList
[NumCaptureDevices
].name
= strdup(str
);
217 CaptureDeviceList
[NumCaptureDevices
].guid
= *guid
;
225 static ALuint
DSoundPlaybackProc(ALvoid
*ptr
)
227 ALCdevice
*Device
= (ALCdevice
*)ptr
;
228 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)Device
->ExtraData
;
230 DWORD LastCursor
= 0;
232 VOID
*WritePtr1
, *WritePtr2
;
233 DWORD WriteCnt1
, WriteCnt2
;
234 BOOL Playing
= FALSE
;
242 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
243 DSBCaps
.dwSize
= sizeof(DSBCaps
);
244 err
= IDirectSoundBuffer_GetCaps(data
->DSsbuffer
, &DSBCaps
);
247 ERR("Failed to get buffer caps: 0x%lx\n", err
);
248 aluHandleDisconnect(Device
);
252 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
253 FragSize
= Device
->UpdateSize
* FrameSize
;
255 IDirectSoundBuffer_GetCurrentPosition(data
->DSsbuffer
, &LastCursor
, NULL
);
256 while(!data
->killNow
)
258 // Get current play cursor
259 IDirectSoundBuffer_GetCurrentPosition(data
->DSsbuffer
, &PlayCursor
, NULL
);
260 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
266 err
= IDirectSoundBuffer_Play(data
->DSsbuffer
, 0, 0, DSBPLAY_LOOPING
);
269 ERR("Failed to play buffer: 0x%lx\n", err
);
270 aluHandleDisconnect(Device
);
276 avail
= WaitForSingleObjectEx(data
->NotifyEvent
, 2000, FALSE
);
277 if(avail
!= WAIT_OBJECT_0
)
278 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
281 avail
-= avail
%FragSize
;
283 // Lock output buffer
286 err
= IDirectSoundBuffer_Lock(data
->DSsbuffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
288 // If the buffer is lost, restore it and lock
289 if(err
== DSERR_BUFFERLOST
)
291 WARN("Buffer lost, restoring...\n");
292 err
= IDirectSoundBuffer_Restore(data
->DSsbuffer
);
297 err
= IDirectSoundBuffer_Lock(data
->DSsbuffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
301 // Successfully locked the output buffer
304 // If we have an active context, mix data directly into output buffer otherwise fill with silence
305 aluMixData(Device
, WritePtr1
, WriteCnt1
/FrameSize
);
306 aluMixData(Device
, WritePtr2
, WriteCnt2
/FrameSize
);
308 // Unlock output buffer only when successfully locked
309 IDirectSoundBuffer_Unlock(data
->DSsbuffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
313 ERR("Buffer lock error: %#lx\n", err
);
314 aluHandleDisconnect(Device
);
318 // Update old write cursor location
319 LastCursor
+= WriteCnt1
+WriteCnt2
;
320 LastCursor
%= DSBCaps
.dwBufferBytes
;
326 static ALCenum
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
328 DSoundPlaybackData
*data
= NULL
;
332 if(!PlaybackDeviceList
)
334 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
336 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
339 if(!deviceName
&& NumPlaybackDevices
> 0)
341 deviceName
= PlaybackDeviceList
[0].name
;
342 guid
= &PlaybackDeviceList
[0].guid
;
348 for(i
= 0;i
< NumPlaybackDevices
;i
++)
350 if(strcmp(deviceName
, PlaybackDeviceList
[i
].name
) == 0)
352 guid
= &PlaybackDeviceList
[i
].guid
;
356 if(i
== NumPlaybackDevices
)
357 return ALC_INVALID_VALUE
;
360 //Initialise requested device
361 data
= calloc(1, sizeof(DSoundPlaybackData
));
363 return ALC_OUT_OF_MEMORY
;
366 data
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
367 if(data
->NotifyEvent
== NULL
)
370 //DirectSound Init code
372 hr
= DirectSoundCreate(guid
, &data
->DS
, NULL
);
374 hr
= IDirectSound_SetCooperativeLevel(data
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
378 IDirectSound_Release(data
->DS
);
379 if(data
->NotifyEvent
)
380 CloseHandle(data
->NotifyEvent
);
382 ERR("Device init failed: 0x%08lx\n", hr
);
383 return ALC_INVALID_VALUE
;
386 device
->DeviceName
= strdup(deviceName
);
387 device
->ExtraData
= data
;
391 static void DSoundClosePlayback(ALCdevice
*device
)
393 DSoundPlaybackData
*data
= device
->ExtraData
;
396 IDirectSoundNotify_Release(data
->DSnotify
);
397 data
->DSnotify
= NULL
;
399 IDirectSoundBuffer_Release(data
->DSsbuffer
);
400 data
->DSsbuffer
= NULL
;
401 if(data
->DSpbuffer
!= NULL
)
402 IDirectSoundBuffer_Release(data
->DSpbuffer
);
403 data
->DSpbuffer
= NULL
;
405 IDirectSound_Release(data
->DS
);
406 CloseHandle(data
->NotifyEvent
);
408 device
->ExtraData
= NULL
;
411 static ALCboolean
DSoundResetPlayback(ALCdevice
*device
)
413 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
414 DSBUFFERDESC DSBDescription
;
415 WAVEFORMATEXTENSIBLE OutputType
;
419 memset(&OutputType
, 0, sizeof(OutputType
));
422 IDirectSoundNotify_Release(data
->DSnotify
);
423 data
->DSnotify
= NULL
;
425 IDirectSoundBuffer_Release(data
->DSsbuffer
);
426 data
->DSsbuffer
= NULL
;
427 if(data
->DSpbuffer
!= NULL
)
428 IDirectSoundBuffer_Release(data
->DSpbuffer
);
429 data
->DSpbuffer
= NULL
;
431 switch(device
->FmtType
)
434 device
->FmtType
= DevFmtUByte
;
437 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
441 device
->FmtType
= DevFmtShort
;
444 device
->FmtType
= DevFmtInt
;
452 hr
= IDirectSound_GetSpeakerConfig(data
->DS
, &speakers
);
455 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
457 speakers
= DSSPEAKER_CONFIG(speakers
);
458 if(speakers
== DSSPEAKER_MONO
)
459 device
->FmtChans
= DevFmtMono
;
460 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
461 device
->FmtChans
= DevFmtStereo
;
462 else if(speakers
== DSSPEAKER_QUAD
)
463 device
->FmtChans
= DevFmtQuad
;
464 else if(speakers
== DSSPEAKER_5POINT1
)
465 device
->FmtChans
= DevFmtX51
;
466 else if(speakers
== DSSPEAKER_7POINT1
)
467 device
->FmtChans
= DevFmtX71
;
469 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
472 switch(device
->FmtChans
)
475 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
478 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
482 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
483 SPEAKER_FRONT_RIGHT
|
488 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
489 SPEAKER_FRONT_RIGHT
|
490 SPEAKER_FRONT_CENTER
|
491 SPEAKER_LOW_FREQUENCY
|
496 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
497 SPEAKER_FRONT_RIGHT
|
498 SPEAKER_FRONT_CENTER
|
499 SPEAKER_LOW_FREQUENCY
|
504 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
505 SPEAKER_FRONT_RIGHT
|
506 SPEAKER_FRONT_CENTER
|
507 SPEAKER_LOW_FREQUENCY
|
508 SPEAKER_BACK_CENTER
|
513 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
514 SPEAKER_FRONT_RIGHT
|
515 SPEAKER_FRONT_CENTER
|
516 SPEAKER_LOW_FREQUENCY
|
526 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
527 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
528 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
529 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
530 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
531 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
532 OutputType
.Format
.cbSize
= 0;
535 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
537 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
538 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
539 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
540 if(device
->FmtType
== DevFmtFloat
)
541 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
543 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
546 IDirectSoundBuffer_Release(data
->DSpbuffer
);
547 data
->DSpbuffer
= NULL
;
553 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
554 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
555 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
556 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->DSpbuffer
, NULL
);
559 hr
= IDirectSoundBuffer_SetFormat(data
->DSpbuffer
,&OutputType
.Format
);
564 if(device
->NumUpdates
> MAX_UPDATES
)
566 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
567 MAX_UPDATES
-1) / MAX_UPDATES
;
568 device
->NumUpdates
= MAX_UPDATES
;
571 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
572 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
573 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
574 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
575 OutputType
.Format
.nBlockAlign
;
576 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
577 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->DSsbuffer
, NULL
);
578 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
580 device
->FmtType
= DevFmtShort
;
587 hr
= IDirectSoundBuffer_QueryInterface(data
->DSsbuffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&data
->DSnotify
);
590 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
593 for(i
= 0;i
< device
->NumUpdates
;++i
)
595 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
596 OutputType
.Format
.nBlockAlign
;
597 notifies
[i
].hEventNotify
= data
->NotifyEvent
;
599 if(IDirectSoundNotify_SetNotificationPositions(data
->DSnotify
, device
->NumUpdates
, notifies
) != DS_OK
)
606 if(data
->DSnotify
!= NULL
)
607 IDirectSoundNotify_Release(data
->DSnotify
);
608 data
->DSnotify
= NULL
;
609 if(data
->DSsbuffer
!= NULL
)
610 IDirectSoundBuffer_Release(data
->DSsbuffer
);
611 data
->DSsbuffer
= NULL
;
612 if(data
->DSpbuffer
!= NULL
)
613 IDirectSoundBuffer_Release(data
->DSpbuffer
);
614 data
->DSpbuffer
= NULL
;
618 ResetEvent(data
->NotifyEvent
);
619 SetDefaultWFXChannelOrder(device
);
624 static ALCboolean
DSoundStartPlayback(ALCdevice
*device
)
626 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
628 data
->thread
= StartThread(DSoundPlaybackProc
, device
);
629 if(data
->thread
== NULL
)
635 static void DSoundStopPlayback(ALCdevice
*device
)
637 DSoundPlaybackData
*data
= device
->ExtraData
;
643 StopThread(data
->thread
);
647 IDirectSoundBuffer_Stop(data
->DSsbuffer
);
651 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
653 DSoundCaptureData
*data
= NULL
;
654 WAVEFORMATEXTENSIBLE InputType
;
655 DSCBUFFERDESC DSCBDescription
;
660 if(!CaptureDeviceList
)
662 /* Initialize COM to prevent name truncation */
663 hrcom
= CoInitialize(NULL
);
664 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
666 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
671 if(!deviceName
&& NumCaptureDevices
> 0)
673 deviceName
= CaptureDeviceList
[0].name
;
674 guid
= &CaptureDeviceList
[0].guid
;
680 for(i
= 0;i
< NumCaptureDevices
;i
++)
682 if(strcmp(deviceName
, CaptureDeviceList
[i
].name
) == 0)
684 guid
= &CaptureDeviceList
[i
].guid
;
688 if(i
== NumCaptureDevices
)
689 return ALC_INVALID_VALUE
;
692 switch(device
->FmtType
)
697 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
698 return ALC_INVALID_ENUM
;
707 //Initialise requested device
708 data
= calloc(1, sizeof(DSoundCaptureData
));
710 return ALC_OUT_OF_MEMORY
;
714 //DirectSoundCapture Init code
716 hr
= DirectSoundCaptureCreate(guid
, &data
->DSC
, NULL
);
719 memset(&InputType
, 0, sizeof(InputType
));
721 switch(device
->FmtChans
)
724 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
727 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
731 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
732 SPEAKER_FRONT_RIGHT
|
737 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
738 SPEAKER_FRONT_RIGHT
|
739 SPEAKER_FRONT_CENTER
|
740 SPEAKER_LOW_FREQUENCY
|
745 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
746 SPEAKER_FRONT_RIGHT
|
747 SPEAKER_FRONT_CENTER
|
748 SPEAKER_LOW_FREQUENCY
|
753 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
754 SPEAKER_FRONT_RIGHT
|
755 SPEAKER_FRONT_CENTER
|
756 SPEAKER_LOW_FREQUENCY
|
757 SPEAKER_BACK_CENTER
|
762 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
763 SPEAKER_FRONT_RIGHT
|
764 SPEAKER_FRONT_CENTER
|
765 SPEAKER_LOW_FREQUENCY
|
773 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
774 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
775 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
776 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
777 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
778 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
779 InputType
.Format
.cbSize
= 0;
781 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
783 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
784 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
785 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
786 if(device
->FmtType
== DevFmtFloat
)
787 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
789 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
792 samples
= device
->UpdateSize
* device
->NumUpdates
;
793 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
795 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
796 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
797 DSCBDescription
.dwFlags
= 0;
798 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
799 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
801 hr
= IDirectSoundCapture_CreateCaptureBuffer(data
->DSC
, &DSCBDescription
, &data
->DSCbuffer
, NULL
);
805 data
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
806 if(data
->Ring
== NULL
)
807 hr
= DSERR_OUTOFMEMORY
;
812 ERR("Device init failed: 0x%08lx\n", hr
);
814 DestroyRingBuffer(data
->Ring
);
816 if(data
->DSCbuffer
!= NULL
)
817 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
818 data
->DSCbuffer
= NULL
;
820 IDirectSoundCapture_Release(data
->DSC
);
824 return ALC_INVALID_VALUE
;
827 data
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
828 SetDefaultWFXChannelOrder(device
);
830 device
->DeviceName
= strdup(deviceName
);
831 device
->ExtraData
= data
;
836 static void DSoundCloseCapture(ALCdevice
*device
)
838 DSoundCaptureData
*data
= device
->ExtraData
;
840 DestroyRingBuffer(data
->Ring
);
843 if(data
->DSCbuffer
!= NULL
)
845 IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
846 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
847 data
->DSCbuffer
= NULL
;
850 IDirectSoundCapture_Release(data
->DSC
);
854 device
->ExtraData
= NULL
;
857 static void DSoundStartCapture(ALCdevice
*device
)
859 DSoundCaptureData
*data
= device
->ExtraData
;
862 hr
= IDirectSoundCaptureBuffer_Start(data
->DSCbuffer
, DSCBSTART_LOOPING
);
865 ERR("start failed: 0x%08lx\n", hr
);
866 aluHandleDisconnect(device
);
870 static void DSoundStopCapture(ALCdevice
*device
)
872 DSoundCaptureData
*data
= device
->ExtraData
;
875 hr
= IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
878 ERR("stop failed: 0x%08lx\n", hr
);
879 aluHandleDisconnect(device
);
883 static ALCenum
DSoundCaptureSamples(ALCdevice
*Device
, ALCvoid
*pBuffer
, ALCuint lSamples
)
885 DSoundCaptureData
*data
= Device
->ExtraData
;
886 ReadRingBuffer(data
->Ring
, pBuffer
, lSamples
);
890 static ALCuint
DSoundAvailableSamples(ALCdevice
*Device
)
892 DSoundCaptureData
*data
= Device
->ExtraData
;
893 DWORD ReadCursor
, LastCursor
, BufferBytes
, NumBytes
;
894 VOID
*ReadPtr1
, *ReadPtr2
;
895 DWORD ReadCnt1
, ReadCnt2
;
899 if(!Device
->Connected
)
902 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
903 BufferBytes
= data
->BufferBytes
;
904 LastCursor
= data
->Cursor
;
906 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(data
->DSCbuffer
, NULL
, &ReadCursor
);
909 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
912 hr
= IDirectSoundCaptureBuffer_Lock(data
->DSCbuffer
, LastCursor
, NumBytes
,
913 &ReadPtr1
, &ReadCnt1
,
914 &ReadPtr2
, &ReadCnt2
, 0);
918 WriteRingBuffer(data
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
920 WriteRingBuffer(data
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
921 hr
= IDirectSoundCaptureBuffer_Unlock(data
->DSCbuffer
,
924 data
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
929 ERR("update failed: 0x%08lx\n", hr
);
930 aluHandleDisconnect(Device
);
934 return RingBufferSize(data
->Ring
);
938 static ALint64
DSoundGetLatency(ALCdevice
*device
)
945 static const BackendFuncs DSoundFuncs
= {
955 DSoundCaptureSamples
,
956 DSoundAvailableSamples
,
957 ALCdevice_LockDefault
,
958 ALCdevice_UnlockDefault
,
963 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
967 *FuncList
= DSoundFuncs
;
971 void alcDSoundDeinit(void)
975 for(i
= 0;i
< NumPlaybackDevices
;++i
)
976 free(PlaybackDeviceList
[i
].name
);
977 free(PlaybackDeviceList
);
978 PlaybackDeviceList
= NULL
;
979 NumPlaybackDevices
= 0;
981 for(i
= 0;i
< NumCaptureDevices
;++i
)
982 free(CaptureDeviceList
[i
].name
);
983 free(CaptureDeviceList
);
984 CaptureDeviceList
= NULL
;
985 NumCaptureDevices
= 0;
992 void alcDSoundProbe(enum DevProbe type
)
999 case ALL_DEVICE_PROBE
:
1000 for(i
= 0;i
< NumPlaybackDevices
;++i
)
1001 free(PlaybackDeviceList
[i
].name
);
1002 free(PlaybackDeviceList
);
1003 PlaybackDeviceList
= NULL
;
1004 NumPlaybackDevices
= 0;
1006 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
1008 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr
);
1011 for(i
= 0;i
< NumPlaybackDevices
;i
++)
1012 AppendAllDevicesList(PlaybackDeviceList
[i
].name
);
1016 case CAPTURE_DEVICE_PROBE
:
1017 for(i
= 0;i
< NumCaptureDevices
;++i
)
1018 free(CaptureDeviceList
[i
].name
);
1019 free(CaptureDeviceList
);
1020 CaptureDeviceList
= NULL
;
1021 NumCaptureDevices
= 0;
1023 /* Initialize COM to prevent name truncation */
1024 hrcom
= CoInitialize(NULL
);
1025 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
1027 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr
);
1030 for(i
= 0;i
< NumCaptureDevices
;i
++)
1031 AppendCaptureDeviceList(CaptureDeviceList
[i
].name
);
1033 if(SUCCEEDED(hrcom
))