zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
dsound.c
Go to the documentation of this file.
1 
21 #include "config.h"
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
26 
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
34 
35 #include "alMain.h"
36 #include "alu.h"
37 
38 #ifndef DSSPEAKER_5POINT1
39 #define DSSPEAKER_5POINT1 6
40 #endif
41 #ifndef DSSPEAKER_7POINT1
42 #define DSSPEAKER_7POINT1 7
43 #endif
44 
45 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
47 
48 
49 static void *ds_handle;
50 static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
51 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
52 static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
53 static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
54 
55 #define DirectSoundCreate pDirectSoundCreate
56 #define DirectSoundEnumerateA pDirectSoundEnumerateA
57 #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
58 #define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
59 
60 
61 typedef struct {
62  // DirectSound Playback Device
63  IDirectSound *DS;
64  IDirectSoundBuffer *PrimaryBuffer;
65  IDirectSoundBuffer *Buffer;
66  IDirectSoundNotify *Notifies;
67  HANDLE NotifyEvent;
68 
69  volatile int killNow;
70  ALvoid *thread;
71 } DSoundPlaybackData;
72 
73 typedef struct {
74  // DirectSound Capture Device
75  IDirectSoundCapture *DSC;
76  IDirectSoundCaptureBuffer *DSCbuffer;
77  DWORD BufferBytes;
78  DWORD Cursor;
79  RingBuffer *Ring;
80 } DSoundCaptureData;
81 
82 
83 typedef struct {
84  ALCchar *name;
85  GUID guid;
86 } DevMap;
87 
88 static DevMap *PlaybackDeviceList;
90 static DevMap *CaptureDeviceList;
92 
93 #define MAX_UPDATES 128
94 
95 static ALCboolean DSoundLoad(void)
96 {
97  if(!ds_handle)
98  {
99  ds_handle = LoadLib("dsound.dll");
100  if(ds_handle == NULL)
101  {
102  ERR("Failed to load dsound.dll\n");
103  return ALC_FALSE;
104  }
105 
106 #define LOAD_FUNC(f) do { \
107  p##f = GetSymbol(ds_handle, #f); \
108  if(p##f == NULL) { \
109  CloseLib(ds_handle); \
110  ds_handle = NULL; \
111  return ALC_FALSE; \
112  } \
113 } while(0)
118 #undef LOAD_FUNC
119  }
120  return ALC_TRUE;
121 }
122 
123 
124 static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
125 {
126  LPOLESTR guidstr = NULL;
127  char str[1024];
128  HRESULT hr;
129  void *temp;
130  int count;
131  ALuint i;
132 
133  (void)data;
134  (void)drvname;
135 
136  if(!guid)
137  return TRUE;
138 
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++;
146 
147  for(i = 0;i < NumPlaybackDevices;i++)
148  {
149  if(strcmp(str, PlaybackDeviceList[i].name) == 0)
150  break;
151  }
152  } while(i != NumPlaybackDevices);
153 
154  hr = StringFromCLSID(guid, &guidstr);
155  if(SUCCEEDED(hr))
156  {
157  TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
158  CoTaskMemFree(guidstr);
159  }
160 
161  temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
162  if(temp)
163  {
164  PlaybackDeviceList = temp;
168  }
169 
170  return TRUE;
171 }
172 
173 
174 static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
175 {
176  LPOLESTR guidstr = NULL;
177  char str[1024];
178  HRESULT hr;
179  void *temp;
180  int count;
181  ALuint i;
182 
183  (void)data;
184  (void)drvname;
185 
186  if(!guid)
187  return TRUE;
188 
189  count = 0;
190  do {
191  if(count == 0)
192  snprintf(str, sizeof(str), "%s", desc);
193  else
194  snprintf(str, sizeof(str), "%s #%d", desc, count+1);
195  count++;
196 
197  for(i = 0;i < NumCaptureDevices;i++)
198  {
199  if(strcmp(str, CaptureDeviceList[i].name) == 0)
200  break;
201  }
202  } while(i != NumCaptureDevices);
203 
204  hr = StringFromCLSID(guid, &guidstr);
205  if(SUCCEEDED(hr))
206  {
207  TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
208  CoTaskMemFree(guidstr);
209  }
210 
211  temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
212  if(temp)
213  {
214  CaptureDeviceList = temp;
216  CaptureDeviceList[NumCaptureDevices].guid = *guid;
218  }
219 
220  return TRUE;
221 }
222 
223 
225 {
226  ALCdevice *Device = (ALCdevice*)ptr;
227  DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
228  DSBCAPS DSBCaps;
229  DWORD LastCursor = 0;
230  DWORD PlayCursor;
231  VOID *WritePtr1, *WritePtr2;
232  DWORD WriteCnt1, WriteCnt2;
233  BOOL Playing = FALSE;
234  DWORD FrameSize;
235  DWORD FragSize;
236  DWORD avail;
237  HRESULT err;
238 
239  SetRTPriority();
240 
241  memset(&DSBCaps, 0, sizeof(DSBCaps));
242  DSBCaps.dwSize = sizeof(DSBCaps);
243  err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps);
244  if(FAILED(err))
245  {
246  ERR("Failed to get buffer caps: 0x%lx\n", err);
247  ALCdevice_Lock(Device);
248  aluHandleDisconnect(Device);
249  ALCdevice_Unlock(Device);
250  return 1;
251  }
252 
253  FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
254  FragSize = Device->UpdateSize * FrameSize;
255 
256  IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL);
257  while(!data->killNow)
258  {
259  // Get current play cursor
260  IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL);
261  avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
262 
263  if(avail < FragSize)
264  {
265  if(!Playing)
266  {
267  err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING);
268  if(FAILED(err))
269  {
270  ERR("Failed to play buffer: 0x%lx\n", err);
271  ALCdevice_Lock(Device);
272  aluHandleDisconnect(Device);
273  ALCdevice_Unlock(Device);
274  return 1;
275  }
276  Playing = TRUE;
277  }
278 
279  avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
280  if(avail != WAIT_OBJECT_0)
281  ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
282  continue;
283  }
284  avail -= avail%FragSize;
285 
286  // Lock output buffer
287  WriteCnt1 = 0;
288  WriteCnt2 = 0;
289  err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
290 
291  // If the buffer is lost, restore it and lock
292  if(err == DSERR_BUFFERLOST)
293  {
294  WARN("Buffer lost, restoring...\n");
295  err = IDirectSoundBuffer_Restore(data->Buffer);
296  if(SUCCEEDED(err))
297  {
298  Playing = FALSE;
299  LastCursor = 0;
300  err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
301  }
302  }
303 
304  // Successfully locked the output buffer
305  if(SUCCEEDED(err))
306  {
307  // If we have an active context, mix data directly into output buffer otherwise fill with silence
308  aluMixData(Device, WritePtr1, WriteCnt1/FrameSize);
309  aluMixData(Device, WritePtr2, WriteCnt2/FrameSize);
310 
311  // Unlock output buffer only when successfully locked
312  IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
313  }
314  else
315  {
316  ERR("Buffer lock error: %#lx\n", err);
317  ALCdevice_Lock(Device);
318  aluHandleDisconnect(Device);
319  ALCdevice_Unlock(Device);
320  return 1;
321  }
322 
323  // Update old write cursor location
324  LastCursor += WriteCnt1+WriteCnt2;
325  LastCursor %= DSBCaps.dwBufferBytes;
326  }
327 
328  return 0;
329 }
330 
331 static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
332 {
333  DSoundPlaybackData *data = NULL;
334  LPGUID guid = NULL;
335  HRESULT hr;
336 
337  if(!PlaybackDeviceList)
338  {
340  if(FAILED(hr))
341  ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
342  }
343 
344  if(!deviceName && NumPlaybackDevices > 0)
345  {
346  deviceName = PlaybackDeviceList[0].name;
347  guid = &PlaybackDeviceList[0].guid;
348  }
349  else
350  {
351  ALuint i;
352 
353  for(i = 0;i < NumPlaybackDevices;i++)
354  {
355  if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
356  {
357  guid = &PlaybackDeviceList[i].guid;
358  break;
359  }
360  }
361  if(i == NumPlaybackDevices)
362  return ALC_INVALID_VALUE;
363  }
364 
365  //Initialise requested device
366  data = calloc(1, sizeof(DSoundPlaybackData));
367  if(!data)
368  return ALC_OUT_OF_MEMORY;
369 
370  hr = DS_OK;
371  data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
372  if(data->NotifyEvent == NULL)
373  hr = E_FAIL;
374 
375  //DirectSound Init code
376  if(SUCCEEDED(hr))
377  hr = DirectSoundCreate(guid, &data->DS, NULL);
378  if(SUCCEEDED(hr))
379  hr = IDirectSound_SetCooperativeLevel(data->DS, GetForegroundWindow(), DSSCL_PRIORITY);
380  if(FAILED(hr))
381  {
382  if(data->DS)
383  IDirectSound_Release(data->DS);
384  if(data->NotifyEvent)
385  CloseHandle(data->NotifyEvent);
386  free(data);
387  ERR("Device init failed: 0x%08lx\n", hr);
388  return ALC_INVALID_VALUE;
389  }
390 
391  device->DeviceName = strdup(deviceName);
392  device->ExtraData = data;
393  return ALC_NO_ERROR;
394 }
395 
396 static void DSoundClosePlayback(ALCdevice *device)
397 {
398  DSoundPlaybackData *data = device->ExtraData;
399 
400  if(data->Notifies)
401  IDirectSoundNotify_Release(data->Notifies);
402  data->Notifies = NULL;
403  if(data->Buffer)
404  IDirectSoundBuffer_Release(data->Buffer);
405  data->Buffer = NULL;
406  if(data->PrimaryBuffer != NULL)
407  IDirectSoundBuffer_Release(data->PrimaryBuffer);
408  data->PrimaryBuffer = NULL;
409 
410  IDirectSound_Release(data->DS);
411  CloseHandle(data->NotifyEvent);
412  free(data);
413  device->ExtraData = NULL;
414 }
415 
417 {
418  DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
419  DSBUFFERDESC DSBDescription;
420  WAVEFORMATEXTENSIBLE OutputType;
421  DWORD speakers;
422  HRESULT hr;
423 
424  memset(&OutputType, 0, sizeof(OutputType));
425 
426  if(data->Notifies)
427  IDirectSoundNotify_Release(data->Notifies);
428  data->Notifies = NULL;
429  if(data->Buffer)
430  IDirectSoundBuffer_Release(data->Buffer);
431  data->Buffer = NULL;
432  if(data->PrimaryBuffer != NULL)
433  IDirectSoundBuffer_Release(data->PrimaryBuffer);
434  data->PrimaryBuffer = NULL;
435 
436  switch(device->FmtType)
437  {
438  case DevFmtByte:
439  device->FmtType = DevFmtUByte;
440  break;
441  case DevFmtFloat:
442  if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST))
443  break;
444  /* fall-through */
445  case DevFmtUShort:
446  device->FmtType = DevFmtShort;
447  break;
448  case DevFmtUInt:
449  device->FmtType = DevFmtInt;
450  break;
451  case DevFmtUByte:
452  case DevFmtShort:
453  case DevFmtInt:
454  break;
455  }
456 
457  hr = IDirectSound_GetSpeakerConfig(data->DS, &speakers);
458  if(SUCCEEDED(hr))
459  {
460  if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
461  {
462  speakers = DSSPEAKER_CONFIG(speakers);
463  if(speakers == DSSPEAKER_MONO)
464  device->FmtChans = DevFmtMono;
465  else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
466  device->FmtChans = DevFmtStereo;
467  else if(speakers == DSSPEAKER_QUAD)
468  device->FmtChans = DevFmtQuad;
469  else if(speakers == DSSPEAKER_5POINT1)
470  device->FmtChans = DevFmtX51;
471  else if(speakers == DSSPEAKER_7POINT1)
472  device->FmtChans = DevFmtX71;
473  else
474  ERR("Unknown system speaker config: 0x%lx\n", speakers);
475  }
476 
477  switch(device->FmtChans)
478  {
479  case DevFmtMono:
480  OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
481  break;
482  case DevFmtStereo:
483  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
485  break;
486  case DevFmtQuad:
487  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
491  break;
492  case DevFmtX51:
493  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
499  break;
500  case DevFmtX51Side:
501  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
507  break;
508  case DevFmtX61:
509  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
516  break;
517  case DevFmtX71:
518  OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
526  break;
527  }
528 
529 retry_open:
530  hr = S_OK;
531  OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
532  OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
533  OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
534  OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
535  OutputType.Format.nSamplesPerSec = device->Frequency;
536  OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
537  OutputType.Format.cbSize = 0;
538  }
539 
540  if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
541  {
542  OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
543  OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
544  OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
545  if(device->FmtType == DevFmtFloat)
546  OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
547  else
548  OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
549 
550  if(data->PrimaryBuffer)
551  IDirectSoundBuffer_Release(data->PrimaryBuffer);
552  data->PrimaryBuffer = NULL;
553  }
554  else
555  {
556  if(SUCCEEDED(hr) && !data->PrimaryBuffer)
557  {
558  memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
559  DSBDescription.dwSize=sizeof(DSBUFFERDESC);
560  DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
561  hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->PrimaryBuffer, NULL);
562  }
563  if(SUCCEEDED(hr))
564  hr = IDirectSoundBuffer_SetFormat(data->PrimaryBuffer,&OutputType.Format);
565  }
566 
567  if(SUCCEEDED(hr))
568  {
569  if(device->NumUpdates > MAX_UPDATES)
570  {
571  device->UpdateSize = (device->UpdateSize*device->NumUpdates +
573  device->NumUpdates = MAX_UPDATES;
574  }
575 
576  memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
577  DSBDescription.dwSize=sizeof(DSBUFFERDESC);
578  DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
579  DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
580  OutputType.Format.nBlockAlign;
581  DSBDescription.lpwfxFormat=&OutputType.Format;
582  hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->Buffer, NULL);
583  if(FAILED(hr) && device->FmtType == DevFmtFloat)
584  {
585  device->FmtType = DevFmtShort;
586  goto retry_open;
587  }
588  }
589 
590  if(SUCCEEDED(hr))
591  {
592  hr = IDirectSoundBuffer_QueryInterface(data->Buffer, &IID_IDirectSoundNotify, (LPVOID *)&data->Notifies);
593  if(SUCCEEDED(hr))
594  {
595  DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
596  ALuint i;
597 
598  for(i = 0;i < device->NumUpdates;++i)
599  {
600  notifies[i].dwOffset = i * device->UpdateSize *
601  OutputType.Format.nBlockAlign;
602  notifies[i].hEventNotify = data->NotifyEvent;
603  }
604  if(IDirectSoundNotify_SetNotificationPositions(data->Notifies, device->NumUpdates, notifies) != DS_OK)
605  hr = E_FAIL;
606  }
607  }
608 
609  if(FAILED(hr))
610  {
611  if(data->Notifies != NULL)
612  IDirectSoundNotify_Release(data->Notifies);
613  data->Notifies = NULL;
614  if(data->Buffer != NULL)
615  IDirectSoundBuffer_Release(data->Buffer);
616  data->Buffer = NULL;
617  if(data->PrimaryBuffer != NULL)
618  IDirectSoundBuffer_Release(data->PrimaryBuffer);
619  data->PrimaryBuffer = NULL;
620  return ALC_FALSE;
621  }
622 
623  ResetEvent(data->NotifyEvent);
625 
626  return ALC_TRUE;
627 }
628 
630 {
631  DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
632 
633  data->thread = StartThread(DSoundPlaybackProc, device);
634  if(data->thread == NULL)
635  return ALC_FALSE;
636 
637  return ALC_TRUE;
638 }
639 
640 static void DSoundStopPlayback(ALCdevice *device)
641 {
642  DSoundPlaybackData *data = device->ExtraData;
643 
644  if(!data->thread)
645  return;
646 
647  data->killNow = 1;
648  StopThread(data->thread);
649  data->thread = NULL;
650 
651  data->killNow = 0;
652  IDirectSoundBuffer_Stop(data->Buffer);
653 }
654 
655 
656 static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
657 {
658  DSoundCaptureData *data = NULL;
659  WAVEFORMATEXTENSIBLE InputType;
660  DSCBUFFERDESC DSCBDescription;
661  LPGUID guid = NULL;
662  HRESULT hr, hrcom;
663  ALuint samples;
664 
665  if(!CaptureDeviceList)
666  {
667  /* Initialize COM to prevent name truncation */
668  hrcom = CoInitialize(NULL);
670  if(FAILED(hr))
671  ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
672  if(SUCCEEDED(hrcom))
673  CoUninitialize();
674  }
675 
676  if(!deviceName && NumCaptureDevices > 0)
677  {
678  deviceName = CaptureDeviceList[0].name;
679  guid = &CaptureDeviceList[0].guid;
680  }
681  else
682  {
683  ALuint i;
684 
685  for(i = 0;i < NumCaptureDevices;i++)
686  {
687  if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
688  {
689  guid = &CaptureDeviceList[i].guid;
690  break;
691  }
692  }
693  if(i == NumCaptureDevices)
694  return ALC_INVALID_VALUE;
695  }
696 
697  switch(device->FmtType)
698  {
699  case DevFmtByte:
700  case DevFmtUShort:
701  case DevFmtUInt:
702  WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
703  return ALC_INVALID_ENUM;
704 
705  case DevFmtUByte:
706  case DevFmtShort:
707  case DevFmtInt:
708  case DevFmtFloat:
709  break;
710  }
711 
712  //Initialise requested device
713  data = calloc(1, sizeof(DSoundCaptureData));
714  if(!data)
715  return ALC_OUT_OF_MEMORY;
716 
717  hr = DS_OK;
718 
719  //DirectSoundCapture Init code
720  if(SUCCEEDED(hr))
721  hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL);
722  if(SUCCEEDED(hr))
723  {
724  memset(&InputType, 0, sizeof(InputType));
725 
726  switch(device->FmtChans)
727  {
728  case DevFmtMono:
730  break;
731  case DevFmtStereo:
732  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
734  break;
735  case DevFmtQuad:
736  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
740  break;
741  case DevFmtX51:
742  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
748  break;
749  case DevFmtX51Side:
750  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
756  break;
757  case DevFmtX61:
758  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
765  break;
766  case DevFmtX71:
767  InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
775  break;
776  }
777 
778  InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
779  InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
780  InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
781  InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
782  InputType.Format.nSamplesPerSec = device->Frequency;
783  InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
784  InputType.Format.cbSize = 0;
785 
786  if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
787  {
789  InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
790  InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
791  if(device->FmtType == DevFmtFloat)
792  InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
793  else
794  InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
795  }
796 
797  samples = device->UpdateSize * device->NumUpdates;
798  samples = maxu(samples, 100 * device->Frequency / 1000);
799 
800  memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
801  DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
802  DSCBDescription.dwFlags = 0;
803  DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
804  DSCBDescription.lpwfxFormat = &InputType.Format;
805 
806  hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL);
807  }
808  if(SUCCEEDED(hr))
809  {
810  data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
811  if(data->Ring == NULL)
812  hr = DSERR_OUTOFMEMORY;
813  }
814 
815  if(FAILED(hr))
816  {
817  ERR("Device init failed: 0x%08lx\n", hr);
818 
819  DestroyRingBuffer(data->Ring);
820  data->Ring = NULL;
821  if(data->DSCbuffer != NULL)
822  IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
823  data->DSCbuffer = NULL;
824  if(data->DSC)
825  IDirectSoundCapture_Release(data->DSC);
826  data->DSC = NULL;
827 
828  free(data);
829  return ALC_INVALID_VALUE;
830  }
831 
832  data->BufferBytes = DSCBDescription.dwBufferBytes;
834 
835  device->DeviceName = strdup(deviceName);
836  device->ExtraData = data;
837 
838  return ALC_NO_ERROR;
839 }
840 
841 static void DSoundCloseCapture(ALCdevice *device)
842 {
843  DSoundCaptureData *data = device->ExtraData;
844 
845  DestroyRingBuffer(data->Ring);
846  data->Ring = NULL;
847 
848  if(data->DSCbuffer != NULL)
849  {
850  IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
851  IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
852  data->DSCbuffer = NULL;
853  }
854 
855  IDirectSoundCapture_Release(data->DSC);
856  data->DSC = NULL;
857 
858  free(data);
859  device->ExtraData = NULL;
860 }
861 
862 static void DSoundStartCapture(ALCdevice *device)
863 {
864  DSoundCaptureData *data = device->ExtraData;
865  HRESULT hr;
866 
867  hr = IDirectSoundCaptureBuffer_Start(data->DSCbuffer, DSCBSTART_LOOPING);
868  if(FAILED(hr))
869  {
870  ERR("start failed: 0x%08lx\n", hr);
871  aluHandleDisconnect(device);
872  }
873 }
874 
875 static void DSoundStopCapture(ALCdevice *device)
876 {
877  DSoundCaptureData *data = device->ExtraData;
878  HRESULT hr;
879 
880  hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
881  if(FAILED(hr))
882  {
883  ERR("stop failed: 0x%08lx\n", hr);
884  aluHandleDisconnect(device);
885  }
886 }
887 
888 static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
889 {
890  DSoundCaptureData *data = Device->ExtraData;
891  ReadRingBuffer(data->Ring, pBuffer, lSamples);
892  return ALC_NO_ERROR;
893 }
894 
896 {
897  DSoundCaptureData *data = Device->ExtraData;
898  DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
899  VOID *ReadPtr1, *ReadPtr2;
900  DWORD ReadCnt1, ReadCnt2;
901  DWORD FrameSize;
902  HRESULT hr;
903 
904  if(!Device->Connected)
905  goto done;
906 
907  FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
908  BufferBytes = data->BufferBytes;
909  LastCursor = data->Cursor;
910 
911  hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor);
912  if(SUCCEEDED(hr))
913  {
914  NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
915  if(NumBytes == 0)
916  goto done;
917  hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes,
918  &ReadPtr1, &ReadCnt1,
919  &ReadPtr2, &ReadCnt2, 0);
920  }
921  if(SUCCEEDED(hr))
922  {
923  WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize);
924  if(ReadPtr2 != NULL)
925  WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize);
926  hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer,
927  ReadPtr1, ReadCnt1,
928  ReadPtr2, ReadCnt2);
929  data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
930  }
931 
932  if(FAILED(hr))
933  {
934  ERR("update failed: 0x%08lx\n", hr);
935  aluHandleDisconnect(Device);
936  }
937 
938 done:
939  return RingBufferSize(data->Ring);
940 }
941 
942 
943 static const BackendFuncs DSoundFuncs = {
958 };
959 
960 
962 {
963  if(!DSoundLoad())
964  return ALC_FALSE;
965  *FuncList = DSoundFuncs;
966  return ALC_TRUE;
967 }
968 
969 void alcDSoundDeinit(void)
970 {
971  ALuint i;
972 
973  for(i = 0;i < NumPlaybackDevices;++i)
977  NumPlaybackDevices = 0;
978 
979  for(i = 0;i < NumCaptureDevices;++i)
980  free(CaptureDeviceList[i].name);
983  NumCaptureDevices = 0;
984 
985  if(ds_handle)
986  CloseLib(ds_handle);
987  ds_handle = NULL;
988 }
989 
991 {
992  HRESULT hr, hrcom;
993  ALuint i;
994 
995  switch(type)
996  {
997  case ALL_DEVICE_PROBE:
998  for(i = 0;i < NumPlaybackDevices;++i)
1002  NumPlaybackDevices = 0;
1003 
1005  if(FAILED(hr))
1006  ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
1007  else
1008  {
1009  for(i = 0;i < NumPlaybackDevices;i++)
1011  }
1012  break;
1013 
1014  case CAPTURE_DEVICE_PROBE:
1015  for(i = 0;i < NumCaptureDevices;++i)
1016  free(CaptureDeviceList[i].name);
1019  NumCaptureDevices = 0;
1020 
1021  /* Initialize COM to prevent name truncation */
1022  hrcom = CoInitialize(NULL);
1024  if(FAILED(hr))
1025  ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
1026  else
1027  {
1028  for(i = 0;i < NumCaptureDevices;i++)
1030  }
1031  if(SUCCEEDED(hrcom))
1032  CoUninitialize();
1033  break;
1034  }
1035 }
static ALuint NumCaptureDevices
Definition: dsound.c:91
static void DSoundCloseCapture(ALCdevice *device)
Definition: dsound.c:841
ALCboolean Connected
Definition: alMain.h:564
void ALvoid
Definition: al.h:74
#define MAX_UPDATES
Definition: dsound.c:93
#define ALC_TRUE
Definition: alc.h:84
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
WORD nChannels
Definition: audiodefs.h:43
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
char * strdup(const char *inStr)
Definition: strdup.c:6
#define NULL
Definition: ftobjs.h:61
static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
Definition: dsound.c:174
#define TRACE(...)
Definition: alMain.h:806
static void DSoundStopPlayback(ALCdevice *device)
Definition: dsound.c:640
#define DirectSoundCaptureCreate
Definition: dsound.c:57
DWORD nAvgBytesPerSec
Definition: audiodefs.h:45
#define ALC_INVALID_ENUM
Definition: alc.h:111
static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
Definition: dsound.c:331
SDL_EventEntry * free
Definition: SDL_events.c:80
#define SPEAKER_FRONT_CENTER
Definition: audiodefs.h:226
ALuint Frequency
Definition: alMain.h:569
#define SPEAKER_BACK_LEFT
Definition: audiodefs.h:228
#define SPEAKER_BACK_RIGHT
Definition: audiodefs.h:229
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
Definition: ALu.c:970
#define memset
Definition: SDL_malloc.c:633
static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
Definition: dsound.c:656
ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device)
Definition: ALc.c:1285
EGLImageKHR EGLint * name
Definition: eglext.h:284
static const BackendFuncs DSoundFuncs
Definition: dsound.c:943
#define SPEAKER_FRONT_RIGHT
Definition: audiodefs.h:225
static DevMap * PlaybackDeviceList
Definition: dsound.c:88
#define DEVICE_SAMPLE_TYPE_REQUEST
Definition: alMain.h:655
ALuint Flags
Definition: alMain.h:605
ALsizei RingBufferSize(RingBuffer *ring)
Definition: alcRing.c:67
static ALCboolean DSoundResetPlayback(ALCdevice *device)
Definition: dsound.c:416
void AppendCaptureDeviceList(const ALCchar *name)
unsigned int ALCuint
Definition: alc.h:60
#define calloc
Definition: SDL_malloc.c:636
ALvoid aluHandleDisconnect(ALCdevice *device)
Definition: ALu.c:1176
char ALCchar
Definition: alc.h:42
#define SPEAKER_BACK_CENTER
Definition: audiodefs.h:232
#define DirectSoundCaptureEnumerateA
Definition: dsound.c:58
#define ALCdevice_Unlock(a)
Definition: alMain.h:647
struct RingBuffer RingBuffer
Definition: alMain.h:750
#define WAVE_FORMAT_EXTENSIBLE
Definition: makehrtf.c:179
#define SPEAKER_SIDE_LEFT
Definition: audiodefs.h:233
void * ExtraData
Definition: alMain.h:630
static IDirectSoundCapture ** ppDSC
Definition: dsound.c:52
#define ALC_FALSE
Definition: alc.h:81
static IDirectSound ** ppDS
Definition: dsound.c:50
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
ALuint StopThread(ALvoid *thread)
Definition: alcThread.c:131
static ALCboolean DSoundLoad(void)
Definition: dsound.c:95
void SetDefaultWFXChannelOrder(ALCdevice *device)
Definition: ALc.c:1295
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
static ALCboolean DSoundStartPlayback(ALCdevice *device)
Definition: dsound.c:629
static HRESULT(WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice
GLint GLsizei count
Definition: gl2ext.h:1011
GLsizei samples
Definition: gl2ext.h:970
RingBuffer * CreateRingBuffer(ALsizei frame_size, ALsizei length)
Definition: alcRing.c:41
static ALuint DSoundPlaybackProc(ALvoid *ptr)
Definition: dsound.c:224
#define DirectSoundEnumerateA
Definition: dsound.c:56
#define LOAD_FUNC(f)
static void * pContext
Definition: dsound.c:51
static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
Definition: dsound.c:124
#define realloc
Definition: SDL_malloc.c:637
static void DSoundStartCapture(ALCdevice *device)
Definition: dsound.c:862
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)
WORD nBlockAlign
Definition: audiodefs.h:46
unsigned int ALuint
Definition: al.h:59
void SetRTPriority(void)
Definition: helpers.c:470
static DevMap * CaptureDeviceList
Definition: dsound.c:90
#define WARN(...)
Definition: alMain.h:811
#define FALSE
Definition: ftobjs.h:57
union WAVEFORMATEXTENSIBLE::@63 Samples
#define WAVE_FORMAT_PCM
Definition: makehrtf.c:177
enum DevFmtChannels FmtChans
Definition: alMain.h:572
DWORD nSamplesPerSec
Definition: audiodefs.h:44
typedef LPVOID(WINAPI *PFNWGLCREATEIMAGEBUFFERI3DPROC)(HDC hDC
#define DEVICE_CHANNELS_REQUEST
Definition: alMain.h:653
#define SPEAKER_LOW_FREQUENCY
Definition: audiodefs.h:227
static SDL_Thread * thread
static ALCuint DSoundAvailableSamples(ALCdevice *Device)
Definition: dsound.c:895
#define ALC_NO_ERROR
Definition: alc.h:102
void ALCdevice_LockDefault(ALCdevice *device)
Definition: ALc.c:1277
char ALCboolean
Definition: alc.h:39
WORD wBitsPerSample
Definition: audiodefs.h:47
void ALCvoid
Definition: alc.h:75
#define ERR(...)
Definition: alMain.h:816
ALuint UpdateSize
Definition: alMain.h:570
WORD wFormatTag
Definition: audiodefs.h:42
ALuint NumUpdates
Definition: alMain.h:571
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex
static ALuint NumPlaybackDevices
Definition: dsound.c:89
#define SPEAKER_SIDE_RIGHT
Definition: audiodefs.h:234
void alcDSoundProbe(enum DevProbe type)
Definition: dsound.c:990
enum DevFmtType FmtType
Definition: alMain.h:573
WAVEFORMATEX Format
Definition: audiodefs.h:76
static void DSoundClosePlayback(ALCdevice *device)
Definition: dsound.c:396
ALCchar * DeviceName
Definition: alMain.h:575
#define ALC_INVALID_VALUE
Definition: alc.h:114
#define ALC_OUT_OF_MEMORY
Definition: alc.h:117
static IDirectSound IUnknown * pUnkOuter
Definition: dsound.c:50
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
Definition: alcRing.c:108
#define DirectSoundCreate
Definition: dsound.c:55
ALCboolean alcDSoundInit(BackendFuncs *FuncList)
Definition: dsound.c:961
static void * ds_handle
Definition: dsound.c:49
#define str(s)
#define SPEAKER_FRONT_LEFT
Definition: audiodefs.h:224
static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
Definition: dsound.c:888
static void DSoundStopCapture(ALCdevice *device)
Definition: dsound.c:875
int i
Definition: pngrutil.c:1377
int ALCenum
Definition: alc.h:66
const ALCchar * DevFmtTypeString(enum DevFmtType type)
Definition: ALc.c:1136
void alcDSoundDeinit(void)
Definition: dsound.c:969
ALuint BytesFromDevFmt(enum DevFmtType type)
Definition: ALc.c:1165
void DestroyRingBuffer(RingBuffer *ring)
Definition: alcRing.c:58
typedef VOID(WINAPI *PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC)(HGLRC dstCtx
#define TRUE
Definition: ftobjs.h:53
void ALCdevice_UnlockDefault(ALCdevice *device)
Definition: ALc.c:1281
static __inline ALuint maxu(ALuint a, ALuint b)
Definition: alu.h:63
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
Definition: alcRing.c:78
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
Definition: ALc.c:1179
#define ALCdevice_Lock(a)
Definition: alMain.h:646
void AppendAllDevicesList(const ALCchar *name)
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
Definition: alcThread.c:100
DevProbe
Definition: alMain.h:383
static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
Definition: alMain.h:523
typedef BOOL(WINAPI *PFNWGLSETSTEREOEMITTERSTATE3DLPROC)(HDC hDC