Remove hungarian notation from dsound and mmdevapi
[openal-soft/openal-hmr.git] / Alc / backends / dsound.c
blob23d91b6914510c61c9d3852d155dc555f1846395
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 *DS;
65 IDirectSoundBuffer *DSpbuffer;
66 IDirectSoundBuffer *DSsbuffer;
67 IDirectSoundNotify *DSnotify;
68 HANDLE NotifyEvent;
70 volatile int killNow;
71 ALvoid *thread;
72 } DSoundPlaybackData;
74 typedef struct {
75 // DirectSound Capture Device
76 IDirectSoundCapture *DSC;
77 IDirectSoundCaptureBuffer *DSCbuffer;
78 DWORD BufferBytes;
79 DWORD Cursor;
80 RingBuffer *Ring;
81 } DSoundCaptureData;
84 typedef struct {
85 ALCchar *name;
86 GUID guid;
87 } DevMap;
89 static DevMap *PlaybackDeviceList;
90 static ALuint NumPlaybackDevices;
91 static DevMap *CaptureDeviceList;
92 static ALuint NumCaptureDevices;
94 #define MAX_UPDATES 128
96 static ALCboolean DSoundLoad(void)
98 if(!ds_handle)
100 ds_handle = LoadLib("dsound.dll");
101 if(ds_handle == NULL)
103 ERR("Failed to load dsound.dll\n");
104 return ALC_FALSE;
107 #define LOAD_FUNC(f) do { \
108 p##f = GetSymbol(ds_handle, #f); \
109 if(p##f == NULL) { \
110 CloseLib(ds_handle); \
111 ds_handle = NULL; \
112 return ALC_FALSE; \
114 } while(0)
115 LOAD_FUNC(DirectSoundCreate);
116 LOAD_FUNC(DirectSoundEnumerateA);
117 LOAD_FUNC(DirectSoundCaptureCreate);
118 LOAD_FUNC(DirectSoundCaptureEnumerateA);
119 #undef LOAD_FUNC
121 return ALC_TRUE;
125 static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
127 LPOLESTR guidstr = NULL;
128 char str[1024];
129 HRESULT hr;
130 void *temp;
131 int count;
132 ALuint i;
134 (void)data;
135 (void)drvname;
137 if(!guid)
138 return TRUE;
140 count = 0;
141 do {
142 if(count == 0)
143 snprintf(str, sizeof(str), "%s", desc);
144 else
145 snprintf(str, sizeof(str), "%s #%d", desc, count+1);
146 count++;
148 for(i = 0;i < NumPlaybackDevices;i++)
150 if(strcmp(str, PlaybackDeviceList[i].name) == 0)
151 break;
153 } while(i != NumPlaybackDevices);
155 hr = StringFromCLSID(guid, &guidstr);
156 if(SUCCEEDED(hr))
158 TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
159 CoTaskMemFree(guidstr);
162 temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
163 if(temp)
165 PlaybackDeviceList = temp;
166 PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
167 PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
168 NumPlaybackDevices++;
171 return TRUE;
175 static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
177 LPOLESTR guidstr = NULL;
178 char str[1024];
179 HRESULT hr;
180 void *temp;
181 int count;
182 ALuint i;
184 (void)data;
185 (void)drvname;
187 if(!guid)
188 return TRUE;
190 count = 0;
191 do {
192 if(count == 0)
193 snprintf(str, sizeof(str), "%s", desc);
194 else
195 snprintf(str, sizeof(str), "%s #%d", desc, count+1);
196 count++;
198 for(i = 0;i < NumCaptureDevices;i++)
200 if(strcmp(str, CaptureDeviceList[i].name) == 0)
201 break;
203 } while(i != NumCaptureDevices);
205 hr = StringFromCLSID(guid, &guidstr);
206 if(SUCCEEDED(hr))
208 TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
209 CoTaskMemFree(guidstr);
212 temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
213 if(temp)
215 CaptureDeviceList = temp;
216 CaptureDeviceList[NumCaptureDevices].name = strdup(str);
217 CaptureDeviceList[NumCaptureDevices].guid = *guid;
218 NumCaptureDevices++;
221 return TRUE;
225 static ALuint DSoundPlaybackProc(ALvoid *ptr)
227 ALCdevice *Device = (ALCdevice*)ptr;
228 DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
229 DSBCAPS DSBCaps;
230 DWORD LastCursor = 0;
231 DWORD PlayCursor;
232 VOID *WritePtr1, *WritePtr2;
233 DWORD WriteCnt1, WriteCnt2;
234 BOOL Playing = FALSE;
235 DWORD FrameSize;
236 DWORD FragSize;
237 DWORD avail;
238 HRESULT err;
240 SetRTPriority();
242 memset(&DSBCaps, 0, sizeof(DSBCaps));
243 DSBCaps.dwSize = sizeof(DSBCaps);
244 err = IDirectSoundBuffer_GetCaps(data->DSsbuffer, &DSBCaps);
245 if(FAILED(err))
247 ERR("Failed to get buffer caps: 0x%lx\n", err);
248 aluHandleDisconnect(Device);
249 return 1;
252 FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
253 FragSize = Device->UpdateSize * FrameSize;
255 IDirectSoundBuffer_GetCurrentPosition(data->DSsbuffer, &LastCursor, NULL);
256 while(!data->killNow)
258 // Get current play cursor
259 IDirectSoundBuffer_GetCurrentPosition(data->DSsbuffer, &PlayCursor, NULL);
260 avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
262 if(avail < FragSize)
264 if(!Playing)
266 err = IDirectSoundBuffer_Play(data->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
267 if(FAILED(err))
269 ERR("Failed to play buffer: 0x%lx\n", err);
270 aluHandleDisconnect(Device);
271 return 1;
273 Playing = TRUE;
276 avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
277 if(avail != WAIT_OBJECT_0)
278 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
279 continue;
281 avail -= avail%FragSize;
283 // Lock output buffer
284 WriteCnt1 = 0;
285 WriteCnt2 = 0;
286 err = IDirectSoundBuffer_Lock(data->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
288 // If the buffer is lost, restore it and lock
289 if(err == DSERR_BUFFERLOST)
291 WARN("Buffer lost, restoring...\n");
292 err = IDirectSoundBuffer_Restore(data->DSsbuffer);
293 if(SUCCEEDED(err))
295 Playing = FALSE;
296 LastCursor = 0;
297 err = IDirectSoundBuffer_Lock(data->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
301 // Successfully locked the output buffer
302 if(SUCCEEDED(err))
304 // If we have an active context, mix data directly into output buffer otherwise fill with silence
305 aluMixData(Device, WritePtr1, WriteCnt1/FrameSize);
306 aluMixData(Device, WritePtr2, WriteCnt2/FrameSize);
308 // Unlock output buffer only when successfully locked
309 IDirectSoundBuffer_Unlock(data->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
311 else
313 ERR("Buffer lock error: %#lx\n", err);
314 aluHandleDisconnect(Device);
315 return 1;
318 // Update old write cursor location
319 LastCursor += WriteCnt1+WriteCnt2;
320 LastCursor %= DSBCaps.dwBufferBytes;
323 return 0;
326 static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
328 DSoundPlaybackData *data = NULL;
329 LPGUID guid = NULL;
330 HRESULT hr;
332 if(!PlaybackDeviceList)
334 hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
335 if(FAILED(hr))
336 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
339 if(!deviceName && NumPlaybackDevices > 0)
341 deviceName = PlaybackDeviceList[0].name;
342 guid = &PlaybackDeviceList[0].guid;
344 else
346 ALuint i;
348 for(i = 0;i < NumPlaybackDevices;i++)
350 if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
352 guid = &PlaybackDeviceList[i].guid;
353 break;
356 if(i == NumPlaybackDevices)
357 return ALC_INVALID_VALUE;
360 //Initialise requested device
361 data = calloc(1, sizeof(DSoundPlaybackData));
362 if(!data)
363 return ALC_OUT_OF_MEMORY;
365 hr = DS_OK;
366 data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
367 if(data->NotifyEvent == NULL)
368 hr = E_FAIL;
370 //DirectSound Init code
371 if(SUCCEEDED(hr))
372 hr = DirectSoundCreate(guid, &data->DS, NULL);
373 if(SUCCEEDED(hr))
374 hr = IDirectSound_SetCooperativeLevel(data->DS, GetForegroundWindow(), DSSCL_PRIORITY);
375 if(FAILED(hr))
377 if(data->DS)
378 IDirectSound_Release(data->DS);
379 if(data->NotifyEvent)
380 CloseHandle(data->NotifyEvent);
381 free(data);
382 ERR("Device init failed: 0x%08lx\n", hr);
383 return ALC_INVALID_VALUE;
386 device->DeviceName = strdup(deviceName);
387 device->ExtraData = data;
388 return ALC_NO_ERROR;
391 static void DSoundClosePlayback(ALCdevice *device)
393 DSoundPlaybackData *data = device->ExtraData;
395 if(data->DSnotify)
396 IDirectSoundNotify_Release(data->DSnotify);
397 data->DSnotify = NULL;
398 if(data->DSsbuffer)
399 IDirectSoundBuffer_Release(data->DSsbuffer);
400 data->DSsbuffer = NULL;
401 if(data->DSpbuffer != NULL)
402 IDirectSoundBuffer_Release(data->DSpbuffer);
403 data->DSpbuffer = NULL;
405 IDirectSound_Release(data->DS);
406 CloseHandle(data->NotifyEvent);
407 free(data);
408 device->ExtraData = NULL;
411 static ALCboolean DSoundResetPlayback(ALCdevice *device)
413 DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
414 DSBUFFERDESC DSBDescription;
415 WAVEFORMATEXTENSIBLE OutputType;
416 DWORD speakers;
417 HRESULT hr;
419 memset(&OutputType, 0, sizeof(OutputType));
421 if(data->DSnotify)
422 IDirectSoundNotify_Release(data->DSnotify);
423 data->DSnotify = NULL;
424 if(data->DSsbuffer)
425 IDirectSoundBuffer_Release(data->DSsbuffer);
426 data->DSsbuffer = NULL;
427 if(data->DSpbuffer != NULL)
428 IDirectSoundBuffer_Release(data->DSpbuffer);
429 data->DSpbuffer = NULL;
431 switch(device->FmtType)
433 case DevFmtByte:
434 device->FmtType = DevFmtUByte;
435 break;
436 case DevFmtUShort:
437 device->FmtType = DevFmtShort;
438 break;
439 case DevFmtUInt:
440 device->FmtType = DevFmtInt;
441 break;
442 case DevFmtUByte:
443 case DevFmtShort:
444 case DevFmtInt:
445 case DevFmtFloat:
446 break;
449 hr = IDirectSound_GetSpeakerConfig(data->DS, &speakers);
450 if(SUCCEEDED(hr))
452 if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
454 speakers = DSSPEAKER_CONFIG(speakers);
455 if(speakers == DSSPEAKER_MONO)
456 device->FmtChans = DevFmtMono;
457 else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
458 device->FmtChans = DevFmtStereo;
459 else if(speakers == DSSPEAKER_QUAD)
460 device->FmtChans = DevFmtQuad;
461 else if(speakers == DSSPEAKER_5POINT1)
462 device->FmtChans = DevFmtX51;
463 else if(speakers == DSSPEAKER_7POINT1)
464 device->FmtChans = DevFmtX71;
465 else
466 ERR("Unknown system speaker config: 0x%lx\n", speakers);
469 switch(device->FmtChans)
471 case DevFmtMono:
472 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
473 break;
474 case DevFmtStereo:
475 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
476 SPEAKER_FRONT_RIGHT;
477 break;
478 case DevFmtQuad:
479 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
480 SPEAKER_FRONT_RIGHT |
481 SPEAKER_BACK_LEFT |
482 SPEAKER_BACK_RIGHT;
483 break;
484 case DevFmtX51:
485 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
486 SPEAKER_FRONT_RIGHT |
487 SPEAKER_FRONT_CENTER |
488 SPEAKER_LOW_FREQUENCY |
489 SPEAKER_BACK_LEFT |
490 SPEAKER_BACK_RIGHT;
491 break;
492 case DevFmtX51Side:
493 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
494 SPEAKER_FRONT_RIGHT |
495 SPEAKER_FRONT_CENTER |
496 SPEAKER_LOW_FREQUENCY |
497 SPEAKER_SIDE_LEFT |
498 SPEAKER_SIDE_RIGHT;
499 break;
500 case DevFmtX61:
501 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
502 SPEAKER_FRONT_RIGHT |
503 SPEAKER_FRONT_CENTER |
504 SPEAKER_LOW_FREQUENCY |
505 SPEAKER_BACK_CENTER |
506 SPEAKER_SIDE_LEFT |
507 SPEAKER_SIDE_RIGHT;
508 break;
509 case DevFmtX71:
510 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
511 SPEAKER_FRONT_RIGHT |
512 SPEAKER_FRONT_CENTER |
513 SPEAKER_LOW_FREQUENCY |
514 SPEAKER_BACK_LEFT |
515 SPEAKER_BACK_RIGHT |
516 SPEAKER_SIDE_LEFT |
517 SPEAKER_SIDE_RIGHT;
518 break;
521 retry_open:
522 hr = S_OK;
523 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
524 OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
525 OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
526 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
527 OutputType.Format.nSamplesPerSec = device->Frequency;
528 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
529 OutputType.Format.cbSize = 0;
532 if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
534 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
535 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
536 OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
537 if(device->FmtType == DevFmtFloat)
538 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
539 else
540 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
542 if(data->DSpbuffer)
543 IDirectSoundBuffer_Release(data->DSpbuffer);
544 data->DSpbuffer = NULL;
546 else
548 if(SUCCEEDED(hr))
550 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
551 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
552 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
553 hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->DSpbuffer, NULL);
555 if(SUCCEEDED(hr))
556 hr = IDirectSoundBuffer_SetFormat(data->DSpbuffer,&OutputType.Format);
559 if(SUCCEEDED(hr))
561 if(device->NumUpdates > MAX_UPDATES)
563 device->UpdateSize = (device->UpdateSize*device->NumUpdates +
564 MAX_UPDATES-1) / MAX_UPDATES;
565 device->NumUpdates = MAX_UPDATES;
568 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
569 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
570 DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
571 DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
572 OutputType.Format.nBlockAlign;
573 DSBDescription.lpwfxFormat=&OutputType.Format;
574 hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->DSsbuffer, NULL);
575 if(FAILED(hr) && device->FmtType == DevFmtFloat)
577 device->FmtType = DevFmtShort;
578 goto retry_open;
582 if(SUCCEEDED(hr))
584 hr = IDirectSoundBuffer_QueryInterface(data->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&data->DSnotify);
585 if(SUCCEEDED(hr))
587 DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
588 ALuint i;
590 for(i = 0;i < device->NumUpdates;++i)
592 notifies[i].dwOffset = i * device->UpdateSize *
593 OutputType.Format.nBlockAlign;
594 notifies[i].hEventNotify = data->NotifyEvent;
596 if(IDirectSoundNotify_SetNotificationPositions(data->DSnotify, device->NumUpdates, notifies) != DS_OK)
597 hr = E_FAIL;
601 if(FAILED(hr))
603 if(data->DSnotify != NULL)
604 IDirectSoundNotify_Release(data->DSnotify);
605 data->DSnotify = NULL;
606 if(data->DSsbuffer != NULL)
607 IDirectSoundBuffer_Release(data->DSsbuffer);
608 data->DSsbuffer = NULL;
609 if(data->DSpbuffer != NULL)
610 IDirectSoundBuffer_Release(data->DSpbuffer);
611 data->DSpbuffer = NULL;
612 return ALC_FALSE;
615 ResetEvent(data->NotifyEvent);
616 SetDefaultWFXChannelOrder(device);
618 return ALC_TRUE;
621 static ALCboolean DSoundStartPlayback(ALCdevice *device)
623 DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
625 data->thread = StartThread(DSoundPlaybackProc, device);
626 if(data->thread == NULL)
627 return ALC_FALSE;
629 return ALC_TRUE;
632 static void DSoundStopPlayback(ALCdevice *device)
634 DSoundPlaybackData *data = device->ExtraData;
636 if(!data->thread)
637 return;
639 data->killNow = 1;
640 StopThread(data->thread);
641 data->thread = NULL;
643 data->killNow = 0;
644 IDirectSoundBuffer_Stop(data->DSsbuffer);
648 static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
650 DSoundCaptureData *data = NULL;
651 WAVEFORMATEXTENSIBLE InputType;
652 DSCBUFFERDESC DSCBDescription;
653 LPGUID guid = NULL;
654 HRESULT hr, hrcom;
655 ALuint samples;
657 if(!CaptureDeviceList)
659 /* Initialize COM to prevent name truncation */
660 hrcom = CoInitialize(NULL);
661 hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
662 if(FAILED(hr))
663 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
664 if(SUCCEEDED(hrcom))
665 CoUninitialize();
668 if(!deviceName && NumCaptureDevices > 0)
670 deviceName = CaptureDeviceList[0].name;
671 guid = &CaptureDeviceList[0].guid;
673 else
675 ALuint i;
677 for(i = 0;i < NumCaptureDevices;i++)
679 if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
681 guid = &CaptureDeviceList[i].guid;
682 break;
685 if(i == NumCaptureDevices)
686 return ALC_INVALID_VALUE;
689 switch(device->FmtType)
691 case DevFmtByte:
692 case DevFmtUShort:
693 case DevFmtUInt:
694 WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
695 return ALC_INVALID_ENUM;
697 case DevFmtUByte:
698 case DevFmtShort:
699 case DevFmtInt:
700 case DevFmtFloat:
701 break;
704 //Initialise requested device
705 data = calloc(1, sizeof(DSoundCaptureData));
706 if(!data)
707 return ALC_OUT_OF_MEMORY;
709 hr = DS_OK;
711 //DirectSoundCapture Init code
712 if(SUCCEEDED(hr))
713 hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL);
714 if(SUCCEEDED(hr))
716 memset(&InputType, 0, sizeof(InputType));
718 switch(device->FmtChans)
720 case DevFmtMono:
721 InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
722 break;
723 case DevFmtStereo:
724 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
725 SPEAKER_FRONT_RIGHT;
726 break;
727 case DevFmtQuad:
728 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
729 SPEAKER_FRONT_RIGHT |
730 SPEAKER_BACK_LEFT |
731 SPEAKER_BACK_RIGHT;
732 break;
733 case DevFmtX51:
734 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
735 SPEAKER_FRONT_RIGHT |
736 SPEAKER_FRONT_CENTER |
737 SPEAKER_LOW_FREQUENCY |
738 SPEAKER_BACK_LEFT |
739 SPEAKER_BACK_RIGHT;
740 break;
741 case DevFmtX51Side:
742 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
743 SPEAKER_FRONT_RIGHT |
744 SPEAKER_FRONT_CENTER |
745 SPEAKER_LOW_FREQUENCY |
746 SPEAKER_SIDE_LEFT |
747 SPEAKER_SIDE_RIGHT;
748 break;
749 case DevFmtX61:
750 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
751 SPEAKER_FRONT_RIGHT |
752 SPEAKER_FRONT_CENTER |
753 SPEAKER_LOW_FREQUENCY |
754 SPEAKER_BACK_CENTER |
755 SPEAKER_SIDE_LEFT |
756 SPEAKER_SIDE_RIGHT;
757 break;
758 case DevFmtX71:
759 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
760 SPEAKER_FRONT_RIGHT |
761 SPEAKER_FRONT_CENTER |
762 SPEAKER_LOW_FREQUENCY |
763 SPEAKER_BACK_LEFT |
764 SPEAKER_BACK_RIGHT |
765 SPEAKER_SIDE_LEFT |
766 SPEAKER_SIDE_RIGHT;
767 break;
770 InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
771 InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
772 InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
773 InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
774 InputType.Format.nSamplesPerSec = device->Frequency;
775 InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
776 InputType.Format.cbSize = 0;
778 if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
780 InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
781 InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
782 InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
783 if(device->FmtType == DevFmtFloat)
784 InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
785 else
786 InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
789 samples = device->UpdateSize * device->NumUpdates;
790 samples = maxu(samples, 100 * device->Frequency / 1000);
792 memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
793 DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
794 DSCBDescription.dwFlags = 0;
795 DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
796 DSCBDescription.lpwfxFormat = &InputType.Format;
798 hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL);
800 if(SUCCEEDED(hr))
802 data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
803 if(data->Ring == NULL)
804 hr = DSERR_OUTOFMEMORY;
807 if(FAILED(hr))
809 ERR("Device init failed: 0x%08lx\n", hr);
811 DestroyRingBuffer(data->Ring);
812 data->Ring = NULL;
813 if(data->DSCbuffer != NULL)
814 IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
815 data->DSCbuffer = NULL;
816 if(data->DSC)
817 IDirectSoundCapture_Release(data->DSC);
818 data->DSC = NULL;
820 free(data);
821 return ALC_INVALID_VALUE;
824 data->BufferBytes = DSCBDescription.dwBufferBytes;
825 SetDefaultWFXChannelOrder(device);
827 device->DeviceName = strdup(deviceName);
828 device->ExtraData = data;
830 return ALC_NO_ERROR;
833 static void DSoundCloseCapture(ALCdevice *device)
835 DSoundCaptureData *data = device->ExtraData;
837 DestroyRingBuffer(data->Ring);
838 data->Ring = NULL;
840 if(data->DSCbuffer != NULL)
842 IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
843 IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
844 data->DSCbuffer = NULL;
847 IDirectSoundCapture_Release(data->DSC);
848 data->DSC = NULL;
850 free(data);
851 device->ExtraData = NULL;
854 static void DSoundStartCapture(ALCdevice *device)
856 DSoundCaptureData *data = device->ExtraData;
857 HRESULT hr;
859 hr = IDirectSoundCaptureBuffer_Start(data->DSCbuffer, DSCBSTART_LOOPING);
860 if(FAILED(hr))
862 ERR("start failed: 0x%08lx\n", hr);
863 aluHandleDisconnect(device);
867 static void DSoundStopCapture(ALCdevice *device)
869 DSoundCaptureData *data = device->ExtraData;
870 HRESULT hr;
872 hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
873 if(FAILED(hr))
875 ERR("stop failed: 0x%08lx\n", hr);
876 aluHandleDisconnect(device);
880 static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
882 DSoundCaptureData *data = Device->ExtraData;
883 ReadRingBuffer(data->Ring, pBuffer, lSamples);
884 return ALC_NO_ERROR;
887 static ALCuint DSoundAvailableSamples(ALCdevice *Device)
889 DSoundCaptureData *data = Device->ExtraData;
890 DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
891 VOID *ReadPtr1, *ReadPtr2;
892 DWORD ReadCnt1, ReadCnt2;
893 DWORD FrameSize;
894 HRESULT hr;
896 if(!Device->Connected)
897 goto done;
899 FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
900 BufferBytes = data->BufferBytes;
901 LastCursor = data->Cursor;
903 hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor);
904 if(SUCCEEDED(hr))
906 NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
907 if(NumBytes == 0)
908 goto done;
909 hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes,
910 &ReadPtr1, &ReadCnt1,
911 &ReadPtr2, &ReadCnt2, 0);
913 if(SUCCEEDED(hr))
915 WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize);
916 if(ReadPtr2 != NULL)
917 WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize);
918 hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer,
919 ReadPtr1, ReadCnt1,
920 ReadPtr2, ReadCnt2);
921 data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
924 if(FAILED(hr))
926 ERR("update failed: 0x%08lx\n", hr);
927 aluHandleDisconnect(Device);
930 done:
931 return RingBufferSize(data->Ring);
934 static const BackendFuncs DSoundFuncs = {
935 DSoundOpenPlayback,
936 DSoundClosePlayback,
937 DSoundResetPlayback,
938 DSoundStartPlayback,
939 DSoundStopPlayback,
940 DSoundOpenCapture,
941 DSoundCloseCapture,
942 DSoundStartCapture,
943 DSoundStopCapture,
944 DSoundCaptureSamples,
945 DSoundAvailableSamples
949 ALCboolean alcDSoundInit(BackendFuncs *FuncList)
951 if(!DSoundLoad())
952 return ALC_FALSE;
953 *FuncList = DSoundFuncs;
954 return ALC_TRUE;
957 void alcDSoundDeinit(void)
959 ALuint i;
961 for(i = 0;i < NumPlaybackDevices;++i)
962 free(PlaybackDeviceList[i].name);
963 free(PlaybackDeviceList);
964 PlaybackDeviceList = NULL;
965 NumPlaybackDevices = 0;
967 for(i = 0;i < NumCaptureDevices;++i)
968 free(CaptureDeviceList[i].name);
969 free(CaptureDeviceList);
970 CaptureDeviceList = NULL;
971 NumCaptureDevices = 0;
973 if(ds_handle)
974 CloseLib(ds_handle);
975 ds_handle = NULL;
978 void alcDSoundProbe(enum DevProbe type)
980 HRESULT hr, hrcom;
981 ALuint i;
983 switch(type)
985 case ALL_DEVICE_PROBE:
986 for(i = 0;i < NumPlaybackDevices;++i)
987 free(PlaybackDeviceList[i].name);
988 free(PlaybackDeviceList);
989 PlaybackDeviceList = NULL;
990 NumPlaybackDevices = 0;
992 hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
993 if(FAILED(hr))
994 ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
995 else
997 for(i = 0;i < NumPlaybackDevices;i++)
998 AppendAllDeviceList(PlaybackDeviceList[i].name);
1000 break;
1002 case CAPTURE_DEVICE_PROBE:
1003 for(i = 0;i < NumCaptureDevices;++i)
1004 free(CaptureDeviceList[i].name);
1005 free(CaptureDeviceList);
1006 CaptureDeviceList = NULL;
1007 NumCaptureDevices = 0;
1009 /* Initialize COM to prevent name truncation */
1010 hrcom = CoInitialize(NULL);
1011 hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
1012 if(FAILED(hr))
1013 ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
1014 else
1016 for(i = 0;i < NumCaptureDevices;i++)
1017 AppendCaptureDeviceList(CaptureDeviceList[i].name);
1019 if(SUCCEEDED(hrcom))
1020 CoUninitialize();
1021 break;