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_
41 #include "backends/base.h"
43 #ifndef DSSPEAKER_5POINT1
44 # define DSSPEAKER_5POINT1 0x00000006
46 #ifndef DSSPEAKER_7POINT1
47 # define DSSPEAKER_7POINT1 0x00000007
49 #ifndef DSSPEAKER_7POINT1_SURROUND
50 # define DSSPEAKER_7POINT1_SURROUND 0x00000008
52 #ifndef DSSPEAKER_5POINT1_SURROUND
53 # define DSSPEAKER_5POINT1_SURROUND 0x00000009
57 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
62 static void *ds_handle
;
63 static HRESULT (WINAPI
*pDirectSoundCreate
)(const GUID
*pcGuidDevice
, IDirectSound
**ppDS
, IUnknown
*pUnkOuter
);
64 static HRESULT (WINAPI
*pDirectSoundEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
65 static HRESULT (WINAPI
*pDirectSoundCaptureCreate
)(const GUID
*pcGuidDevice
, IDirectSoundCapture
**ppDSC
, IUnknown
*pUnkOuter
);
66 static HRESULT (WINAPI
*pDirectSoundCaptureEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
68 #define DirectSoundCreate pDirectSoundCreate
69 #define DirectSoundEnumerateW pDirectSoundEnumerateW
70 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
71 #define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW
75 static ALCboolean
DSoundLoad(void)
80 ds_handle
= LoadLib("dsound.dll");
83 ERR("Failed to load dsound.dll\n");
87 #define LOAD_FUNC(f) do { \
88 p##f = GetSymbol(ds_handle, #f); \
90 CloseLib(ds_handle); \
95 LOAD_FUNC(DirectSoundCreate
);
96 LOAD_FUNC(DirectSoundEnumerateW
);
97 LOAD_FUNC(DirectSoundCaptureCreate
);
98 LOAD_FUNC(DirectSoundCaptureEnumerateW
);
106 #define MAX_UPDATES 128
112 TYPEDEF_VECTOR(DevMap
, vector_DevMap
)
114 static vector_DevMap PlaybackDevices
;
115 static vector_DevMap CaptureDevices
;
117 static void clear_devlist(vector_DevMap
*list
)
119 #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
120 VECTOR_FOR_EACH(DevMap
, *list
, DEINIT_STR
);
122 VECTOR_RESIZE(*list
, 0);
125 static BOOL CALLBACK
DSoundEnumDevices(GUID
*guid
, const WCHAR
*desc
, const WCHAR
* UNUSED(drvname
), void *data
)
127 vector_DevMap
*devices
= data
;
128 OLECHAR
*guidstr
= NULL
;
137 AL_STRING_INIT(entry
.name
);
141 al_string_copy_wcstr(&entry
.name
, desc
);
145 snprintf(str
, sizeof(str
), " #%d", count
+1);
146 al_string_append_cstr(&entry
.name
, str
);
150 iter
= VECTOR_ITER_BEGIN(*devices
);
151 end
= VECTOR_ITER_END(*devices
);
152 for(;iter
!= end
;++iter
)
154 if(al_string_cmp(entry
.name
, iter
->name
) == 0)
157 } while(iter
!= end
);
160 hr
= StringFromCLSID(guid
, &guidstr
);
163 TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry
.name
), guidstr
);
164 CoTaskMemFree(guidstr
);
167 VECTOR_PUSH_BACK(*devices
, entry
);
173 typedef struct ALCdsoundPlayback
{
174 DERIVE_FROM_TYPE(ALCbackend
);
177 IDirectSoundBuffer
*PrimaryBuffer
;
178 IDirectSoundBuffer
*Buffer
;
179 IDirectSoundNotify
*Notifies
;
182 volatile int killNow
;
186 static int ALCdsoundPlayback_mixerProc(void *ptr
);
188 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback
*self
, ALCdevice
*device
);
189 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, Destruct
)
190 static ALCenum
ALCdsoundPlayback_open(ALCdsoundPlayback
*self
, const ALCchar
*name
);
191 static void ALCdsoundPlayback_close(ALCdsoundPlayback
*self
);
192 static ALCboolean
ALCdsoundPlayback_reset(ALCdsoundPlayback
*self
);
193 static ALCboolean
ALCdsoundPlayback_start(ALCdsoundPlayback
*self
);
194 static void ALCdsoundPlayback_stop(ALCdsoundPlayback
*self
);
195 static DECLARE_FORWARD2(ALCdsoundPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
196 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, ALCuint
, availableSamples
)
197 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, ALint64
, getLatency
)
198 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, lock
)
199 static DECLARE_FORWARD(ALCdsoundPlayback
, ALCbackend
, void, unlock
)
200 DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback
)
202 DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback
);
205 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback
*self
, ALCdevice
*device
)
207 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
208 SET_VTABLE2(ALCdsoundPlayback
, ALCbackend
, self
);
212 FORCE_ALIGN
static int ALCdsoundPlayback_mixerProc(void *ptr
)
214 ALCdsoundPlayback
*self
= ptr
;
215 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
217 DWORD LastCursor
= 0;
219 void *WritePtr1
, *WritePtr2
;
220 DWORD WriteCnt1
, WriteCnt2
;
221 BOOL Playing
= FALSE
;
228 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
230 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
231 DSBCaps
.dwSize
= sizeof(DSBCaps
);
232 err
= IDirectSoundBuffer_GetCaps(self
->Buffer
, &DSBCaps
);
235 ERR("Failed to get buffer caps: 0x%lx\n", err
);
236 ALCdevice_Lock(device
);
237 aluHandleDisconnect(device
);
238 ALCdevice_Unlock(device
);
242 FrameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
243 FragSize
= device
->UpdateSize
* FrameSize
;
245 IDirectSoundBuffer_GetCurrentPosition(self
->Buffer
, &LastCursor
, NULL
);
246 while(!self
->killNow
)
248 // Get current play cursor
249 IDirectSoundBuffer_GetCurrentPosition(self
->Buffer
, &PlayCursor
, NULL
);
250 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
256 err
= IDirectSoundBuffer_Play(self
->Buffer
, 0, 0, DSBPLAY_LOOPING
);
259 ERR("Failed to play buffer: 0x%lx\n", err
);
260 ALCdevice_Lock(device
);
261 aluHandleDisconnect(device
);
262 ALCdevice_Unlock(device
);
268 avail
= WaitForSingleObjectEx(self
->NotifyEvent
, 2000, FALSE
);
269 if(avail
!= WAIT_OBJECT_0
)
270 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
273 avail
-= avail
%FragSize
;
275 // Lock output buffer
278 err
= IDirectSoundBuffer_Lock(self
->Buffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
280 // If the buffer is lost, restore it and lock
281 if(err
== DSERR_BUFFERLOST
)
283 WARN("Buffer lost, restoring...\n");
284 err
= IDirectSoundBuffer_Restore(self
->Buffer
);
289 err
= IDirectSoundBuffer_Lock(self
->Buffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
293 // Successfully locked the output buffer
296 // If we have an active context, mix data directly into output buffer otherwise fill with silence
297 aluMixData(device
, WritePtr1
, WriteCnt1
/FrameSize
);
298 aluMixData(device
, WritePtr2
, WriteCnt2
/FrameSize
);
300 // Unlock output buffer only when successfully locked
301 IDirectSoundBuffer_Unlock(self
->Buffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
305 ERR("Buffer lock error: %#lx\n", err
);
306 ALCdevice_Lock(device
);
307 aluHandleDisconnect(device
);
308 ALCdevice_Unlock(device
);
312 // Update old write cursor location
313 LastCursor
+= WriteCnt1
+WriteCnt2
;
314 LastCursor
%= DSBCaps
.dwBufferBytes
;
320 static ALCenum
ALCdsoundPlayback_open(ALCdsoundPlayback
*self
, const ALCchar
*deviceName
)
322 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
323 const GUID
*guid
= NULL
;
326 if(VECTOR_SIZE(PlaybackDevices
) == 0)
328 /* Initialize COM to prevent name truncation */
329 hrcom
= CoInitialize(NULL
);
330 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
332 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
337 if(!deviceName
&& VECTOR_SIZE(PlaybackDevices
) > 0)
339 deviceName
= al_string_get_cstr(VECTOR_FRONT(PlaybackDevices
).name
);
340 guid
= &VECTOR_FRONT(PlaybackDevices
).guid
;
346 #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
347 VECTOR_FIND_IF(iter
, const DevMap
, PlaybackDevices
, MATCH_NAME
);
349 if(iter
== VECTOR_ITER_END(PlaybackDevices
))
350 return ALC_INVALID_VALUE
;
355 self
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
356 if(self
->NotifyEvent
== NULL
)
359 //DirectSound Init code
361 hr
= DirectSoundCreate(guid
, &self
->DS
, NULL
);
363 hr
= IDirectSound_SetCooperativeLevel(self
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
367 IDirectSound_Release(self
->DS
);
369 if(self
->NotifyEvent
)
370 CloseHandle(self
->NotifyEvent
);
371 self
->NotifyEvent
= NULL
;
373 ERR("Device init failed: 0x%08lx\n", hr
);
374 return ALC_INVALID_VALUE
;
377 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
382 static void ALCdsoundPlayback_close(ALCdsoundPlayback
*self
)
385 IDirectSoundNotify_Release(self
->Notifies
);
386 self
->Notifies
= NULL
;
388 IDirectSoundBuffer_Release(self
->Buffer
);
390 if(self
->PrimaryBuffer
!= NULL
)
391 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
392 self
->PrimaryBuffer
= NULL
;
394 IDirectSound_Release(self
->DS
);
396 CloseHandle(self
->NotifyEvent
);
397 self
->NotifyEvent
= NULL
;
400 static ALCboolean
ALCdsoundPlayback_reset(ALCdsoundPlayback
*self
)
402 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
403 DSBUFFERDESC DSBDescription
;
404 WAVEFORMATEXTENSIBLE OutputType
;
408 memset(&OutputType
, 0, sizeof(OutputType
));
411 IDirectSoundNotify_Release(self
->Notifies
);
412 self
->Notifies
= NULL
;
414 IDirectSoundBuffer_Release(self
->Buffer
);
416 if(self
->PrimaryBuffer
!= NULL
)
417 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
418 self
->PrimaryBuffer
= NULL
;
420 switch(device
->FmtType
)
423 device
->FmtType
= DevFmtUByte
;
426 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
430 device
->FmtType
= DevFmtShort
;
433 device
->FmtType
= DevFmtInt
;
441 hr
= IDirectSound_GetSpeakerConfig(self
->DS
, &speakers
);
444 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
446 speakers
= DSSPEAKER_CONFIG(speakers
);
447 if(speakers
== DSSPEAKER_MONO
)
448 device
->FmtChans
= DevFmtMono
;
449 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
450 device
->FmtChans
= DevFmtStereo
;
451 else if(speakers
== DSSPEAKER_QUAD
)
452 device
->FmtChans
= DevFmtQuad
;
453 else if(speakers
== DSSPEAKER_5POINT1
|| speakers
== DSSPEAKER_5POINT1_SURROUND
)
454 device
->FmtChans
= DevFmtX51
;
455 else if(speakers
== DSSPEAKER_7POINT1
|| speakers
== DSSPEAKER_7POINT1_SURROUND
)
456 device
->FmtChans
= DevFmtX71
;
458 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
461 switch(device
->FmtChans
)
464 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
467 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
471 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
472 SPEAKER_FRONT_RIGHT
|
477 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
478 SPEAKER_FRONT_RIGHT
|
479 SPEAKER_FRONT_CENTER
|
480 SPEAKER_LOW_FREQUENCY
|
485 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
486 SPEAKER_FRONT_RIGHT
|
487 SPEAKER_FRONT_CENTER
|
488 SPEAKER_LOW_FREQUENCY
|
493 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
494 SPEAKER_FRONT_RIGHT
|
495 SPEAKER_FRONT_CENTER
|
496 SPEAKER_LOW_FREQUENCY
|
497 SPEAKER_BACK_CENTER
|
502 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
503 SPEAKER_FRONT_RIGHT
|
504 SPEAKER_FRONT_CENTER
|
505 SPEAKER_LOW_FREQUENCY
|
515 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
516 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
517 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
518 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
519 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
520 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
521 OutputType
.Format
.cbSize
= 0;
524 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
526 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
527 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
528 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
529 if(device
->FmtType
== DevFmtFloat
)
530 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
532 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
534 if(self
->PrimaryBuffer
)
535 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
536 self
->PrimaryBuffer
= NULL
;
540 if(SUCCEEDED(hr
) && !self
->PrimaryBuffer
)
542 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
543 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
544 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
545 hr
= IDirectSound_CreateSoundBuffer(self
->DS
, &DSBDescription
, &self
->PrimaryBuffer
, NULL
);
548 hr
= IDirectSoundBuffer_SetFormat(self
->PrimaryBuffer
,&OutputType
.Format
);
553 if(device
->NumUpdates
> MAX_UPDATES
)
555 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
556 MAX_UPDATES
-1) / MAX_UPDATES
;
557 device
->NumUpdates
= MAX_UPDATES
;
560 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
561 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
562 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
563 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
564 OutputType
.Format
.nBlockAlign
;
565 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
566 hr
= IDirectSound_CreateSoundBuffer(self
->DS
, &DSBDescription
, &self
->Buffer
, NULL
);
567 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
569 device
->FmtType
= DevFmtShort
;
576 hr
= IDirectSoundBuffer_QueryInterface(self
->Buffer
, &IID_IDirectSoundNotify
, (void**)&self
->Notifies
);
579 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
582 for(i
= 0;i
< device
->NumUpdates
;++i
)
584 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
585 OutputType
.Format
.nBlockAlign
;
586 notifies
[i
].hEventNotify
= self
->NotifyEvent
;
588 if(IDirectSoundNotify_SetNotificationPositions(self
->Notifies
, device
->NumUpdates
, notifies
) != DS_OK
)
595 if(self
->Notifies
!= NULL
)
596 IDirectSoundNotify_Release(self
->Notifies
);
597 self
->Notifies
= NULL
;
598 if(self
->Buffer
!= NULL
)
599 IDirectSoundBuffer_Release(self
->Buffer
);
601 if(self
->PrimaryBuffer
!= NULL
)
602 IDirectSoundBuffer_Release(self
->PrimaryBuffer
);
603 self
->PrimaryBuffer
= NULL
;
607 ResetEvent(self
->NotifyEvent
);
608 SetDefaultWFXChannelOrder(device
);
613 static ALCboolean
ALCdsoundPlayback_start(ALCdsoundPlayback
*self
)
616 if(althrd_create(&self
->thread
, ALCdsoundPlayback_mixerProc
, self
) != althrd_success
)
622 static void ALCdsoundPlayback_stop(ALCdsoundPlayback
*self
)
630 althrd_join(self
->thread
, &res
);
632 IDirectSoundBuffer_Stop(self
->Buffer
);
637 typedef struct ALCdsoundCapture
{
638 DERIVE_FROM_TYPE(ALCbackend
);
640 IDirectSoundCapture
*DSC
;
641 IDirectSoundCaptureBuffer
*DSCbuffer
;
647 static void ALCdsoundCapture_Construct(ALCdsoundCapture
*self
, ALCdevice
*device
);
648 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, Destruct
)
649 static ALCenum
ALCdsoundCapture_open(ALCdsoundCapture
*self
, const ALCchar
*name
);
650 static void ALCdsoundCapture_close(ALCdsoundCapture
*self
);
651 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, ALCboolean
, reset
)
652 static ALCboolean
ALCdsoundCapture_start(ALCdsoundCapture
*self
);
653 static void ALCdsoundCapture_stop(ALCdsoundCapture
*self
);
654 static ALCenum
ALCdsoundCapture_captureSamples(ALCdsoundCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
655 static ALCuint
ALCdsoundCapture_availableSamples(ALCdsoundCapture
*self
);
656 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, ALint64
, getLatency
)
657 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, lock
)
658 static DECLARE_FORWARD(ALCdsoundCapture
, ALCbackend
, void, unlock
)
659 DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture
)
661 DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture
);
663 static void ALCdsoundCapture_Construct(ALCdsoundCapture
*self
, ALCdevice
*device
)
665 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
666 SET_VTABLE2(ALCdsoundCapture
, ALCbackend
, self
);
670 static ALCenum
ALCdsoundCapture_open(ALCdsoundCapture
*self
, const ALCchar
*deviceName
)
672 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
673 WAVEFORMATEXTENSIBLE InputType
;
674 DSCBUFFERDESC DSCBDescription
;
675 const GUID
*guid
= NULL
;
679 if(VECTOR_SIZE(CaptureDevices
) == 0)
681 /* Initialize COM to prevent name truncation */
682 hrcom
= CoInitialize(NULL
);
683 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
685 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
690 if(!deviceName
&& VECTOR_SIZE(CaptureDevices
) > 0)
692 deviceName
= al_string_get_cstr(VECTOR_FRONT(CaptureDevices
).name
);
693 guid
= &VECTOR_FRONT(CaptureDevices
).guid
;
699 #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
700 VECTOR_FIND_IF(iter
, const DevMap
, CaptureDevices
, MATCH_NAME
);
702 if(iter
== VECTOR_ITER_END(CaptureDevices
))
703 return ALC_INVALID_VALUE
;
707 switch(device
->FmtType
)
712 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
713 return ALC_INVALID_ENUM
;
722 //DirectSoundCapture Init code
723 hr
= DirectSoundCaptureCreate(guid
, &self
->DSC
, NULL
);
726 memset(&InputType
, 0, sizeof(InputType
));
728 switch(device
->FmtChans
)
731 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
734 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
738 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
739 SPEAKER_FRONT_RIGHT
|
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
|
760 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
761 SPEAKER_FRONT_RIGHT
|
762 SPEAKER_FRONT_CENTER
|
763 SPEAKER_LOW_FREQUENCY
|
764 SPEAKER_BACK_CENTER
|
769 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
770 SPEAKER_FRONT_RIGHT
|
771 SPEAKER_FRONT_CENTER
|
772 SPEAKER_LOW_FREQUENCY
|
780 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
781 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
782 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
783 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
784 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
785 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
786 InputType
.Format
.cbSize
= 0;
788 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
790 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
791 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
792 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
793 if(device
->FmtType
== DevFmtFloat
)
794 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
796 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
799 samples
= device
->UpdateSize
* device
->NumUpdates
;
800 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
802 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
803 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
804 DSCBDescription
.dwFlags
= 0;
805 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
806 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
808 hr
= IDirectSoundCapture_CreateCaptureBuffer(self
->DSC
, &DSCBDescription
, &self
->DSCbuffer
, NULL
);
812 self
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
813 if(self
->Ring
== NULL
)
814 hr
= DSERR_OUTOFMEMORY
;
819 ERR("Device init failed: 0x%08lx\n", hr
);
821 DestroyRingBuffer(self
->Ring
);
823 if(self
->DSCbuffer
!= NULL
)
824 IDirectSoundCaptureBuffer_Release(self
->DSCbuffer
);
825 self
->DSCbuffer
= NULL
;
827 IDirectSoundCapture_Release(self
->DSC
);
830 return ALC_INVALID_VALUE
;
833 self
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
834 SetDefaultWFXChannelOrder(device
);
836 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
841 static void ALCdsoundCapture_close(ALCdsoundCapture
*self
)
843 DestroyRingBuffer(self
->Ring
);
846 if(self
->DSCbuffer
!= NULL
)
848 IDirectSoundCaptureBuffer_Stop(self
->DSCbuffer
);
849 IDirectSoundCaptureBuffer_Release(self
->DSCbuffer
);
850 self
->DSCbuffer
= NULL
;
853 IDirectSoundCapture_Release(self
->DSC
);
857 static ALCboolean
ALCdsoundCapture_start(ALCdsoundCapture
*self
)
861 hr
= IDirectSoundCaptureBuffer_Start(self
->DSCbuffer
, DSCBSTART_LOOPING
);
864 ERR("start failed: 0x%08lx\n", hr
);
865 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
);
872 static void ALCdsoundCapture_stop(ALCdsoundCapture
*self
)
876 hr
= IDirectSoundCaptureBuffer_Stop(self
->DSCbuffer
);
879 ERR("stop failed: 0x%08lx\n", hr
);
880 aluHandleDisconnect(STATIC_CAST(ALCbackend
, self
)->mDevice
);
884 static ALCenum
ALCdsoundCapture_captureSamples(ALCdsoundCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
886 ReadRingBuffer(self
->Ring
, buffer
, samples
);
890 static ALCuint
ALCdsoundCapture_availableSamples(ALCdsoundCapture
*self
)
892 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
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
= self
->BufferBytes
;
904 LastCursor
= self
->Cursor
;
906 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(self
->DSCbuffer
, NULL
, &ReadCursor
);
909 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
912 hr
= IDirectSoundCaptureBuffer_Lock(self
->DSCbuffer
, LastCursor
, NumBytes
,
913 &ReadPtr1
, &ReadCnt1
,
914 &ReadPtr2
, &ReadCnt2
, 0);
918 WriteRingBuffer(self
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
920 WriteRingBuffer(self
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
921 hr
= IDirectSoundCaptureBuffer_Unlock(self
->DSCbuffer
,
924 self
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
929 ERR("update failed: 0x%08lx\n", hr
);
930 aluHandleDisconnect(device
);
934 return RingBufferSize(self
->Ring
);
938 static inline void AppendAllDevicesList2(const DevMap
*entry
)
939 { AppendAllDevicesList(al_string_get_cstr(entry
->name
)); }
940 static inline void AppendCaptureDeviceList2(const DevMap
*entry
)
941 { AppendCaptureDeviceList(al_string_get_cstr(entry
->name
)); }
943 typedef struct ALCdsoundBackendFactory
{
944 DERIVE_FROM_TYPE(ALCbackendFactory
);
945 } ALCdsoundBackendFactory
;
946 #define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } }
948 ALCbackendFactory
*ALCdsoundBackendFactory_getFactory(void);
950 static ALCboolean
ALCdsoundBackendFactory_init(ALCdsoundBackendFactory
*self
);
951 static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory
*self
);
952 static ALCboolean
ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory
*self
, ALCbackend_Type type
);
953 static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory
*self
, enum DevProbe type
);
954 static ALCbackend
* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
955 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory
);
958 ALCbackendFactory
*ALCdsoundBackendFactory_getFactory(void)
960 static ALCdsoundBackendFactory factory
= ALCDSOUNDBACKENDFACTORY_INITIALIZER
;
961 return STATIC_CAST(ALCbackendFactory
, &factory
);
965 static ALCboolean
ALCdsoundBackendFactory_init(ALCdsoundBackendFactory
* UNUSED(self
))
967 VECTOR_INIT(PlaybackDevices
);
968 VECTOR_INIT(CaptureDevices
);
975 static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory
* UNUSED(self
))
977 clear_devlist(&PlaybackDevices
);
978 VECTOR_DEINIT(PlaybackDevices
);
980 clear_devlist(&CaptureDevices
);
981 VECTOR_DEINIT(CaptureDevices
);
990 static ALCboolean
ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
992 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
997 static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory
* UNUSED(self
), enum DevProbe type
)
1001 /* Initialize COM to prevent name truncation */
1002 hrcom
= CoInitialize(NULL
);
1005 case ALL_DEVICE_PROBE
:
1006 clear_devlist(&PlaybackDevices
);
1007 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
1009 ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr
);
1010 VECTOR_FOR_EACH(const DevMap
, PlaybackDevices
, AppendAllDevicesList2
);
1013 case CAPTURE_DEVICE_PROBE
:
1014 clear_devlist(&CaptureDevices
);
1015 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
1017 ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr
);
1018 VECTOR_FOR_EACH(const DevMap
, CaptureDevices
, AppendCaptureDeviceList2
);
1021 if(SUCCEEDED(hrcom
))
1025 static ALCbackend
* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
1027 if(type
== ALCbackend_Playback
)
1029 ALCdsoundPlayback
*backend
;
1031 backend
= ALCdsoundPlayback_New(sizeof(*backend
));
1032 if(!backend
) return NULL
;
1033 memset(backend
, 0, sizeof(*backend
));
1035 ALCdsoundPlayback_Construct(backend
, device
);
1037 return STATIC_CAST(ALCbackend
, backend
);
1040 if(type
== ALCbackend_Capture
)
1042 ALCdsoundCapture
*backend
;
1044 backend
= ALCdsoundCapture_New(sizeof(*backend
));
1045 if(!backend
) return NULL
;
1046 memset(backend
, 0, sizeof(*backend
));
1048 ALCdsoundCapture_Construct(backend
, device
);
1050 return STATIC_CAST(ALCbackend
, backend
);