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
;
405 hr
= IDirectSound_GetSpeakerConfig(pData
->lpDS
, &speakers
);
408 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
410 speakers
= DSSPEAKER_CONFIG(speakers
);
411 if(speakers
== DSSPEAKER_MONO
)
412 device
->FmtChans
= DevFmtMono
;
413 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
414 device
->FmtChans
= DevFmtStereo
;
415 else if(speakers
== DSSPEAKER_QUAD
)
416 device
->FmtChans
= DevFmtQuad
;
417 else if(speakers
== DSSPEAKER_5POINT1
)
418 device
->FmtChans
= DevFmtX51
;
419 else if(speakers
== DSSPEAKER_7POINT1
)
420 device
->FmtChans
= DevFmtX71
;
422 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
425 switch(device
->FmtChans
)
428 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
431 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
435 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
436 SPEAKER_FRONT_RIGHT
|
441 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
442 SPEAKER_FRONT_RIGHT
|
443 SPEAKER_FRONT_CENTER
|
444 SPEAKER_LOW_FREQUENCY
|
449 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
450 SPEAKER_FRONT_RIGHT
|
451 SPEAKER_FRONT_CENTER
|
452 SPEAKER_LOW_FREQUENCY
|
457 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
458 SPEAKER_FRONT_RIGHT
|
459 SPEAKER_FRONT_CENTER
|
460 SPEAKER_LOW_FREQUENCY
|
461 SPEAKER_BACK_CENTER
|
466 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
467 SPEAKER_FRONT_RIGHT
|
468 SPEAKER_FRONT_CENTER
|
469 SPEAKER_LOW_FREQUENCY
|
479 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
480 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
481 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
482 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
483 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
484 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
485 OutputType
.Format
.cbSize
= 0;
488 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
490 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
491 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
492 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
493 if(device
->FmtType
== DevFmtFloat
)
494 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
496 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
499 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
500 pData
->DSpbuffer
= NULL
;
506 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
507 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
508 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
509 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSpbuffer
, NULL
);
512 hr
= IDirectSoundBuffer_SetFormat(pData
->DSpbuffer
,&OutputType
.Format
);
517 if(device
->NumUpdates
> MAX_UPDATES
)
519 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
520 MAX_UPDATES
-1) / MAX_UPDATES
;
521 device
->NumUpdates
= MAX_UPDATES
;
524 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
525 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
526 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
527 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
528 OutputType
.Format
.nBlockAlign
;
529 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
530 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSsbuffer
, NULL
);
531 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
533 device
->FmtType
= DevFmtShort
;
540 hr
= IDirectSoundBuffer_QueryInterface(pData
->DSsbuffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&pData
->DSnotify
);
543 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
546 for(i
= 0;i
< device
->NumUpdates
;++i
)
548 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
549 OutputType
.Format
.nBlockAlign
;
550 notifies
[i
].hEventNotify
= pData
->hNotifyEvent
;
552 if(IDirectSoundNotify_SetNotificationPositions(pData
->DSnotify
, device
->NumUpdates
, notifies
) != DS_OK
)
559 ResetEvent(pData
->hNotifyEvent
);
560 SetDefaultWFXChannelOrder(device
);
561 pData
->thread
= StartThread(DSoundPlaybackProc
, device
);
562 if(pData
->thread
== NULL
)
568 if(pData
->DSnotify
!= NULL
)
569 IDirectSoundNotify_Release(pData
->DSnotify
);
570 pData
->DSnotify
= NULL
;
571 if(pData
->DSsbuffer
!= NULL
)
572 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
573 pData
->DSsbuffer
= NULL
;
574 if(pData
->DSpbuffer
!= NULL
)
575 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
576 pData
->DSpbuffer
= NULL
;
583 static void DSoundStopPlayback(ALCdevice
*device
)
585 DSoundPlaybackData
*pData
= device
->ExtraData
;
591 StopThread(pData
->thread
);
592 pData
->thread
= NULL
;
596 IDirectSoundNotify_Release(pData
->DSnotify
);
597 pData
->DSnotify
= NULL
;
598 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
599 pData
->DSsbuffer
= NULL
;
600 if(pData
->DSpbuffer
!= NULL
)
601 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
602 pData
->DSpbuffer
= NULL
;
606 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
608 DSoundCaptureData
*pData
= NULL
;
609 WAVEFORMATEXTENSIBLE InputType
;
610 DSCBUFFERDESC DSCBDescription
;
615 if(!CaptureDeviceList
)
617 /* Initialize COM to prevent name truncation */
618 hrcom
= CoInitialize(NULL
);
619 hr
= DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices
, NULL
);
621 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr
);
626 if(!deviceName
&& NumCaptureDevices
> 0)
628 deviceName
= CaptureDeviceList
[0].name
;
629 guid
= &CaptureDeviceList
[0].guid
;
635 for(i
= 0;i
< NumCaptureDevices
;i
++)
637 if(strcmp(deviceName
, CaptureDeviceList
[i
].name
) == 0)
639 guid
= &CaptureDeviceList
[i
].guid
;
643 if(i
== NumCaptureDevices
)
644 return ALC_INVALID_VALUE
;
647 //Initialise requested device
648 pData
= calloc(1, sizeof(DSoundCaptureData
));
650 return ALC_OUT_OF_MEMORY
;
654 //DirectSoundCapture Init code
656 hr
= DirectSoundCaptureCreate(guid
, &pData
->lpDSC
, NULL
);
659 memset(&InputType
, 0, sizeof(InputType
));
661 switch(device
->FmtChans
)
664 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
667 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
671 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
672 SPEAKER_FRONT_RIGHT
|
677 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
678 SPEAKER_FRONT_RIGHT
|
679 SPEAKER_FRONT_CENTER
|
680 SPEAKER_LOW_FREQUENCY
|
685 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
686 SPEAKER_FRONT_RIGHT
|
687 SPEAKER_FRONT_CENTER
|
688 SPEAKER_LOW_FREQUENCY
|
693 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
694 SPEAKER_FRONT_RIGHT
|
695 SPEAKER_FRONT_CENTER
|
696 SPEAKER_LOW_FREQUENCY
|
697 SPEAKER_BACK_CENTER
|
702 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
703 SPEAKER_FRONT_RIGHT
|
704 SPEAKER_FRONT_CENTER
|
705 SPEAKER_LOW_FREQUENCY
|
713 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
714 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
715 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
716 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
717 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
718 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
719 InputType
.Format
.cbSize
= 0;
721 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
723 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
724 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
725 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
726 if(device
->FmtType
== DevFmtFloat
)
727 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
729 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
732 samples
= device
->UpdateSize
* device
->NumUpdates
;
733 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
735 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
736 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
737 DSCBDescription
.dwFlags
= 0;
738 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
739 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
741 hr
= IDirectSoundCapture_CreateCaptureBuffer(pData
->lpDSC
, &DSCBDescription
, &pData
->DSCbuffer
, NULL
);
745 pData
->pRing
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
746 if(pData
->pRing
== NULL
)
747 hr
= DSERR_OUTOFMEMORY
;
752 ERR("Device init failed: 0x%08lx\n", hr
);
754 DestroyRingBuffer(pData
->pRing
);
756 if(pData
->DSCbuffer
!= NULL
)
757 IDirectSoundCaptureBuffer_Release(pData
->DSCbuffer
);
758 pData
->DSCbuffer
= NULL
;
760 IDirectSoundCapture_Release(pData
->lpDSC
);
764 return ALC_INVALID_VALUE
;
767 pData
->dwBufferBytes
= DSCBDescription
.dwBufferBytes
;
768 SetDefaultWFXChannelOrder(device
);
770 device
->szDeviceName
= strdup(deviceName
);
771 device
->ExtraData
= pData
;
776 static void DSoundCloseCapture(ALCdevice
*device
)
778 DSoundCaptureData
*pData
= device
->ExtraData
;
780 DestroyRingBuffer(pData
->pRing
);
783 if(pData
->DSCbuffer
!= NULL
)
785 IDirectSoundCaptureBuffer_Stop(pData
->DSCbuffer
);
786 IDirectSoundCaptureBuffer_Release(pData
->DSCbuffer
);
787 pData
->DSCbuffer
= NULL
;
790 IDirectSoundCapture_Release(pData
->lpDSC
);
794 device
->ExtraData
= NULL
;
797 static void DSoundStartCapture(ALCdevice
*device
)
799 DSoundCaptureData
*pData
= device
->ExtraData
;
802 hr
= IDirectSoundCaptureBuffer_Start(pData
->DSCbuffer
, DSCBSTART_LOOPING
);
805 ERR("start failed: 0x%08lx\n", hr
);
806 aluHandleDisconnect(device
);
810 static void DSoundStopCapture(ALCdevice
*device
)
812 DSoundCaptureData
*pData
= device
->ExtraData
;
815 hr
= IDirectSoundCaptureBuffer_Stop(pData
->DSCbuffer
);
818 ERR("stop failed: 0x%08lx\n", hr
);
819 aluHandleDisconnect(device
);
823 static ALCenum
DSoundCaptureSamples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
825 DSoundCaptureData
*pData
= pDevice
->ExtraData
;
826 ReadRingBuffer(pData
->pRing
, pBuffer
, lSamples
);
830 static ALCuint
DSoundAvailableSamples(ALCdevice
*pDevice
)
832 DSoundCaptureData
*pData
= pDevice
->ExtraData
;
833 DWORD dwRead
, dwCursor
, dwBufferBytes
, dwNumBytes
;
834 void *pvAudio1
, *pvAudio2
;
835 DWORD dwAudioBytes1
, dwAudioBytes2
;
839 if(!pDevice
->Connected
)
842 FrameSize
= FrameSizeFromDevFmt(pDevice
->FmtChans
, pDevice
->FmtType
);
843 dwBufferBytes
= pData
->dwBufferBytes
;
844 dwCursor
= pData
->dwCursor
;
846 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(pData
->DSCbuffer
, NULL
, &dwRead
);
849 dwNumBytes
= (dwBufferBytes
+ dwRead
- dwCursor
) % dwBufferBytes
;
852 hr
= IDirectSoundCaptureBuffer_Lock(pData
->DSCbuffer
,
853 dwCursor
, dwNumBytes
,
854 &pvAudio1
, &dwAudioBytes1
,
855 &pvAudio2
, &dwAudioBytes2
, 0);
859 WriteRingBuffer(pData
->pRing
, pvAudio1
, dwAudioBytes1
/FrameSize
);
861 WriteRingBuffer(pData
->pRing
, pvAudio2
, dwAudioBytes2
/FrameSize
);
862 hr
= IDirectSoundCaptureBuffer_Unlock(pData
->DSCbuffer
,
863 pvAudio1
, dwAudioBytes1
,
864 pvAudio2
, dwAudioBytes2
);
865 pData
->dwCursor
= (dwCursor
+ dwAudioBytes1
+ dwAudioBytes2
) % dwBufferBytes
;
870 ERR("update failed: 0x%08lx\n", hr
);
871 aluHandleDisconnect(pDevice
);
875 return RingBufferSize(pData
->pRing
);
878 static const BackendFuncs DSoundFuncs
= {
887 DSoundCaptureSamples
,
888 DSoundAvailableSamples
892 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
896 *FuncList
= DSoundFuncs
;
900 void alcDSoundDeinit(void)
904 for(i
= 0;i
< NumPlaybackDevices
;++i
)
905 free(PlaybackDeviceList
[i
].name
);
906 free(PlaybackDeviceList
);
907 PlaybackDeviceList
= NULL
;
908 NumPlaybackDevices
= 0;
910 for(i
= 0;i
< NumCaptureDevices
;++i
)
911 free(CaptureDeviceList
[i
].name
);
912 free(CaptureDeviceList
);
913 CaptureDeviceList
= NULL
;
914 NumCaptureDevices
= 0;
921 void alcDSoundProbe(enum DevProbe type
)
929 AppendDeviceList(dsDevice
);
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
);