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
*lpDSC
;
77 IDirectSoundCaptureBuffer
*DSCbuffer
;
89 static const ALCchar dsDevice
[] = "DirectSound Default";
90 static DevMap
*PlaybackDeviceList
;
91 static ALuint NumPlaybackDevices
;
92 static DevMap
*CaptureDeviceList
;
93 static ALuint NumCaptureDevices
;
95 #define MAX_UPDATES 128
97 static ALCboolean
DSoundLoad(void)
101 ds_handle
= LoadLib("dsound.dll");
102 if(ds_handle
== NULL
)
104 ERR("Failed to load dsound.dll\n");
108 #define LOAD_FUNC(f) do { \
109 p##f = GetSymbol(ds_handle, #f); \
111 CloseLib(ds_handle); \
116 LOAD_FUNC(DirectSoundCreate
);
117 LOAD_FUNC(DirectSoundEnumerateA
);
118 LOAD_FUNC(DirectSoundCaptureCreate
);
119 LOAD_FUNC(DirectSoundCaptureEnumerateA
);
126 static BOOL CALLBACK
DSoundEnumPlaybackDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
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 temp
= realloc(PlaybackDeviceList
, sizeof(DevMap
) * (NumPlaybackDevices
+1));
157 PlaybackDeviceList
= temp
;
158 PlaybackDeviceList
[NumPlaybackDevices
].name
= strdup(str
);
159 PlaybackDeviceList
[NumPlaybackDevices
].guid
= *guid
;
160 NumPlaybackDevices
++;
167 static BOOL CALLBACK
DSoundEnumCaptureDevices(LPGUID guid
, LPCSTR desc
, LPCSTR drvname
, LPVOID data
)
183 snprintf(str
, sizeof(str
), "%s", desc
);
185 snprintf(str
, sizeof(str
), "%s #%d", desc
, count
+1);
188 for(i
= 0;i
< NumCaptureDevices
;i
++)
190 if(strcmp(str
, CaptureDeviceList
[i
].name
) == 0)
193 } while(i
!= NumCaptureDevices
);
195 temp
= realloc(CaptureDeviceList
, sizeof(DevMap
) * (NumCaptureDevices
+1));
198 CaptureDeviceList
= temp
;
199 CaptureDeviceList
[NumCaptureDevices
].name
= strdup(str
);
200 CaptureDeviceList
[NumCaptureDevices
].guid
= *guid
;
208 static ALuint
DSoundPlaybackProc(ALvoid
*ptr
)
210 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
211 DSoundPlaybackData
*pData
= (DSoundPlaybackData
*)pDevice
->ExtraData
;
213 DWORD LastCursor
= 0;
215 VOID
*WritePtr1
, *WritePtr2
;
216 DWORD WriteCnt1
, WriteCnt2
;
217 BOOL Playing
= FALSE
;
225 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
226 DSBCaps
.dwSize
= sizeof(DSBCaps
);
227 err
= IDirectSoundBuffer_GetCaps(pData
->DSsbuffer
, &DSBCaps
);
230 ERR("Failed to get buffer caps: 0x%lx\n", err
);
231 aluHandleDisconnect(pDevice
);
235 FrameSize
= FrameSizeFromDevFmt(pDevice
->FmtChans
, pDevice
->FmtType
);
236 FragSize
= pDevice
->UpdateSize
* FrameSize
;
238 IDirectSoundBuffer_GetCurrentPosition(pData
->DSsbuffer
, &LastCursor
, NULL
);
239 while(!pData
->killNow
)
241 // Get current play cursor
242 IDirectSoundBuffer_GetCurrentPosition(pData
->DSsbuffer
, &PlayCursor
, NULL
);
243 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
249 err
= IDirectSoundBuffer_Play(pData
->DSsbuffer
, 0, 0, DSBPLAY_LOOPING
);
252 ERR("Failed to play buffer: 0x%lx\n", err
);
253 aluHandleDisconnect(pDevice
);
259 avail
= WaitForSingleObjectEx(pData
->hNotifyEvent
, 2000, FALSE
);
260 if(avail
!= WAIT_OBJECT_0
)
261 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
264 avail
-= avail
%FragSize
;
266 // Lock output buffer
269 err
= IDirectSoundBuffer_Lock(pData
->DSsbuffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
271 // If the buffer is lost, restore it and lock
272 if(err
== DSERR_BUFFERLOST
)
274 WARN("Buffer lost, restoring...\n");
275 err
= IDirectSoundBuffer_Restore(pData
->DSsbuffer
);
280 err
= IDirectSoundBuffer_Lock(pData
->DSsbuffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
284 // Successfully locked the output buffer
287 // If we have an active context, mix data directly into output buffer otherwise fill with silence
288 aluMixData(pDevice
, WritePtr1
, WriteCnt1
/FrameSize
);
289 aluMixData(pDevice
, WritePtr2
, WriteCnt2
/FrameSize
);
291 // Unlock output buffer only when successfully locked
292 IDirectSoundBuffer_Unlock(pData
->DSsbuffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
296 ERR("Buffer lock error: %#lx\n", err
);
297 aluHandleDisconnect(pDevice
);
301 // Update old write cursor location
302 LastCursor
+= WriteCnt1
+WriteCnt2
;
303 LastCursor
%= DSBCaps
.dwBufferBytes
;
309 static ALCenum
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
311 DSoundPlaybackData
*pData
= NULL
;
316 deviceName
= dsDevice
;
317 else if(strcmp(deviceName
, dsDevice
) != 0)
321 if(!PlaybackDeviceList
)
323 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
325 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
328 for(i
= 0;i
< NumPlaybackDevices
;i
++)
330 if(strcmp(deviceName
, PlaybackDeviceList
[i
].name
) == 0)
332 guid
= &PlaybackDeviceList
[i
].guid
;
336 if(i
== NumPlaybackDevices
)
337 return ALC_INVALID_VALUE
;
340 //Initialise requested device
341 pData
= calloc(1, sizeof(DSoundPlaybackData
));
343 return ALC_OUT_OF_MEMORY
;
346 pData
->hNotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
347 if(pData
->hNotifyEvent
== NULL
)
350 //DirectSound Init code
352 hr
= DirectSoundCreate(guid
, &pData
->lpDS
, NULL
);
354 hr
= IDirectSound_SetCooperativeLevel(pData
->lpDS
, GetForegroundWindow(), DSSCL_PRIORITY
);
358 IDirectSound_Release(pData
->lpDS
);
359 if(pData
->hNotifyEvent
)
360 CloseHandle(pData
->hNotifyEvent
);
362 ERR("Device init failed: 0x%08lx\n", hr
);
363 return ALC_INVALID_VALUE
;
366 device
->szDeviceName
= strdup(deviceName
);
367 device
->ExtraData
= pData
;
371 static void DSoundClosePlayback(ALCdevice
*device
)
373 DSoundPlaybackData
*pData
= device
->ExtraData
;
375 IDirectSound_Release(pData
->lpDS
);
376 CloseHandle(pData
->hNotifyEvent
);
378 device
->ExtraData
= NULL
;
381 static ALCboolean
DSoundResetPlayback(ALCdevice
*device
)
383 DSoundPlaybackData
*pData
= (DSoundPlaybackData
*)device
->ExtraData
;
384 DSBUFFERDESC DSBDescription
;
385 WAVEFORMATEXTENSIBLE OutputType
;
389 memset(&OutputType
, 0, sizeof(OutputType
));
391 switch(device
->FmtType
)
394 device
->FmtType
= DevFmtUByte
;
397 device
->FmtType
= DevFmtShort
;
400 device
->FmtType
= DevFmtInt
;
409 hr
= IDirectSound_GetSpeakerConfig(pData
->lpDS
, &speakers
);
412 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
414 speakers
= DSSPEAKER_CONFIG(speakers
);
415 if(speakers
== DSSPEAKER_MONO
)
416 device
->FmtChans
= DevFmtMono
;
417 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
418 device
->FmtChans
= DevFmtStereo
;
419 else if(speakers
== DSSPEAKER_QUAD
)
420 device
->FmtChans
= DevFmtQuad
;
421 else if(speakers
== DSSPEAKER_5POINT1
)
422 device
->FmtChans
= DevFmtX51
;
423 else if(speakers
== DSSPEAKER_7POINT1
)
424 device
->FmtChans
= DevFmtX71
;
426 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
429 switch(device
->FmtChans
)
432 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
435 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
439 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
440 SPEAKER_FRONT_RIGHT
|
445 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
446 SPEAKER_FRONT_RIGHT
|
447 SPEAKER_FRONT_CENTER
|
448 SPEAKER_LOW_FREQUENCY
|
453 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
454 SPEAKER_FRONT_RIGHT
|
455 SPEAKER_FRONT_CENTER
|
456 SPEAKER_LOW_FREQUENCY
|
461 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
462 SPEAKER_FRONT_RIGHT
|
463 SPEAKER_FRONT_CENTER
|
464 SPEAKER_LOW_FREQUENCY
|
465 SPEAKER_BACK_CENTER
|
470 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
471 SPEAKER_FRONT_RIGHT
|
472 SPEAKER_FRONT_CENTER
|
473 SPEAKER_LOW_FREQUENCY
|
483 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
484 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
485 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
486 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
487 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
488 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
489 OutputType
.Format
.cbSize
= 0;
492 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
494 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
495 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
496 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
497 if(device
->FmtType
== DevFmtFloat
)
498 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
500 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
503 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
504 pData
->DSpbuffer
= NULL
;
510 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
511 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
512 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
513 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSpbuffer
, NULL
);
516 hr
= IDirectSoundBuffer_SetFormat(pData
->DSpbuffer
,&OutputType
.Format
);
521 if(device
->NumUpdates
> MAX_UPDATES
)
523 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
524 MAX_UPDATES
-1) / MAX_UPDATES
;
525 device
->NumUpdates
= MAX_UPDATES
;
528 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
529 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
530 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
531 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
532 OutputType
.Format
.nBlockAlign
;
533 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
534 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSsbuffer
, NULL
);
535 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
537 device
->FmtType
= DevFmtShort
;
544 hr
= IDirectSoundBuffer_QueryInterface(pData
->DSsbuffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&pData
->DSnotify
);
547 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
550 for(i
= 0;i
< device
->NumUpdates
;++i
)
552 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
553 OutputType
.Format
.nBlockAlign
;
554 notifies
[i
].hEventNotify
= pData
->hNotifyEvent
;
556 if(IDirectSoundNotify_SetNotificationPositions(pData
->DSnotify
, device
->NumUpdates
, notifies
) != DS_OK
)
563 ResetEvent(pData
->hNotifyEvent
);
564 SetDefaultWFXChannelOrder(device
);
565 pData
->thread
= StartThread(DSoundPlaybackProc
, device
);
566 if(pData
->thread
== NULL
)
572 if(pData
->DSnotify
!= NULL
)
573 IDirectSoundNotify_Release(pData
->DSnotify
);
574 pData
->DSnotify
= NULL
;
575 if(pData
->DSsbuffer
!= NULL
)
576 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
577 pData
->DSsbuffer
= NULL
;
578 if(pData
->DSpbuffer
!= NULL
)
579 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
580 pData
->DSpbuffer
= NULL
;
587 static void DSoundStopPlayback(ALCdevice
*device
)
589 DSoundPlaybackData
*pData
= device
->ExtraData
;
595 StopThread(pData
->thread
);
596 pData
->thread
= NULL
;
600 IDirectSoundNotify_Release(pData
->DSnotify
);
601 pData
->DSnotify
= NULL
;
602 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
603 pData
->DSsbuffer
= NULL
;
604 if(pData
->DSpbuffer
!= NULL
)
605 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
606 pData
->DSpbuffer
= NULL
;
610 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
612 DSoundCaptureData
*pData
= NULL
;
613 WAVEFORMATEXTENSIBLE InputType
;
614 DSCBUFFERDESC DSCBDescription
;
619 if(!CaptureDeviceList
)
621 /* Initialize COM to prevent name truncation */
622 hrcom
= CoInitialize(NULL
);
623 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
625 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
630 if(!deviceName
&& NumCaptureDevices
> 0)
632 deviceName
= CaptureDeviceList
[0].name
;
633 guid
= &CaptureDeviceList
[0].guid
;
639 for(i
= 0;i
< NumCaptureDevices
;i
++)
641 if(strcmp(deviceName
, CaptureDeviceList
[i
].name
) == 0)
643 guid
= &CaptureDeviceList
[i
].guid
;
647 if(i
== NumCaptureDevices
)
648 return ALC_INVALID_VALUE
;
651 //Initialise requested device
652 pData
= calloc(1, sizeof(DSoundCaptureData
));
654 return ALC_OUT_OF_MEMORY
;
658 //DirectSoundCapture Init code
660 hr
= DirectSoundCaptureCreate(guid
, &pData
->lpDSC
, NULL
);
663 memset(&InputType
, 0, sizeof(InputType
));
665 switch(device
->FmtChans
)
668 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
671 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
675 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
676 SPEAKER_FRONT_RIGHT
|
681 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
682 SPEAKER_FRONT_RIGHT
|
683 SPEAKER_FRONT_CENTER
|
684 SPEAKER_LOW_FREQUENCY
|
689 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
690 SPEAKER_FRONT_RIGHT
|
691 SPEAKER_FRONT_CENTER
|
692 SPEAKER_LOW_FREQUENCY
|
697 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
698 SPEAKER_FRONT_RIGHT
|
699 SPEAKER_FRONT_CENTER
|
700 SPEAKER_LOW_FREQUENCY
|
701 SPEAKER_BACK_CENTER
|
706 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
707 SPEAKER_FRONT_RIGHT
|
708 SPEAKER_FRONT_CENTER
|
709 SPEAKER_LOW_FREQUENCY
|
717 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
718 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
719 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
720 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
721 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
722 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
723 InputType
.Format
.cbSize
= 0;
725 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
727 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
728 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
729 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
730 if(device
->FmtType
== DevFmtFloat
)
731 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
733 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
736 samples
= device
->UpdateSize
* device
->NumUpdates
;
737 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
739 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
740 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
741 DSCBDescription
.dwFlags
= 0;
742 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
743 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
745 hr
= IDirectSoundCapture_CreateCaptureBuffer(pData
->lpDSC
, &DSCBDescription
, &pData
->DSCbuffer
, NULL
);
749 pData
->pRing
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
750 if(pData
->pRing
== NULL
)
751 hr
= DSERR_OUTOFMEMORY
;
756 ERR("Device init failed: 0x%08lx\n", hr
);
758 DestroyRingBuffer(pData
->pRing
);
760 if(pData
->DSCbuffer
!= NULL
)
761 IDirectSoundCaptureBuffer_Release(pData
->DSCbuffer
);
762 pData
->DSCbuffer
= NULL
;
764 IDirectSoundCapture_Release(pData
->lpDSC
);
768 return ALC_INVALID_VALUE
;
771 pData
->dwBufferBytes
= DSCBDescription
.dwBufferBytes
;
772 SetDefaultWFXChannelOrder(device
);
774 device
->szDeviceName
= strdup(deviceName
);
775 device
->ExtraData
= pData
;
780 static void DSoundCloseCapture(ALCdevice
*device
)
782 DSoundCaptureData
*pData
= device
->ExtraData
;
784 DestroyRingBuffer(pData
->pRing
);
787 if(pData
->DSCbuffer
!= NULL
)
789 IDirectSoundCaptureBuffer_Stop(pData
->DSCbuffer
);
790 IDirectSoundCaptureBuffer_Release(pData
->DSCbuffer
);
791 pData
->DSCbuffer
= NULL
;
794 IDirectSoundCapture_Release(pData
->lpDSC
);
798 device
->ExtraData
= NULL
;
801 static void DSoundStartCapture(ALCdevice
*device
)
803 DSoundCaptureData
*pData
= device
->ExtraData
;
806 hr
= IDirectSoundCaptureBuffer_Start(pData
->DSCbuffer
, DSCBSTART_LOOPING
);
809 ERR("start failed: 0x%08lx\n", hr
);
810 aluHandleDisconnect(device
);
814 static void DSoundStopCapture(ALCdevice
*device
)
816 DSoundCaptureData
*pData
= device
->ExtraData
;
819 hr
= IDirectSoundCaptureBuffer_Stop(pData
->DSCbuffer
);
822 ERR("stop failed: 0x%08lx\n", hr
);
823 aluHandleDisconnect(device
);
827 static ALCenum
DSoundCaptureSamples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
829 DSoundCaptureData
*pData
= pDevice
->ExtraData
;
830 ReadRingBuffer(pData
->pRing
, pBuffer
, lSamples
);
834 static ALCuint
DSoundAvailableSamples(ALCdevice
*pDevice
)
836 DSoundCaptureData
*pData
= pDevice
->ExtraData
;
837 DWORD dwRead
, dwCursor
, dwBufferBytes
, dwNumBytes
;
838 void *pvAudio1
, *pvAudio2
;
839 DWORD dwAudioBytes1
, dwAudioBytes2
;
843 if(!pDevice
->Connected
)
846 FrameSize
= FrameSizeFromDevFmt(pDevice
->FmtChans
, pDevice
->FmtType
);
847 dwBufferBytes
= pData
->dwBufferBytes
;
848 dwCursor
= pData
->dwCursor
;
850 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(pData
->DSCbuffer
, NULL
, &dwRead
);
853 dwNumBytes
= (dwBufferBytes
+ dwRead
- dwCursor
) % dwBufferBytes
;
856 hr
= IDirectSoundCaptureBuffer_Lock(pData
->DSCbuffer
,
857 dwCursor
, dwNumBytes
,
858 &pvAudio1
, &dwAudioBytes1
,
859 &pvAudio2
, &dwAudioBytes2
, 0);
863 WriteRingBuffer(pData
->pRing
, pvAudio1
, dwAudioBytes1
/FrameSize
);
865 WriteRingBuffer(pData
->pRing
, pvAudio2
, dwAudioBytes2
/FrameSize
);
866 hr
= IDirectSoundCaptureBuffer_Unlock(pData
->DSCbuffer
,
867 pvAudio1
, dwAudioBytes1
,
868 pvAudio2
, dwAudioBytes2
);
869 pData
->dwCursor
= (dwCursor
+ dwAudioBytes1
+ dwAudioBytes2
) % dwBufferBytes
;
874 ERR("update failed: 0x%08lx\n", hr
);
875 aluHandleDisconnect(pDevice
);
879 return RingBufferSize(pData
->pRing
);
882 static const BackendFuncs DSoundFuncs
= {
891 DSoundCaptureSamples
,
892 DSoundAvailableSamples
896 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
900 *FuncList
= DSoundFuncs
;
904 void alcDSoundDeinit(void)
908 for(i
= 0;i
< NumPlaybackDevices
;++i
)
909 free(PlaybackDeviceList
[i
].name
);
910 free(PlaybackDeviceList
);
911 PlaybackDeviceList
= NULL
;
912 NumPlaybackDevices
= 0;
914 for(i
= 0;i
< NumCaptureDevices
;++i
)
915 free(CaptureDeviceList
[i
].name
);
916 free(CaptureDeviceList
);
917 CaptureDeviceList
= NULL
;
918 NumCaptureDevices
= 0;
925 void alcDSoundProbe(enum DevProbe type
)
932 case ALL_DEVICE_PROBE
:
933 for(i
= 0;i
< NumPlaybackDevices
;++i
)
934 free(PlaybackDeviceList
[i
].name
);
935 free(PlaybackDeviceList
);
936 PlaybackDeviceList
= NULL
;
937 NumPlaybackDevices
= 0;
939 hr
= DirectSoundEnumerateA(DSoundEnumPlaybackDevices
, NULL
);
941 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr
);
944 for(i
= 0;i
< NumPlaybackDevices
;i
++)
945 AppendAllDeviceList(PlaybackDeviceList
[i
].name
);
949 case CAPTURE_DEVICE_PROBE
:
950 for(i
= 0;i
< NumCaptureDevices
;++i
)
951 free(CaptureDeviceList
[i
].name
);
952 free(CaptureDeviceList
);
953 CaptureDeviceList
= NULL
;
954 NumCaptureDevices
= 0;
956 /* Initialize COM to prevent name truncation */
957 hrcom
= CoInitialize(NULL
);
958 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
960 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr
);
963 for(i
= 0;i
< NumCaptureDevices
;i
++)
964 AppendCaptureDeviceList(CaptureDeviceList
[i
].name
);