Removed duplicate file in Android.mk file list.
[openal-soft/android.git] / Alc / backends / dsound.c
blob84b7377a8e332fc0b44d2c6cb96e44189d2b6f89
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
27 #include <dsound.h>
28 #include <cguid.h>
29 #include <mmreg.h>
30 #ifndef _WAVEFORMATEXTENSIBLE_
31 #include <ks.h>
32 #include <ksmedia.h>
33 #endif
35 #include "alMain.h"
36 #include "AL/al.h"
37 #include "AL/alc.h"
39 #ifndef DSSPEAKER_5POINT1
40 #define DSSPEAKER_5POINT1 6
41 #endif
42 #ifndef DSSPEAKER_7POINT1
43 #define DSSPEAKER_7POINT1 7
44 #endif
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
62 typedef struct {
63 // DirectSound Playback Device
64 IDirectSound *lpDS;
65 IDirectSoundBuffer *DSpbuffer;
66 IDirectSoundBuffer *DSsbuffer;
67 IDirectSoundNotify *DSnotify;
68 HANDLE hNotifyEvent;
70 volatile int killNow;
71 ALvoid *thread;
72 } DSoundPlaybackData;
74 typedef struct {
75 // DirectSound Capture Device
76 IDirectSoundCapture *lpDSC;
77 IDirectSoundCaptureBuffer *DSCbuffer;
78 DWORD dwBufferBytes;
79 DWORD dwCursor;
80 RingBuffer *pRing;
81 } DSoundCaptureData;
84 typedef struct {
85 ALCchar *name;
86 GUID guid;
87 } DevMap;
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)
99 if(!ds_handle)
101 ds_handle = LoadLib("dsound.dll");
102 if(ds_handle == NULL)
104 ERR("Failed to load dsound.dll\n");
105 return ALC_FALSE;
108 #define LOAD_FUNC(f) do { \
109 p##f = GetSymbol(ds_handle, #f); \
110 if(p##f == NULL) { \
111 CloseLib(ds_handle); \
112 ds_handle = NULL; \
113 return ALC_FALSE; \
115 } while(0)
116 LOAD_FUNC(DirectSoundCreate);
117 LOAD_FUNC(DirectSoundEnumerateA);
118 LOAD_FUNC(DirectSoundCaptureCreate);
119 LOAD_FUNC(DirectSoundCaptureEnumerateA);
120 #undef LOAD_FUNC
122 return ALC_TRUE;
126 static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
128 char str[1024];
129 void *temp;
130 int count;
131 ALuint i;
133 (void)data;
134 (void)drvname;
136 if(!guid)
137 return TRUE;
139 count = 0;
140 do {
141 if(count == 0)
142 snprintf(str, sizeof(str), "%s", desc);
143 else
144 snprintf(str, sizeof(str), "%s #%d", desc, count+1);
145 count++;
147 for(i = 0;i < NumPlaybackDevices;i++)
149 if(strcmp(str, PlaybackDeviceList[i].name) == 0)
150 break;
152 } while(i != NumPlaybackDevices);
154 temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
155 if(temp)
157 PlaybackDeviceList = temp;
158 PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
159 PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
160 NumPlaybackDevices++;
163 return TRUE;
167 static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
169 char str[1024];
170 void *temp;
171 int count;
172 ALuint i;
174 (void)data;
175 (void)drvname;
177 if(!guid)
178 return TRUE;
180 count = 0;
181 do {
182 if(count == 0)
183 snprintf(str, sizeof(str), "%s", desc);
184 else
185 snprintf(str, sizeof(str), "%s #%d", desc, count+1);
186 count++;
188 for(i = 0;i < NumCaptureDevices;i++)
190 if(strcmp(str, CaptureDeviceList[i].name) == 0)
191 break;
193 } while(i != NumCaptureDevices);
195 temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
196 if(temp)
198 CaptureDeviceList = temp;
199 CaptureDeviceList[NumCaptureDevices].name = strdup(str);
200 CaptureDeviceList[NumCaptureDevices].guid = *guid;
201 NumCaptureDevices++;
204 return TRUE;
208 static ALuint DSoundPlaybackProc(ALvoid *ptr)
210 ALCdevice *pDevice = (ALCdevice*)ptr;
211 DSoundPlaybackData *pData = (DSoundPlaybackData*)pDevice->ExtraData;
212 DSBCAPS DSBCaps;
213 DWORD LastCursor = 0;
214 DWORD PlayCursor;
215 VOID *WritePtr1, *WritePtr2;
216 DWORD WriteCnt1, WriteCnt2;
217 BOOL Playing = FALSE;
218 DWORD FrameSize;
219 DWORD FragSize;
220 DWORD avail;
221 HRESULT err;
223 SetRTPriority();
225 memset(&DSBCaps, 0, sizeof(DSBCaps));
226 DSBCaps.dwSize = sizeof(DSBCaps);
227 err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
228 if(FAILED(err))
230 ERR("Failed to get buffer caps: 0x%lx\n", err);
231 aluHandleDisconnect(pDevice);
232 return 1;
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;
245 if(avail < FragSize)
247 if(!Playing)
249 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
250 if(FAILED(err))
252 ERR("Failed to play buffer: 0x%lx\n", err);
253 aluHandleDisconnect(pDevice);
254 return 1;
256 Playing = TRUE;
259 avail = WaitForSingleObjectEx(pData->hNotifyEvent, 2000, FALSE);
260 if(avail != WAIT_OBJECT_0)
261 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
262 continue;
264 avail -= avail%FragSize;
266 // Lock output buffer
267 WriteCnt1 = 0;
268 WriteCnt2 = 0;
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);
276 if(SUCCEEDED(err))
278 Playing = FALSE;
279 LastCursor = 0;
280 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
284 // Successfully locked the output buffer
285 if(SUCCEEDED(err))
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);
294 else
296 ERR("Buffer lock error: %#lx\n", err);
297 aluHandleDisconnect(pDevice);
298 return 1;
301 // Update old write cursor location
302 LastCursor += WriteCnt1+WriteCnt2;
303 LastCursor %= DSBCaps.dwBufferBytes;
306 return 0;
309 static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
311 DSoundPlaybackData *pData = NULL;
312 LPGUID guid = NULL;
313 HRESULT hr;
315 if(!deviceName)
316 deviceName = dsDevice;
317 else if(strcmp(deviceName, dsDevice) != 0)
319 ALuint i;
321 if(!PlaybackDeviceList)
323 hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
324 if(FAILED(hr))
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;
333 break;
336 if(i == NumPlaybackDevices)
337 return ALC_INVALID_VALUE;
340 //Initialise requested device
341 pData = calloc(1, sizeof(DSoundPlaybackData));
342 if(!pData)
343 return ALC_OUT_OF_MEMORY;
345 hr = DS_OK;
346 pData->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
347 if(pData->hNotifyEvent == NULL)
348 hr = E_FAIL;
350 //DirectSound Init code
351 if(SUCCEEDED(hr))
352 hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
353 if(SUCCEEDED(hr))
354 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
355 if(FAILED(hr))
357 if(pData->lpDS)
358 IDirectSound_Release(pData->lpDS);
359 if(pData->hNotifyEvent)
360 CloseHandle(pData->hNotifyEvent);
361 free(pData);
362 ERR("Device init failed: 0x%08lx\n", hr);
363 return ALC_INVALID_VALUE;
366 device->szDeviceName = strdup(deviceName);
367 device->ExtraData = pData;
368 return ALC_NO_ERROR;
371 static void DSoundClosePlayback(ALCdevice *device)
373 DSoundPlaybackData *pData = device->ExtraData;
375 IDirectSound_Release(pData->lpDS);
376 CloseHandle(pData->hNotifyEvent);
377 free(pData);
378 device->ExtraData = NULL;
381 static ALCboolean DSoundResetPlayback(ALCdevice *device)
383 DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
384 DSBUFFERDESC DSBDescription;
385 WAVEFORMATEXTENSIBLE OutputType;
386 DWORD speakers;
387 HRESULT hr;
389 memset(&OutputType, 0, sizeof(OutputType));
391 switch(device->FmtType)
393 case DevFmtByte:
394 device->FmtType = DevFmtUByte;
395 break;
396 case DevFmtUShort:
397 device->FmtType = DevFmtShort;
398 break;
399 case DevFmtUByte:
400 case DevFmtShort:
401 case DevFmtFloat:
402 break;
405 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
406 if(SUCCEEDED(hr))
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;
421 else
422 ERR("Unknown system speaker config: 0x%lx\n", speakers);
425 switch(device->FmtChans)
427 case DevFmtMono:
428 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
429 break;
430 case DevFmtStereo:
431 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
432 SPEAKER_FRONT_RIGHT;
433 break;
434 case DevFmtQuad:
435 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
436 SPEAKER_FRONT_RIGHT |
437 SPEAKER_BACK_LEFT |
438 SPEAKER_BACK_RIGHT;
439 break;
440 case DevFmtX51:
441 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
442 SPEAKER_FRONT_RIGHT |
443 SPEAKER_FRONT_CENTER |
444 SPEAKER_LOW_FREQUENCY |
445 SPEAKER_BACK_LEFT |
446 SPEAKER_BACK_RIGHT;
447 break;
448 case DevFmtX51Side:
449 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
450 SPEAKER_FRONT_RIGHT |
451 SPEAKER_FRONT_CENTER |
452 SPEAKER_LOW_FREQUENCY |
453 SPEAKER_SIDE_LEFT |
454 SPEAKER_SIDE_RIGHT;
455 break;
456 case DevFmtX61:
457 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
458 SPEAKER_FRONT_RIGHT |
459 SPEAKER_FRONT_CENTER |
460 SPEAKER_LOW_FREQUENCY |
461 SPEAKER_BACK_CENTER |
462 SPEAKER_SIDE_LEFT |
463 SPEAKER_SIDE_RIGHT;
464 break;
465 case DevFmtX71:
466 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
467 SPEAKER_FRONT_RIGHT |
468 SPEAKER_FRONT_CENTER |
469 SPEAKER_LOW_FREQUENCY |
470 SPEAKER_BACK_LEFT |
471 SPEAKER_BACK_RIGHT |
472 SPEAKER_SIDE_LEFT |
473 SPEAKER_SIDE_RIGHT;
474 break;
477 retry_open:
478 hr = S_OK;
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;
495 else
496 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
498 if(pData->DSpbuffer)
499 IDirectSoundBuffer_Release(pData->DSpbuffer);
500 pData->DSpbuffer = NULL;
502 else
504 if(SUCCEEDED(hr))
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);
511 if(SUCCEEDED(hr))
512 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
515 if(SUCCEEDED(hr))
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;
534 goto retry_open;
538 if(SUCCEEDED(hr))
540 hr = IDirectSoundBuffer_QueryInterface(pData->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&pData->DSnotify);
541 if(SUCCEEDED(hr))
543 DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
544 ALuint i;
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)
553 hr = E_FAIL;
557 if(SUCCEEDED(hr))
559 ResetEvent(pData->hNotifyEvent);
560 SetDefaultWFXChannelOrder(device);
561 pData->thread = StartThread(DSoundPlaybackProc, device);
562 if(pData->thread == NULL)
563 hr = E_FAIL;
566 if(FAILED(hr))
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;
577 return ALC_FALSE;
580 return ALC_TRUE;
583 static void DSoundStopPlayback(ALCdevice *device)
585 DSoundPlaybackData *pData = device->ExtraData;
587 if(!pData->thread)
588 return;
590 pData->killNow = 1;
591 StopThread(pData->thread);
592 pData->thread = NULL;
594 pData->killNow = 0;
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;
611 LPGUID guid = NULL;
612 HRESULT hr, hrcom;
613 ALuint samples;
615 if(!CaptureDeviceList)
617 /* Initialize COM to prevent name truncation */
618 hrcom = CoInitialize(NULL);
619 hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
620 if(FAILED(hr))
621 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
622 if(SUCCEEDED(hrcom))
623 CoUninitialize();
626 if(!deviceName && NumCaptureDevices > 0)
628 deviceName = CaptureDeviceList[0].name;
629 guid = &CaptureDeviceList[0].guid;
631 else
633 ALuint i;
635 for(i = 0;i < NumCaptureDevices;i++)
637 if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
639 guid = &CaptureDeviceList[i].guid;
640 break;
643 if(i == NumCaptureDevices)
644 return ALC_INVALID_VALUE;
647 //Initialise requested device
648 pData = calloc(1, sizeof(DSoundCaptureData));
649 if(!pData)
650 return ALC_OUT_OF_MEMORY;
652 hr = DS_OK;
654 //DirectSoundCapture Init code
655 if(SUCCEEDED(hr))
656 hr = DirectSoundCaptureCreate(guid, &pData->lpDSC, NULL);
657 if(SUCCEEDED(hr))
659 memset(&InputType, 0, sizeof(InputType));
661 switch(device->FmtChans)
663 case DevFmtMono:
664 InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
665 break;
666 case DevFmtStereo:
667 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
668 SPEAKER_FRONT_RIGHT;
669 break;
670 case DevFmtQuad:
671 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
672 SPEAKER_FRONT_RIGHT |
673 SPEAKER_BACK_LEFT |
674 SPEAKER_BACK_RIGHT;
675 break;
676 case DevFmtX51:
677 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
678 SPEAKER_FRONT_RIGHT |
679 SPEAKER_FRONT_CENTER |
680 SPEAKER_LOW_FREQUENCY |
681 SPEAKER_BACK_LEFT |
682 SPEAKER_BACK_RIGHT;
683 break;
684 case DevFmtX51Side:
685 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
686 SPEAKER_FRONT_RIGHT |
687 SPEAKER_FRONT_CENTER |
688 SPEAKER_LOW_FREQUENCY |
689 SPEAKER_SIDE_LEFT |
690 SPEAKER_SIDE_RIGHT;
691 break;
692 case DevFmtX61:
693 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
694 SPEAKER_FRONT_RIGHT |
695 SPEAKER_FRONT_CENTER |
696 SPEAKER_LOW_FREQUENCY |
697 SPEAKER_BACK_CENTER |
698 SPEAKER_SIDE_LEFT |
699 SPEAKER_SIDE_RIGHT;
700 break;
701 case DevFmtX71:
702 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
703 SPEAKER_FRONT_RIGHT |
704 SPEAKER_FRONT_CENTER |
705 SPEAKER_LOW_FREQUENCY |
706 SPEAKER_BACK_LEFT |
707 SPEAKER_BACK_RIGHT |
708 SPEAKER_SIDE_LEFT |
709 SPEAKER_SIDE_RIGHT;
710 break;
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;
728 else
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);
743 if(SUCCEEDED(hr))
745 pData->pRing = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
746 if(pData->pRing == NULL)
747 hr = DSERR_OUTOFMEMORY;
750 if(FAILED(hr))
752 ERR("Device init failed: 0x%08lx\n", hr);
754 DestroyRingBuffer(pData->pRing);
755 pData->pRing = NULL;
756 if(pData->DSCbuffer != NULL)
757 IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
758 pData->DSCbuffer = NULL;
759 if(pData->lpDSC)
760 IDirectSoundCapture_Release(pData->lpDSC);
761 pData->lpDSC = NULL;
763 free(pData);
764 return ALC_INVALID_VALUE;
767 pData->dwBufferBytes = DSCBDescription.dwBufferBytes;
768 SetDefaultWFXChannelOrder(device);
770 device->szDeviceName = strdup(deviceName);
771 device->ExtraData = pData;
773 return ALC_NO_ERROR;
776 static void DSoundCloseCapture(ALCdevice *device)
778 DSoundCaptureData *pData = device->ExtraData;
780 DestroyRingBuffer(pData->pRing);
781 pData->pRing = NULL;
783 if(pData->DSCbuffer != NULL)
785 IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
786 IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
787 pData->DSCbuffer = NULL;
790 IDirectSoundCapture_Release(pData->lpDSC);
791 pData->lpDSC = NULL;
793 free(pData);
794 device->ExtraData = NULL;
797 static void DSoundStartCapture(ALCdevice *device)
799 DSoundCaptureData *pData = device->ExtraData;
800 HRESULT hr;
802 hr = IDirectSoundCaptureBuffer_Start(pData->DSCbuffer, DSCBSTART_LOOPING);
803 if(FAILED(hr))
805 ERR("start failed: 0x%08lx\n", hr);
806 aluHandleDisconnect(device);
810 static void DSoundStopCapture(ALCdevice *device)
812 DSoundCaptureData *pData = device->ExtraData;
813 HRESULT hr;
815 hr = IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
816 if(FAILED(hr))
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);
827 return ALC_NO_ERROR;
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;
836 DWORD FrameSize;
837 HRESULT hr;
839 if(!pDevice->Connected)
840 goto done;
842 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
843 dwBufferBytes = pData->dwBufferBytes;
844 dwCursor = pData->dwCursor;
846 hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead);
847 if(SUCCEEDED(hr))
849 dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes;
850 if(dwNumBytes == 0)
851 goto done;
852 hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer,
853 dwCursor, dwNumBytes,
854 &pvAudio1, &dwAudioBytes1,
855 &pvAudio2, &dwAudioBytes2, 0);
857 if(SUCCEEDED(hr))
859 WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize);
860 if(pvAudio2 != NULL)
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;
868 if(FAILED(hr))
870 ERR("update failed: 0x%08lx\n", hr);
871 aluHandleDisconnect(pDevice);
874 done:
875 return RingBufferSize(pData->pRing);
878 static const BackendFuncs DSoundFuncs = {
879 DSoundOpenPlayback,
880 DSoundClosePlayback,
881 DSoundResetPlayback,
882 DSoundStopPlayback,
883 DSoundOpenCapture,
884 DSoundCloseCapture,
885 DSoundStartCapture,
886 DSoundStopCapture,
887 DSoundCaptureSamples,
888 DSoundAvailableSamples
892 ALCboolean alcDSoundInit(BackendFuncs *FuncList)
894 if(!DSoundLoad())
895 return ALC_FALSE;
896 *FuncList = DSoundFuncs;
897 return ALC_TRUE;
900 void alcDSoundDeinit(void)
902 ALuint i;
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;
916 if(ds_handle)
917 CloseLib(ds_handle);
918 ds_handle = NULL;
921 void alcDSoundProbe(enum DevProbe type)
923 HRESULT hr, hrcom;
924 ALuint i;
926 switch(type)
928 case DEVICE_PROBE:
929 AppendDeviceList(dsDevice);
930 break;
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);
940 if(FAILED(hr))
941 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
942 else
944 for(i = 0;i < NumPlaybackDevices;i++)
945 AppendAllDeviceList(PlaybackDeviceList[i].name);
947 break;
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);
959 if(FAILED(hr))
960 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
961 else
963 for(i = 0;i < NumCaptureDevices;i++)
964 AppendCaptureDeviceList(CaptureDeviceList[i].name);
966 if(SUCCEEDED(hrcom))
967 CoUninitialize();
968 break;