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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
30 #ifndef _WAVEFORMATEXTENSIBLE_
41 #include "backends/base.h"
43 #ifndef DSSPEAKER_5POINT1
44 # define DSSPEAKER_5POINT1 0x00000006
46 #ifndef DSSPEAKER_5POINT1_BACK
47 # define DSSPEAKER_5POINT1_BACK 0x00000006
49 #ifndef DSSPEAKER_7POINT1
50 # define DSSPEAKER_7POINT1 0x00000007
52 #ifndef DSSPEAKER_7POINT1_SURROUND
53 # define DSSPEAKER_7POINT1_SURROUND 0x00000008
55 #ifndef DSSPEAKER_5POINT1_SURROUND
56 # define DSSPEAKER_5POINT1_SURROUND 0x00000009
60 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 static void *ds_handle
;
66 static HRESULT (WINAPI
*pDirectSoundCreate
)(const GUID
*pcGuidDevice
, IDirectSound
**ppDS
, IUnknown
*pUnkOuter
);
67 static HRESULT (WINAPI
*pDirectSoundEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
68 static HRESULT (WINAPI
*pDirectSoundCaptureCreate
)(const GUID
*pcGuidDevice
, IDirectSoundCapture
**ppDSC
, IUnknown
*pUnkOuter
);
69 static HRESULT (WINAPI
*pDirectSoundCaptureEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
71 #define DirectSoundCreate pDirectSoundCreate
72 #define DirectSoundEnumerateW pDirectSoundEnumerateW
73 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
74 #define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW
78 static ALCboolean
DSoundLoad(void)
83 ds_handle
= LoadLib("dsound.dll");
86 ERR("Failed to load dsound.dll\n");
90 #define LOAD_FUNC(f) do { \
91 p##f = GetSymbol(ds_handle, #f); \
93 CloseLib(ds_handle); \
98 LOAD_FUNC(DirectSoundCreate
);
99 LOAD_FUNC(DirectSoundEnumerateW
);
100 LOAD_FUNC(DirectSoundCaptureCreate
);
101 LOAD_FUNC(DirectSoundCaptureEnumerateW
);
109 #define MAX_UPDATES 128
115 TYPEDEF_VECTOR(DevMap
, vector_DevMap
)
117 static vector_DevMap PlaybackDevices
;
118 static vector_DevMap CaptureDevices
;
120 static void clear_devlist(vector_DevMap
*list
)
122 #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
123 VECTOR_FOR_EACH(DevMap
, *list
, DEINIT_STR
);
125 VECTOR_RESIZE(*list
, 0);
128 static BOOL CALLBACK
DSoundEnumDevices(GUID
*guid
, const WCHAR
*desc
, const WCHAR
* UNUSED(drvname
), void *data
)
130 vector_DevMap
*devices
= data
;
131 OLECHAR
*guidstr
= NULL
;
140 AL_STRING_INIT(entry
.name
);
144 al_string_copy_wcstr(&entry
.name
, desc
);
148 snprintf(str
, sizeof(str
), " #%d", count
+1);
149 al_string_append_cstr(&entry
.name
, str
);
153 iter
= VECTOR_ITER_BEGIN(*devices
);
154 end
= VECTOR_ITER_END(*devices
);
155 for(;iter
!= end
;++iter
)
157 if(al_string_cmp(entry
.name
, iter
->name
) == 0)
160 } while(iter
!= end
);
163 hr
= StringFromCLSID(guid
, &guidstr
);
166 TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry
.name
), guidstr
);
167 CoTaskMemFree(guidstr
);
170 VECTOR_PUSH_BACK(*devices
, entry
);
176 typedef struct ALCdsoundPlayback
{
177 DERIVE_FROM_TYPE(ALCbackend
);
180 IDirectSoundBuffer
*PrimaryBuffer
;
181 IDirectSoundBuffer
*Buffer
;
182 IDirectSoundNotify
*Notifies
;
185 volatile int killNow
;
189 static int ALCdsoundPlayback_mixerProc(void *ptr
);
191 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback
*self
, ALCdevice
*device
);
192 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, Destruct
)
193 static ALCenum
ALCdsoundPlayback_open(ALCdsoundPlayback
*self
, const ALCchar
*name
);
194 static void ALCdsoundPlayback_close(ALCdsoundPlayback
*self
);
195 static ALCboolean
ALCdsoundPlayback_reset(ALCdsoundPlayback
*self
);
196 static ALCboolean
ALCdsoundPlayback_start(ALCdsoundPlayback
*self
);
197 static void ALCdsoundPlayback_stop(ALCdsoundPlayback
*self
);
198 static DECLARE_FORWARD2(ALCdsoundPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
199 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, ALCuint
, availableSamples
)
200 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, ALint64
, getLatency
)
201 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, lock
)
202 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, unlock
)
203 DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback
)
205 DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback
);
208 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback
*self
, ALCdevice
*device
)
210 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
211 SET_VTABLE2(ALCdsoundPlayback
, ALCbackend
, self
);
215 FORCE_ALIGN
static int ALCdsoundPlayback_mixerProc(void *ptr
)
217 ALCdsoundPlayback
*self
= ptr
;
218 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
220 DWORD LastCursor
= 0;
222 void *WritePtr1
, *WritePtr2
;
223 DWORD WriteCnt1
, WriteCnt2
;
224 BOOL Playing
= FALSE
;
231 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
233 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
234 DSBCaps
.dwSize
= sizeof(DSBCaps
);
235 err
= IDirectSoundBuffer_GetCaps(self
->Buffer
, &DSBCaps
);
238 ERR("Failed to get buffer caps: 0x%lx\n", err
);
239 ALCdevice_Lock(device
);
240 aluHandleDisconnect(device
);
241 ALCdevice_Unlock(device
);
245 FrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
246 FragSize
= device
->UpdateSize
* FrameSize
;
248 IDirectSoundBuffer_GetCurrentPosition(self
->Buffer
, &LastCursor
, NULL
);
249 while(!self
->killNow
)
251 // Get current play cursor
252 IDirectSoundBuffer_GetCurrentPosition(self
->Buffer
, &PlayCursor
, NULL
);
253 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
259 err
= IDirectSoundBuffer_Play(self
->Buffer
, 0, 0, DSBPLAY_LOOPING
);
262 ERR("Failed to play buffer: 0x%lx\n", err
);
263 ALCdevice_Lock(device
);
264 aluHandleDisconnect(device
);
265 ALCdevice_Unlock(device
);
271 avail
= WaitForSingleObjectEx(self
->NotifyEvent
, 2000, FALSE
);
272 if(avail
!= WAIT_OBJECT_0
)
273 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
276 avail
-= avail
%FragSize
;
278 // Lock output buffer
281 err
= IDirectSoundBuffer_Lock(self
->Buffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
283 // If the buffer is lost, restore it and lock
284 if(err
== DSERR_BUFFERLOST
)
286 WARN("Buffer lost, restoring...\n");
287 err
= IDirectSoundBuffer_Restore(self
->Buffer
);
292 err
= IDirectSoundBuffer_Lock(self
->Buffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
296 // Successfully locked the output buffer
299 // If we have an active context, mix data directly into output buffer otherwise fill with silence
300 aluMixData(device
, WritePtr1
, WriteCnt1
/FrameSize
);
301 aluMixData(device
, WritePtr2
, WriteCnt2
/FrameSize
);
303 // Unlock output buffer only when successfully locked
304 IDirectSoundBuffer_Unlock(self
->Buffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
308 ERR("Buffer lock error: %#lx\n", err
);
309 ALCdevice_Lock(device
);
310 aluHandleDisconnect(device
);
311 ALCdevice_Unlock(device
);
315 // Update old write cursor location
316 LastCursor
+= WriteCnt1
+WriteCnt2
;
317 LastCursor
%= DSBCaps
.dwBufferBytes
;
323 static ALCenum
ALCdsoundPlayback_open(ALCdsoundPlayback
*self
, const ALCchar
*deviceName
)
325 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
326 const GUID
*guid
= NULL
;
329 if(VECTOR_SIZE(PlaybackDevices
) == 0)
331 /* Initialize COM to prevent name truncation */
332 hrcom
= CoInitialize(NULL
);
333 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
335 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
340 if(!deviceName
&& VECTOR_SIZE(PlaybackDevices
) > 0)
342 deviceName
= al_string_get_cstr(VECTOR_FRONT(PlaybackDevices
).name
);
343 guid
= &VECTOR_FRONT(PlaybackDevices
).guid
;
349 #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
350 VECTOR_FIND_IF(iter
, const DevMap
, PlaybackDevices
, MATCH_NAME
);
352 if(iter
== VECTOR_ITER_END(PlaybackDevices
))
353 return ALC_INVALID_VALUE
;
358 self
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
359 if(self
->NotifyEvent
== NULL
)
362 //DirectSound Init code
364 hr
= DirectSoundCreate(guid
, &self
->DS
, NULL
);
366 hr
= IDirectSound_SetCooperativeLevel(self
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
370 IDirectSound_Release(self
->DS
);
372 if(self
->NotifyEvent
)
373 CloseHandle(self
->NotifyEvent
);
374 self
->NotifyEvent
= NULL
;
376 ERR("Device init failed: 0x%08lx\n", hr
);
377 return ALC_INVALID_VALUE
;
380 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
385 static void ALCdsoundPlayback_close(ALCdsoundPlayback
*self
)
388 IDirectSoundNotify_Release(self
->Notifies
);
389 self
->Notifies
= NULL
;
391 IDirectSoundBuffer_Release(self
->Buffer
);
393 if(self
->PrimaryBuffer
!= NULL
)
394 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
395 self
->PrimaryBuffer
= NULL
;
397 IDirectSound_Release(self
->DS
);
399 CloseHandle(self
->NotifyEvent
);
400 self
->NotifyEvent
= NULL
;
403 static ALCboolean
ALCdsoundPlayback_reset(ALCdsoundPlayback
*self
)
405 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
406 DSBUFFERDESC DSBDescription
;
407 WAVEFORMATEXTENSIBLE OutputType
;
411 memset(&OutputType
, 0, sizeof(OutputType
));
414 IDirectSoundNotify_Release(self
->Notifies
);
415 self
->Notifies
= NULL
;
417 IDirectSoundBuffer_Release(self
->Buffer
);
419 if(self
->PrimaryBuffer
!= NULL
)
420 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
421 self
->PrimaryBuffer
= NULL
;
423 switch(device
->FmtType
)
426 device
->FmtType
= DevFmtUByte
;
429 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
433 device
->FmtType
= DevFmtShort
;
436 device
->FmtType
= DevFmtInt
;
444 hr
= IDirectSound_GetSpeakerConfig(self
->DS
, &speakers
);
447 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
449 speakers
= DSSPEAKER_CONFIG(speakers
);
450 if(speakers
== DSSPEAKER_MONO
)
451 device
->FmtChans
= DevFmtMono
;
452 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
453 device
->FmtChans
= DevFmtStereo
;
454 else if(speakers
== DSSPEAKER_QUAD
)
455 device
->FmtChans
= DevFmtQuad
;
456 else if(speakers
== DSSPEAKER_5POINT1_SURROUND
)
457 device
->FmtChans
= DevFmtX51
;
458 else if(speakers
== DSSPEAKER_5POINT1_BACK
)
459 device
->FmtChans
= DevFmtX51Rear
;
460 else if(speakers
== DSSPEAKER_7POINT1
|| speakers
== DSSPEAKER_7POINT1_SURROUND
)
461 device
->FmtChans
= DevFmtX71
;
463 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
466 switch(device
->FmtChans
)
469 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
472 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
476 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
477 SPEAKER_FRONT_RIGHT
|
482 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
483 SPEAKER_FRONT_RIGHT
|
484 SPEAKER_FRONT_CENTER
|
485 SPEAKER_LOW_FREQUENCY
|
490 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
491 SPEAKER_FRONT_RIGHT
|
492 SPEAKER_FRONT_CENTER
|
493 SPEAKER_LOW_FREQUENCY
|
498 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
499 SPEAKER_FRONT_RIGHT
|
500 SPEAKER_FRONT_CENTER
|
501 SPEAKER_LOW_FREQUENCY
|
502 SPEAKER_BACK_CENTER
|
507 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
508 SPEAKER_FRONT_RIGHT
|
509 SPEAKER_FRONT_CENTER
|
510 SPEAKER_LOW_FREQUENCY
|
520 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
521 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
522 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
523 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
524 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
525 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
526 OutputType
.Format
.cbSize
= 0;
529 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
531 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
532 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
533 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
534 if(device
->FmtType
== DevFmtFloat
)
535 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
537 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
539 if(self
->PrimaryBuffer
)
540 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
541 self
->PrimaryBuffer
= NULL
;
545 if(SUCCEEDED(hr
) && !self
->PrimaryBuffer
)
547 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
548 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
549 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
550 hr
= IDirectSound_CreateSoundBuffer(self
->DS
, &DSBDescription
, &self
->PrimaryBuffer
, NULL
);
553 hr
= IDirectSoundBuffer_SetFormat(self
->PrimaryBuffer
,&OutputType
.Format
);
558 if(device
->NumUpdates
> MAX_UPDATES
)
560 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
561 MAX_UPDATES
-1) / MAX_UPDATES
;
562 device
->NumUpdates
= MAX_UPDATES
;
565 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
566 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
567 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
568 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
569 OutputType
.Format
.nBlockAlign
;
570 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
571 hr
= IDirectSound_CreateSoundBuffer(self
->DS
, &DSBDescription
, &self
->Buffer
, NULL
);
572 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
574 device
->FmtType
= DevFmtShort
;
581 hr
= IDirectSoundBuffer_QueryInterface(self
->Buffer
, &IID_IDirectSoundNotify
, (void**)&self
->Notifies
);
584 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
587 for(i
= 0;i
< device
->NumUpdates
;++i
)
589 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
590 OutputType
.Format
.nBlockAlign
;
591 notifies
[i
].hEventNotify
= self
->NotifyEvent
;
593 if(IDirectSoundNotify_SetNotificationPositions(self
->Notifies
, device
->NumUpdates
, notifies
) != DS_OK
)
600 if(self
->Notifies
!= NULL
)
601 IDirectSoundNotify_Release(self
->Notifies
);
602 self
->Notifies
= NULL
;
603 if(self
->Buffer
!= NULL
)
604 IDirectSoundBuffer_Release(self
->Buffer
);
606 if(self
->PrimaryBuffer
!= NULL
)
607 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
608 self
->PrimaryBuffer
= NULL
;
612 ResetEvent(self
->NotifyEvent
);
613 SetDefaultWFXChannelOrder(device
);
618 static ALCboolean
ALCdsoundPlayback_start(ALCdsoundPlayback
*self
)
621 if(althrd_create(&self
->thread
, ALCdsoundPlayback_mixerProc
, self
) != althrd_success
)
627 static void ALCdsoundPlayback_stop(ALCdsoundPlayback
*self
)
635 althrd_join(self
->thread
, &res
);
637 IDirectSoundBuffer_Stop(self
->Buffer
);
642 typedef struct ALCdsoundCapture
{
643 DERIVE_FROM_TYPE(ALCbackend
);
645 IDirectSoundCapture
*DSC
;
646 IDirectSoundCaptureBuffer
*DSCbuffer
;
652 static void ALCdsoundCapture_Construct(ALCdsoundCapture
*self
, ALCdevice
*device
);
653 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, Destruct
)
654 static ALCenum
ALCdsoundCapture_open(ALCdsoundCapture
*self
, const ALCchar
*name
);
655 static void ALCdsoundCapture_close(ALCdsoundCapture
*self
);
656 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, ALCboolean
, reset
)
657 static ALCboolean
ALCdsoundCapture_start(ALCdsoundCapture
*self
);
658 static void ALCdsoundCapture_stop(ALCdsoundCapture
*self
);
659 static ALCenum
ALCdsoundCapture_captureSamples(ALCdsoundCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
660 static ALCuint
ALCdsoundCapture_availableSamples(ALCdsoundCapture
*self
);
661 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, ALint64
, getLatency
)
662 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, lock
)
663 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, unlock
)
664 DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture
)
666 DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture
);
668 static void ALCdsoundCapture_Construct(ALCdsoundCapture
*self
, ALCdevice
*device
)
670 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
671 SET_VTABLE2(ALCdsoundCapture
, ALCbackend
, self
);
675 static ALCenum
ALCdsoundCapture_open(ALCdsoundCapture
*self
, const ALCchar
*deviceName
)
677 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
678 WAVEFORMATEXTENSIBLE InputType
;
679 DSCBUFFERDESC DSCBDescription
;
680 const GUID
*guid
= NULL
;
684 if(VECTOR_SIZE(CaptureDevices
) == 0)
686 /* Initialize COM to prevent name truncation */
687 hrcom
= CoInitialize(NULL
);
688 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
690 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
695 if(!deviceName
&& VECTOR_SIZE(CaptureDevices
) > 0)
697 deviceName
= al_string_get_cstr(VECTOR_FRONT(CaptureDevices
).name
);
698 guid
= &VECTOR_FRONT(CaptureDevices
).guid
;
704 #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
705 VECTOR_FIND_IF(iter
, const DevMap
, CaptureDevices
, MATCH_NAME
);
707 if(iter
== VECTOR_ITER_END(CaptureDevices
))
708 return ALC_INVALID_VALUE
;
712 switch(device
->FmtType
)
717 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
718 return ALC_INVALID_ENUM
;
727 //DirectSoundCapture Init code
728 hr
= DirectSoundCaptureCreate(guid
, &self
->DSC
, NULL
);
731 memset(&InputType
, 0, sizeof(InputType
));
733 switch(device
->FmtChans
)
736 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
739 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
743 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
744 SPEAKER_FRONT_RIGHT
|
749 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
750 SPEAKER_FRONT_RIGHT
|
751 SPEAKER_FRONT_CENTER
|
752 SPEAKER_LOW_FREQUENCY
|
757 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
758 SPEAKER_FRONT_RIGHT
|
759 SPEAKER_FRONT_CENTER
|
760 SPEAKER_LOW_FREQUENCY
|
765 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
766 SPEAKER_FRONT_RIGHT
|
767 SPEAKER_FRONT_CENTER
|
768 SPEAKER_LOW_FREQUENCY
|
769 SPEAKER_BACK_CENTER
|
774 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
775 SPEAKER_FRONT_RIGHT
|
776 SPEAKER_FRONT_CENTER
|
777 SPEAKER_LOW_FREQUENCY
|
785 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
786 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
787 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
788 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
789 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
790 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
791 InputType
.Format
.cbSize
= 0;
793 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
795 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
796 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
797 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
798 if(device
->FmtType
== DevFmtFloat
)
799 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
801 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
804 samples
= device
->UpdateSize
* device
->NumUpdates
;
805 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
807 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
808 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
809 DSCBDescription
.dwFlags
= 0;
810 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
811 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
813 hr
= IDirectSoundCapture_CreateCaptureBuffer(self
->DSC
, &DSCBDescription
, &self
->DSCbuffer
, NULL
);
817 self
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
818 if(self
->Ring
== NULL
)
819 hr
= DSERR_OUTOFMEMORY
;
824 ERR("Device init failed: 0x%08lx\n", hr
);
826 DestroyRingBuffer(self
->Ring
);
828 if(self
->DSCbuffer
!= NULL
)
829 IDirectSoundCaptureBuffer_Release(self
->DSCbuffer
);
830 self
->DSCbuffer
= NULL
;
832 IDirectSoundCapture_Release(self
->DSC
);
835 return ALC_INVALID_VALUE
;
838 self
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
839 SetDefaultWFXChannelOrder(device
);
841 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
846 static void ALCdsoundCapture_close(ALCdsoundCapture
*self
)
848 DestroyRingBuffer(self
->Ring
);
851 if(self
->DSCbuffer
!= NULL
)
853 IDirectSoundCaptureBuffer_Stop(self
->DSCbuffer
);
854 IDirectSoundCaptureBuffer_Release(self
->DSCbuffer
);
855 self
->DSCbuffer
= NULL
;
858 IDirectSoundCapture_Release(self
->DSC
);
862 static ALCboolean
ALCdsoundCapture_start(ALCdsoundCapture
*self
)
866 hr
= IDirectSoundCaptureBuffer_Start(self
->DSCbuffer
, DSCBSTART_LOOPING
);
869 ERR("start failed: 0x%08lx\n", hr
);
870 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
);
877 static void ALCdsoundCapture_stop(ALCdsoundCapture
*self
)
881 hr
= IDirectSoundCaptureBuffer_Stop(self
->DSCbuffer
);
884 ERR("stop failed: 0x%08lx\n", hr
);
885 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
);
889 static ALCenum
ALCdsoundCapture_captureSamples(ALCdsoundCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
891 ReadRingBuffer(self
->Ring
, buffer
, samples
);
895 static ALCuint
ALCdsoundCapture_availableSamples(ALCdsoundCapture
*self
)
897 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
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
= self
->BufferBytes
;
909 LastCursor
= self
->Cursor
;
911 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(self
->DSCbuffer
, NULL
, &ReadCursor
);
914 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
917 hr
= IDirectSoundCaptureBuffer_Lock(self
->DSCbuffer
, LastCursor
, NumBytes
,
918 &ReadPtr1
, &ReadCnt1
,
919 &ReadPtr2
, &ReadCnt2
, 0);
923 WriteRingBuffer(self
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
925 WriteRingBuffer(self
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
926 hr
= IDirectSoundCaptureBuffer_Unlock(self
->DSCbuffer
,
929 self
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
934 ERR("update failed: 0x%08lx\n", hr
);
935 aluHandleDisconnect(device
);
939 return RingBufferSize(self
->Ring
);
943 static inline void AppendAllDevicesList2(const DevMap
*entry
)
944 { AppendAllDevicesList(al_string_get_cstr(entry
->name
)); }
945 static inline void AppendCaptureDeviceList2(const DevMap
*entry
)
946 { AppendCaptureDeviceList(al_string_get_cstr(entry
->name
)); }
948 typedef struct ALCdsoundBackendFactory
{
949 DERIVE_FROM_TYPE(ALCbackendFactory
);
950 } ALCdsoundBackendFactory
;
951 #define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } }
953 ALCbackendFactory
*ALCdsoundBackendFactory_getFactory(void);
955 static ALCboolean
ALCdsoundBackendFactory_init(ALCdsoundBackendFactory
*self
);
956 static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory
*self
);
957 static ALCboolean
ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory
*self
, ALCbackend_Type type
);
958 static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory
*self
, enum DevProbe type
);
959 static ALCbackend
* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
960 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory
);
963 ALCbackendFactory
*ALCdsoundBackendFactory_getFactory(void)
965 static ALCdsoundBackendFactory factory
= ALCDSOUNDBACKENDFACTORY_INITIALIZER
;
966 return STATIC_CAST(ALCbackendFactory
, &factory
);
970 static ALCboolean
ALCdsoundBackendFactory_init(ALCdsoundBackendFactory
* UNUSED(self
))
972 VECTOR_INIT(PlaybackDevices
);
973 VECTOR_INIT(CaptureDevices
);
980 static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory
* UNUSED(self
))
982 clear_devlist(&PlaybackDevices
);
983 VECTOR_DEINIT(PlaybackDevices
);
985 clear_devlist(&CaptureDevices
);
986 VECTOR_DEINIT(CaptureDevices
);
995 static ALCboolean
ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
997 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
1002 static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory
* UNUSED(self
), enum DevProbe type
)
1006 /* Initialize COM to prevent name truncation */
1007 hrcom
= CoInitialize(NULL
);
1010 case ALL_DEVICE_PROBE
:
1011 clear_devlist(&PlaybackDevices
);
1012 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
1014 ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr
);
1015 VECTOR_FOR_EACH(const DevMap
, PlaybackDevices
, AppendAllDevicesList2
);
1018 case CAPTURE_DEVICE_PROBE
:
1019 clear_devlist(&CaptureDevices
);
1020 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
1022 ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr
);
1023 VECTOR_FOR_EACH(const DevMap
, CaptureDevices
, AppendCaptureDeviceList2
);
1026 if(SUCCEEDED(hrcom
))
1030 static ALCbackend
* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
1032 if(type
== ALCbackend_Playback
)
1034 ALCdsoundPlayback
*backend
;
1036 backend
= ALCdsoundPlayback_New(sizeof(*backend
));
1037 if(!backend
) return NULL
;
1038 memset(backend
, 0, sizeof(*backend
));
1040 ALCdsoundPlayback_Construct(backend
, device
);
1042 return STATIC_CAST(ALCbackend
, backend
);
1045 if(type
== ALCbackend_Capture
)
1047 ALCdsoundCapture
*backend
;
1049 backend
= ALCdsoundCapture_New(sizeof(*backend
));
1050 if(!backend
) return NULL
;
1051 memset(backend
, 0, sizeof(*backend
));
1053 ALCdsoundCapture_Construct(backend
, device
);
1055 return STATIC_CAST(ALCbackend
, backend
);