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 #ifndef DSSPEAKER_5POINT1
42 # define DSSPEAKER_5POINT1 0x00000006
44 #ifndef DSSPEAKER_7POINT1
45 # define DSSPEAKER_7POINT1 0x00000007
47 #ifndef DSSPEAKER_7POINT1_SURROUND
48 # define DSSPEAKER_7POINT1_SURROUND 0x00000008
50 #ifndef DSSPEAKER_5POINT1_SURROUND
51 # define DSSPEAKER_5POINT1_SURROUND 0x00000009
55 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
56 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 static void *ds_handle
;
60 static HRESULT (WINAPI
*pDirectSoundCreate
)(LPCGUID pcGuidDevice
, IDirectSound
**ppDS
, IUnknown
*pUnkOuter
);
61 static HRESULT (WINAPI
*pDirectSoundEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
62 static HRESULT (WINAPI
*pDirectSoundCaptureCreate
)(LPCGUID pcGuidDevice
, IDirectSoundCapture
**ppDSC
, IUnknown
*pUnkOuter
);
63 static HRESULT (WINAPI
*pDirectSoundCaptureEnumerateW
)(LPDSENUMCALLBACKW pDSEnumCallback
, void *pContext
);
65 #define DirectSoundCreate pDirectSoundCreate
66 #define DirectSoundEnumerateW pDirectSoundEnumerateW
67 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
68 #define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW
72 // DirectSound Playback Device
74 IDirectSoundBuffer
*PrimaryBuffer
;
75 IDirectSoundBuffer
*Buffer
;
76 IDirectSoundNotify
*Notifies
;
84 // DirectSound Capture Device
85 IDirectSoundCapture
*DSC
;
86 IDirectSoundCaptureBuffer
*DSCbuffer
;
99 vector_DevMap PlaybackDevices
;
100 vector_DevMap CaptureDevices
;
103 #define MAX_UPDATES 128
106 static ALCboolean
DSoundLoad(void)
110 ds_handle
= LoadLib("dsound.dll");
111 if(ds_handle
== NULL
)
113 ERR("Failed to load dsound.dll\n");
117 #define LOAD_FUNC(f) do { \
118 p##f = GetSymbol(ds_handle, #f); \
120 CloseLib(ds_handle); \
125 LOAD_FUNC(DirectSoundCreate
);
126 LOAD_FUNC(DirectSoundEnumerateW
);
127 LOAD_FUNC(DirectSoundCaptureCreate
);
128 LOAD_FUNC(DirectSoundCaptureEnumerateW
);
135 static BOOL CALLBACK
DSoundEnumDevices(LPGUID guid
, LPCWSTR desc
, LPCWSTR
UNUSED(drvname
), LPVOID data
)
137 vector_DevMap
*devices
= data
;
138 LPOLESTR guidstr
= NULL
;
147 AL_STRING_INIT(entry
.name
);
151 al_string_copy_wcstr(&entry
.name
, desc
);
155 snprintf(str
, sizeof(str
), " #%d", count
+1);
156 al_string_append_cstr(&entry
.name
, str
);
160 iter
= VECTOR_ITER_BEGIN(*devices
);
161 end
= VECTOR_ITER_END(*devices
);
162 for(;iter
!= end
;++iter
)
164 if(al_string_cmp(entry
.name
, iter
->name
) == 0)
167 } while(iter
!= end
);
170 hr
= StringFromCLSID(guid
, &guidstr
);
173 TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry
.name
), guidstr
);
174 CoTaskMemFree(guidstr
);
177 VECTOR_PUSH_BACK(*devices
, entry
);
183 FORCE_ALIGN
static int DSoundPlaybackProc(void *ptr
)
185 ALCdevice
*Device
= (ALCdevice
*)ptr
;
186 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)Device
->ExtraData
;
188 DWORD LastCursor
= 0;
190 VOID
*WritePtr1
, *WritePtr2
;
191 DWORD WriteCnt1
, WriteCnt2
;
192 BOOL Playing
= FALSE
;
199 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
201 memset(&DSBCaps
, 0, sizeof(DSBCaps
));
202 DSBCaps
.dwSize
= sizeof(DSBCaps
);
203 err
= IDirectSoundBuffer_GetCaps(data
->Buffer
, &DSBCaps
);
206 ERR("Failed to get buffer caps: 0x%lx\n", err
);
207 ALCdevice_Lock(Device
);
208 aluHandleDisconnect(Device
);
209 ALCdevice_Unlock(Device
);
213 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
214 FragSize
= Device
->UpdateSize
* FrameSize
;
216 IDirectSoundBuffer_GetCurrentPosition(data
->Buffer
, &LastCursor
, NULL
);
217 while(!data
->killNow
)
219 // Get current play cursor
220 IDirectSoundBuffer_GetCurrentPosition(data
->Buffer
, &PlayCursor
, NULL
);
221 avail
= (PlayCursor
-LastCursor
+DSBCaps
.dwBufferBytes
) % DSBCaps
.dwBufferBytes
;
227 err
= IDirectSoundBuffer_Play(data
->Buffer
, 0, 0, DSBPLAY_LOOPING
);
230 ERR("Failed to play buffer: 0x%lx\n", err
);
231 ALCdevice_Lock(Device
);
232 aluHandleDisconnect(Device
);
233 ALCdevice_Unlock(Device
);
239 avail
= WaitForSingleObjectEx(data
->NotifyEvent
, 2000, FALSE
);
240 if(avail
!= WAIT_OBJECT_0
)
241 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail
);
244 avail
-= avail
%FragSize
;
246 // Lock output buffer
249 err
= IDirectSoundBuffer_Lock(data
->Buffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
251 // If the buffer is lost, restore it and lock
252 if(err
== DSERR_BUFFERLOST
)
254 WARN("Buffer lost, restoring...\n");
255 err
= IDirectSoundBuffer_Restore(data
->Buffer
);
260 err
= IDirectSoundBuffer_Lock(data
->Buffer
, 0, DSBCaps
.dwBufferBytes
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
264 // Successfully locked the output buffer
267 // If we have an active context, mix data directly into output buffer otherwise fill with silence
268 aluMixData(Device
, WritePtr1
, WriteCnt1
/FrameSize
);
269 aluMixData(Device
, WritePtr2
, WriteCnt2
/FrameSize
);
271 // Unlock output buffer only when successfully locked
272 IDirectSoundBuffer_Unlock(data
->Buffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
276 ERR("Buffer lock error: %#lx\n", err
);
277 ALCdevice_Lock(Device
);
278 aluHandleDisconnect(Device
);
279 ALCdevice_Unlock(Device
);
283 // Update old write cursor location
284 LastCursor
+= WriteCnt1
+WriteCnt2
;
285 LastCursor
%= DSBCaps
.dwBufferBytes
;
291 static ALCenum
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
293 DSoundPlaybackData
*data
= NULL
;
297 if(VECTOR_SIZE(PlaybackDevices
) == 0)
299 /* Initialize COM to prevent name truncation */
300 hrcom
= CoInitialize(NULL
);
301 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
303 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
308 if(!deviceName
&& VECTOR_SIZE(PlaybackDevices
) > 0)
310 deviceName
= al_string_get_cstr(VECTOR_FRONT(PlaybackDevices
).name
);
311 guid
= &VECTOR_FRONT(PlaybackDevices
).guid
;
317 iter
= VECTOR_ITER_BEGIN(PlaybackDevices
);
318 end
= VECTOR_ITER_END(PlaybackDevices
);
319 for(;iter
!= end
;++iter
)
321 if(al_string_cmp_cstr(iter
->name
, deviceName
) == 0)
328 return ALC_INVALID_VALUE
;
331 //Initialise requested device
332 data
= calloc(1, sizeof(DSoundPlaybackData
));
334 return ALC_OUT_OF_MEMORY
;
337 data
->NotifyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
338 if(data
->NotifyEvent
== NULL
)
341 //DirectSound Init code
343 hr
= DirectSoundCreate(guid
, &data
->DS
, NULL
);
345 hr
= IDirectSound_SetCooperativeLevel(data
->DS
, GetForegroundWindow(), DSSCL_PRIORITY
);
349 IDirectSound_Release(data
->DS
);
350 if(data
->NotifyEvent
)
351 CloseHandle(data
->NotifyEvent
);
353 ERR("Device init failed: 0x%08lx\n", hr
);
354 return ALC_INVALID_VALUE
;
357 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
358 device
->ExtraData
= data
;
362 static void DSoundClosePlayback(ALCdevice
*device
)
364 DSoundPlaybackData
*data
= device
->ExtraData
;
367 IDirectSoundNotify_Release(data
->Notifies
);
368 data
->Notifies
= NULL
;
370 IDirectSoundBuffer_Release(data
->Buffer
);
372 if(data
->PrimaryBuffer
!= NULL
)
373 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
374 data
->PrimaryBuffer
= NULL
;
376 IDirectSound_Release(data
->DS
);
377 CloseHandle(data
->NotifyEvent
);
379 device
->ExtraData
= NULL
;
382 static ALCboolean
DSoundResetPlayback(ALCdevice
*device
)
384 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
385 DSBUFFERDESC DSBDescription
;
386 WAVEFORMATEXTENSIBLE OutputType
;
390 memset(&OutputType
, 0, sizeof(OutputType
));
393 IDirectSoundNotify_Release(data
->Notifies
);
394 data
->Notifies
= NULL
;
396 IDirectSoundBuffer_Release(data
->Buffer
);
398 if(data
->PrimaryBuffer
!= NULL
)
399 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
400 data
->PrimaryBuffer
= NULL
;
402 switch(device
->FmtType
)
405 device
->FmtType
= DevFmtUByte
;
408 if((device
->Flags
&DEVICE_SAMPLE_TYPE_REQUEST
))
412 device
->FmtType
= DevFmtShort
;
415 device
->FmtType
= DevFmtInt
;
423 hr
= IDirectSound_GetSpeakerConfig(data
->DS
, &speakers
);
426 if(!(device
->Flags
&DEVICE_CHANNELS_REQUEST
))
428 speakers
= DSSPEAKER_CONFIG(speakers
);
429 if(speakers
== DSSPEAKER_MONO
)
430 device
->FmtChans
= DevFmtMono
;
431 else if(speakers
== DSSPEAKER_STEREO
|| speakers
== DSSPEAKER_HEADPHONE
)
432 device
->FmtChans
= DevFmtStereo
;
433 else if(speakers
== DSSPEAKER_QUAD
)
434 device
->FmtChans
= DevFmtQuad
;
435 else if(speakers
== DSSPEAKER_5POINT1
|| speakers
== DSSPEAKER_5POINT1_SURROUND
)
436 device
->FmtChans
= DevFmtX51
;
437 else if(speakers
== DSSPEAKER_7POINT1
|| speakers
== DSSPEAKER_7POINT1_SURROUND
)
438 device
->FmtChans
= DevFmtX71
;
440 ERR("Unknown system speaker config: 0x%lx\n", speakers
);
443 switch(device
->FmtChans
)
446 OutputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
449 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
453 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
454 SPEAKER_FRONT_RIGHT
|
459 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
460 SPEAKER_FRONT_RIGHT
|
461 SPEAKER_FRONT_CENTER
|
462 SPEAKER_LOW_FREQUENCY
|
467 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
468 SPEAKER_FRONT_RIGHT
|
469 SPEAKER_FRONT_CENTER
|
470 SPEAKER_LOW_FREQUENCY
|
475 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
476 SPEAKER_FRONT_RIGHT
|
477 SPEAKER_FRONT_CENTER
|
478 SPEAKER_LOW_FREQUENCY
|
479 SPEAKER_BACK_CENTER
|
484 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
485 SPEAKER_FRONT_RIGHT
|
486 SPEAKER_FRONT_CENTER
|
487 SPEAKER_LOW_FREQUENCY
|
497 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
498 OutputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
499 OutputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
500 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
501 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
502 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
503 OutputType
.Format
.cbSize
= 0;
506 if(OutputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
508 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
509 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
510 OutputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
511 if(device
->FmtType
== DevFmtFloat
)
512 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
514 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
516 if(data
->PrimaryBuffer
)
517 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
518 data
->PrimaryBuffer
= NULL
;
522 if(SUCCEEDED(hr
) && !data
->PrimaryBuffer
)
524 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
525 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
526 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
527 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->PrimaryBuffer
, NULL
);
530 hr
= IDirectSoundBuffer_SetFormat(data
->PrimaryBuffer
,&OutputType
.Format
);
535 if(device
->NumUpdates
> MAX_UPDATES
)
537 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+
538 MAX_UPDATES
-1) / MAX_UPDATES
;
539 device
->NumUpdates
= MAX_UPDATES
;
542 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
543 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
544 DSBDescription
.dwFlags
=DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2
|DSBCAPS_GLOBALFOCUS
;
545 DSBDescription
.dwBufferBytes
=device
->UpdateSize
* device
->NumUpdates
*
546 OutputType
.Format
.nBlockAlign
;
547 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
548 hr
= IDirectSound_CreateSoundBuffer(data
->DS
, &DSBDescription
, &data
->Buffer
, NULL
);
549 if(FAILED(hr
) && device
->FmtType
== DevFmtFloat
)
551 device
->FmtType
= DevFmtShort
;
558 hr
= IDirectSoundBuffer_QueryInterface(data
->Buffer
, &IID_IDirectSoundNotify
, (LPVOID
*)&data
->Notifies
);
561 DSBPOSITIONNOTIFY notifies
[MAX_UPDATES
];
564 for(i
= 0;i
< device
->NumUpdates
;++i
)
566 notifies
[i
].dwOffset
= i
* device
->UpdateSize
*
567 OutputType
.Format
.nBlockAlign
;
568 notifies
[i
].hEventNotify
= data
->NotifyEvent
;
570 if(IDirectSoundNotify_SetNotificationPositions(data
->Notifies
, device
->NumUpdates
, notifies
) != DS_OK
)
577 if(data
->Notifies
!= NULL
)
578 IDirectSoundNotify_Release(data
->Notifies
);
579 data
->Notifies
= NULL
;
580 if(data
->Buffer
!= NULL
)
581 IDirectSoundBuffer_Release(data
->Buffer
);
583 if(data
->PrimaryBuffer
!= NULL
)
584 IDirectSoundBuffer_Release(data
->PrimaryBuffer
);
585 data
->PrimaryBuffer
= NULL
;
589 ResetEvent(data
->NotifyEvent
);
590 SetDefaultWFXChannelOrder(device
);
595 static ALCboolean
DSoundStartPlayback(ALCdevice
*device
)
597 DSoundPlaybackData
*data
= (DSoundPlaybackData
*)device
->ExtraData
;
600 if(althrd_create(&data
->thread
, DSoundPlaybackProc
, device
) != althrd_success
)
606 static void DSoundStopPlayback(ALCdevice
*device
)
608 DSoundPlaybackData
*data
= device
->ExtraData
;
615 althrd_join(data
->thread
, &res
);
617 IDirectSoundBuffer_Stop(data
->Buffer
);
621 static ALCenum
DSoundOpenCapture(ALCdevice
*device
, const ALCchar
*deviceName
)
623 DSoundCaptureData
*data
= NULL
;
624 WAVEFORMATEXTENSIBLE InputType
;
625 DSCBUFFERDESC DSCBDescription
;
630 if(VECTOR_SIZE(CaptureDevices
) == 0)
632 /* Initialize COM to prevent name truncation */
633 hrcom
= CoInitialize(NULL
);
634 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
636 ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr
);
641 if(!deviceName
&& VECTOR_SIZE(CaptureDevices
) > 0)
643 deviceName
= al_string_get_cstr(VECTOR_FRONT(CaptureDevices
).name
);
644 guid
= &VECTOR_FRONT(CaptureDevices
).guid
;
650 iter
= VECTOR_ITER_BEGIN(CaptureDevices
);
651 end
= VECTOR_ITER_END(CaptureDevices
);
652 for(;iter
!= end
;++iter
)
654 if(al_string_cmp_cstr(iter
->name
, deviceName
) == 0)
661 return ALC_INVALID_VALUE
;
664 switch(device
->FmtType
)
669 WARN("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
670 return ALC_INVALID_ENUM
;
679 //Initialise requested device
680 data
= calloc(1, sizeof(DSoundCaptureData
));
682 return ALC_OUT_OF_MEMORY
;
686 //DirectSoundCapture Init code
688 hr
= DirectSoundCaptureCreate(guid
, &data
->DSC
, NULL
);
691 memset(&InputType
, 0, sizeof(InputType
));
693 switch(device
->FmtChans
)
696 InputType
.dwChannelMask
= SPEAKER_FRONT_CENTER
;
699 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
703 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
704 SPEAKER_FRONT_RIGHT
|
709 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
710 SPEAKER_FRONT_RIGHT
|
711 SPEAKER_FRONT_CENTER
|
712 SPEAKER_LOW_FREQUENCY
|
717 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
718 SPEAKER_FRONT_RIGHT
|
719 SPEAKER_FRONT_CENTER
|
720 SPEAKER_LOW_FREQUENCY
|
725 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
726 SPEAKER_FRONT_RIGHT
|
727 SPEAKER_FRONT_CENTER
|
728 SPEAKER_LOW_FREQUENCY
|
729 SPEAKER_BACK_CENTER
|
734 InputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
735 SPEAKER_FRONT_RIGHT
|
736 SPEAKER_FRONT_CENTER
|
737 SPEAKER_LOW_FREQUENCY
|
745 InputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
746 InputType
.Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
747 InputType
.Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
748 InputType
.Format
.nBlockAlign
= InputType
.Format
.nChannels
*InputType
.Format
.wBitsPerSample
/8;
749 InputType
.Format
.nSamplesPerSec
= device
->Frequency
;
750 InputType
.Format
.nAvgBytesPerSec
= InputType
.Format
.nSamplesPerSec
*InputType
.Format
.nBlockAlign
;
751 InputType
.Format
.cbSize
= 0;
753 if(InputType
.Format
.nChannels
> 2 || device
->FmtType
== DevFmtFloat
)
755 InputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
756 InputType
.Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
757 InputType
.Samples
.wValidBitsPerSample
= InputType
.Format
.wBitsPerSample
;
758 if(device
->FmtType
== DevFmtFloat
)
759 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
761 InputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
764 samples
= device
->UpdateSize
* device
->NumUpdates
;
765 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
767 memset(&DSCBDescription
, 0, sizeof(DSCBUFFERDESC
));
768 DSCBDescription
.dwSize
= sizeof(DSCBUFFERDESC
);
769 DSCBDescription
.dwFlags
= 0;
770 DSCBDescription
.dwBufferBytes
= samples
* InputType
.Format
.nBlockAlign
;
771 DSCBDescription
.lpwfxFormat
= &InputType
.Format
;
773 hr
= IDirectSoundCapture_CreateCaptureBuffer(data
->DSC
, &DSCBDescription
, &data
->DSCbuffer
, NULL
);
777 data
->Ring
= CreateRingBuffer(InputType
.Format
.nBlockAlign
, device
->UpdateSize
* device
->NumUpdates
);
778 if(data
->Ring
== NULL
)
779 hr
= DSERR_OUTOFMEMORY
;
784 ERR("Device init failed: 0x%08lx\n", hr
);
786 DestroyRingBuffer(data
->Ring
);
788 if(data
->DSCbuffer
!= NULL
)
789 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
790 data
->DSCbuffer
= NULL
;
792 IDirectSoundCapture_Release(data
->DSC
);
796 return ALC_INVALID_VALUE
;
799 data
->BufferBytes
= DSCBDescription
.dwBufferBytes
;
800 SetDefaultWFXChannelOrder(device
);
802 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
803 device
->ExtraData
= data
;
808 static void DSoundCloseCapture(ALCdevice
*device
)
810 DSoundCaptureData
*data
= device
->ExtraData
;
812 DestroyRingBuffer(data
->Ring
);
815 if(data
->DSCbuffer
!= NULL
)
817 IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
818 IDirectSoundCaptureBuffer_Release(data
->DSCbuffer
);
819 data
->DSCbuffer
= NULL
;
822 IDirectSoundCapture_Release(data
->DSC
);
826 device
->ExtraData
= NULL
;
829 static void DSoundStartCapture(ALCdevice
*device
)
831 DSoundCaptureData
*data
= device
->ExtraData
;
834 hr
= IDirectSoundCaptureBuffer_Start(data
->DSCbuffer
, DSCBSTART_LOOPING
);
837 ERR("start failed: 0x%08lx\n", hr
);
838 aluHandleDisconnect(device
);
842 static void DSoundStopCapture(ALCdevice
*device
)
844 DSoundCaptureData
*data
= device
->ExtraData
;
847 hr
= IDirectSoundCaptureBuffer_Stop(data
->DSCbuffer
);
850 ERR("stop failed: 0x%08lx\n", hr
);
851 aluHandleDisconnect(device
);
855 static ALCenum
DSoundCaptureSamples(ALCdevice
*Device
, ALCvoid
*pBuffer
, ALCuint lSamples
)
857 DSoundCaptureData
*data
= Device
->ExtraData
;
858 ReadRingBuffer(data
->Ring
, pBuffer
, lSamples
);
862 static ALCuint
DSoundAvailableSamples(ALCdevice
*Device
)
864 DSoundCaptureData
*data
= Device
->ExtraData
;
865 DWORD ReadCursor
, LastCursor
, BufferBytes
, NumBytes
;
866 VOID
*ReadPtr1
, *ReadPtr2
;
867 DWORD ReadCnt1
, ReadCnt2
;
871 if(!Device
->Connected
)
874 FrameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
875 BufferBytes
= data
->BufferBytes
;
876 LastCursor
= data
->Cursor
;
878 hr
= IDirectSoundCaptureBuffer_GetCurrentPosition(data
->DSCbuffer
, NULL
, &ReadCursor
);
881 NumBytes
= (ReadCursor
-LastCursor
+ BufferBytes
) % BufferBytes
;
884 hr
= IDirectSoundCaptureBuffer_Lock(data
->DSCbuffer
, LastCursor
, NumBytes
,
885 &ReadPtr1
, &ReadCnt1
,
886 &ReadPtr2
, &ReadCnt2
, 0);
890 WriteRingBuffer(data
->Ring
, ReadPtr1
, ReadCnt1
/FrameSize
);
892 WriteRingBuffer(data
->Ring
, ReadPtr2
, ReadCnt2
/FrameSize
);
893 hr
= IDirectSoundCaptureBuffer_Unlock(data
->DSCbuffer
,
896 data
->Cursor
= (LastCursor
+ReadCnt1
+ReadCnt2
) % BufferBytes
;
901 ERR("update failed: 0x%08lx\n", hr
);
902 aluHandleDisconnect(Device
);
906 return RingBufferSize(data
->Ring
);
910 static const BackendFuncs DSoundFuncs
= {
920 DSoundCaptureSamples
,
921 DSoundAvailableSamples
,
922 ALCdevice_GetLatencyDefault
926 ALCboolean
alcDSoundInit(BackendFuncs
*FuncList
)
928 VECTOR_INIT(PlaybackDevices
);
929 VECTOR_INIT(CaptureDevices
);
933 *FuncList
= DSoundFuncs
;
937 void alcDSoundDeinit(void)
941 iter
= VECTOR_ITER_BEGIN(PlaybackDevices
);
942 end
= VECTOR_ITER_END(PlaybackDevices
);
943 for(;iter
!= end
;++iter
)
944 AL_STRING_DEINIT(iter
->name
);
945 VECTOR_DEINIT(PlaybackDevices
);
947 iter
= VECTOR_ITER_BEGIN(CaptureDevices
);
948 end
= VECTOR_ITER_END(CaptureDevices
);
949 for(;iter
!= end
;++iter
)
950 AL_STRING_DEINIT(iter
->name
);
951 VECTOR_DEINIT(CaptureDevices
);
958 void alcDSoundProbe(enum DevProbe type
)
963 /* Initialize COM to prevent name truncation */
964 hrcom
= CoInitialize(NULL
);
967 case ALL_DEVICE_PROBE
:
968 iter
= VECTOR_ITER_BEGIN(PlaybackDevices
);
969 end
= VECTOR_ITER_END(PlaybackDevices
);
970 for(;iter
!= end
;++iter
)
971 AL_STRING_DEINIT(iter
->name
);
972 VECTOR_RESIZE(PlaybackDevices
, 0);
974 hr
= DirectSoundEnumerateW(DSoundEnumDevices
, &PlaybackDevices
);
976 ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr
);
979 iter
= VECTOR_ITER_BEGIN(PlaybackDevices
);
980 end
= VECTOR_ITER_END(PlaybackDevices
);
981 for(;iter
!= end
;++iter
)
982 AppendAllDevicesList(al_string_get_cstr(iter
->name
));
986 case CAPTURE_DEVICE_PROBE
:
987 iter
= VECTOR_ITER_BEGIN(CaptureDevices
);
988 end
= VECTOR_ITER_END(CaptureDevices
);
989 for(;iter
!= end
;++iter
)
990 AL_STRING_DEINIT(iter
->name
);
991 VECTOR_RESIZE(CaptureDevices
, 0);
993 hr
= DirectSoundCaptureEnumerateW(DSoundEnumDevices
, &CaptureDevices
);
995 ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr
);
998 iter
= VECTOR_ITER_BEGIN(CaptureDevices
);
999 end
= VECTOR_ITER_END(CaptureDevices
);
1000 for(;iter
!= end
;++iter
)
1001 AppendCaptureDeviceList(al_string_get_cstr(iter
->name
));
1005 if(SUCCEEDED(hrcom
))