dsound.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  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.
  8. *
  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.
  13. *
  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
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <memory.h>
  24. #include <dsound.h>
  25. #include <cguid.h>
  26. #include <mmreg.h>
  27. #ifndef _WAVEFORMATEXTENSIBLE_
  28. #include <ks.h>
  29. #include <ksmedia.h>
  30. #endif
  31. #include "alMain.h"
  32. #include "alu.h"
  33. #include "threads.h"
  34. #include "compat.h"
  35. #ifndef DSSPEAKER_5POINT1
  36. # define DSSPEAKER_5POINT1 0x00000006
  37. #endif
  38. #ifndef DSSPEAKER_7POINT1
  39. # define DSSPEAKER_7POINT1 0x00000007
  40. #endif
  41. #ifndef DSSPEAKER_7POINT1_SURROUND
  42. # define DSSPEAKER_7POINT1_SURROUND 0x00000008
  43. #endif
  44. #ifndef DSSPEAKER_5POINT1_SURROUND
  45. # define DSSPEAKER_5POINT1_SURROUND 0x00000009
  46. #endif
  47. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  48. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  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. #define DirectSoundCreate pDirectSoundCreate
  55. #define DirectSoundEnumerateA pDirectSoundEnumerateA
  56. #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
  57. #define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
  58. typedef struct {
  59. // DirectSound Playback Device
  60. IDirectSound *DS;
  61. IDirectSoundBuffer *PrimaryBuffer;
  62. IDirectSoundBuffer *Buffer;
  63. IDirectSoundNotify *Notifies;
  64. HANDLE NotifyEvent;
  65. volatile int killNow;
  66. althread_t thread;
  67. } DSoundPlaybackData;
  68. typedef struct {
  69. // DirectSound Capture Device
  70. IDirectSoundCapture *DSC;
  71. IDirectSoundCaptureBuffer *DSCbuffer;
  72. DWORD BufferBytes;
  73. DWORD Cursor;
  74. RingBuffer *Ring;
  75. } DSoundCaptureData;
  76. typedef struct {
  77. ALCchar *name;
  78. GUID guid;
  79. } DevMap;
  80. static DevMap *PlaybackDeviceList;
  81. static ALuint NumPlaybackDevices;
  82. static DevMap *CaptureDeviceList;
  83. static ALuint NumCaptureDevices;
  84. #define MAX_UPDATES 128
  85. static ALCboolean DSoundLoad(void)
  86. {
  87. if(!ds_handle)
  88. {
  89. ds_handle = LoadLib("dsound.dll");
  90. if(ds_handle == NULL)
  91. {
  92. ERR("Failed to load dsound.dll\n");
  93. return ALC_FALSE;
  94. }
  95. #define LOAD_FUNC(f) do { \
  96. p##f = GetSymbol(ds_handle, #f); \
  97. if(p##f == NULL) { \
  98. CloseLib(ds_handle); \
  99. ds_handle = NULL; \
  100. return ALC_FALSE; \
  101. } \
  102. } while(0)
  103. LOAD_FUNC(DirectSoundCreate);
  104. LOAD_FUNC(DirectSoundEnumerateA);
  105. LOAD_FUNC(DirectSoundCaptureCreate);
  106. LOAD_FUNC(DirectSoundCaptureEnumerateA);
  107. #undef LOAD_FUNC
  108. }
  109. return ALC_TRUE;
  110. }
  111. static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
  112. {
  113. LPOLESTR guidstr = NULL;
  114. char str[1024];
  115. HRESULT hr;
  116. void *temp;
  117. int count;
  118. ALuint i;
  119. if(!guid)
  120. return TRUE;
  121. count = 0;
  122. do {
  123. if(count == 0)
  124. snprintf(str, sizeof(str), "%s", desc);
  125. else
  126. snprintf(str, sizeof(str), "%s #%d", desc, count+1);
  127. count++;
  128. for(i = 0;i < NumPlaybackDevices;i++)
  129. {
  130. if(strcmp(str, PlaybackDeviceList[i].name) == 0)
  131. break;
  132. }
  133. } while(i != NumPlaybackDevices);
  134. hr = StringFromCLSID(guid, &guidstr);
  135. if(SUCCEEDED(hr))
  136. {
  137. TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
  138. CoTaskMemFree(guidstr);
  139. }
  140. temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
  141. if(temp)
  142. {
  143. PlaybackDeviceList = temp;
  144. PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
  145. PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
  146. NumPlaybackDevices++;
  147. }
  148. return TRUE;
  149. }
  150. static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
  151. {
  152. LPOLESTR guidstr = NULL;
  153. char str[1024];
  154. HRESULT hr;
  155. void *temp;
  156. int count;
  157. ALuint i;
  158. if(!guid)
  159. return TRUE;
  160. count = 0;
  161. do {
  162. if(count == 0)
  163. snprintf(str, sizeof(str), "%s", desc);
  164. else
  165. snprintf(str, sizeof(str), "%s #%d", desc, count+1);
  166. count++;
  167. for(i = 0;i < NumCaptureDevices;i++)
  168. {
  169. if(strcmp(str, CaptureDeviceList[i].name) == 0)
  170. break;
  171. }
  172. } while(i != NumCaptureDevices);
  173. hr = StringFromCLSID(guid, &guidstr);
  174. if(SUCCEEDED(hr))
  175. {
  176. TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
  177. CoTaskMemFree(guidstr);
  178. }
  179. temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
  180. if(temp)
  181. {
  182. CaptureDeviceList = temp;
  183. CaptureDeviceList[NumCaptureDevices].name = strdup(str);
  184. CaptureDeviceList[NumCaptureDevices].guid = *guid;
  185. NumCaptureDevices++;
  186. }
  187. return TRUE;
  188. }
  189. FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
  190. {
  191. ALCdevice *Device = (ALCdevice*)ptr;
  192. DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
  193. DSBCAPS DSBCaps;
  194. DWORD LastCursor = 0;
  195. DWORD PlayCursor;
  196. VOID *WritePtr1, *WritePtr2;
  197. DWORD WriteCnt1, WriteCnt2;
  198. BOOL Playing = FALSE;
  199. DWORD FrameSize;
  200. DWORD FragSize;
  201. DWORD avail;
  202. HRESULT err;
  203. SetRTPriority();
  204. SetThreadName(MIXER_THREAD_NAME);
  205. memset(&DSBCaps, 0, sizeof(DSBCaps));
  206. DSBCaps.dwSize = sizeof(DSBCaps);
  207. err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps);
  208. if(FAILED(err))
  209. {
  210. ERR("Failed to get buffer caps: 0x%lx\n", err);
  211. ALCdevice_Lock(Device);
  212. aluHandleDisconnect(Device);
  213. ALCdevice_Unlock(Device);
  214. return 1;
  215. }
  216. FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
  217. FragSize = Device->UpdateSize * FrameSize;
  218. IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL);
  219. while(!data->killNow)
  220. {
  221. // Get current play cursor
  222. IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL);
  223. avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
  224. if(avail < FragSize)
  225. {
  226. if(!Playing)
  227. {
  228. err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING);
  229. if(FAILED(err))
  230. {
  231. ERR("Failed to play buffer: 0x%lx\n", err);
  232. ALCdevice_Lock(Device);
  233. aluHandleDisconnect(Device);
  234. ALCdevice_Unlock(Device);
  235. return 1;
  236. }
  237. Playing = TRUE;
  238. }
  239. avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
  240. if(avail != WAIT_OBJECT_0)
  241. ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
  242. continue;
  243. }
  244. avail -= avail%FragSize;
  245. // Lock output buffer
  246. WriteCnt1 = 0;
  247. WriteCnt2 = 0;
  248. err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  249. // If the buffer is lost, restore it and lock
  250. if(err == DSERR_BUFFERLOST)
  251. {
  252. WARN("Buffer lost, restoring...\n");
  253. err = IDirectSoundBuffer_Restore(data->Buffer);
  254. if(SUCCEEDED(err))
  255. {
  256. Playing = FALSE;
  257. LastCursor = 0;
  258. err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  259. }
  260. }
  261. // Successfully locked the output buffer
  262. if(SUCCEEDED(err))
  263. {
  264. // If we have an active context, mix data directly into output buffer otherwise fill with silence
  265. aluMixData(Device, WritePtr1, WriteCnt1/FrameSize);
  266. aluMixData(Device, WritePtr2, WriteCnt2/FrameSize);
  267. // Unlock output buffer only when successfully locked
  268. IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
  269. }
  270. else
  271. {
  272. ERR("Buffer lock error: %#lx\n", err);
  273. ALCdevice_Lock(Device);
  274. aluHandleDisconnect(Device);
  275. ALCdevice_Unlock(Device);
  276. return 1;
  277. }
  278. // Update old write cursor location
  279. LastCursor += WriteCnt1+WriteCnt2;
  280. LastCursor %= DSBCaps.dwBufferBytes;
  281. }
  282. return 0;
  283. }
  284. static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
  285. {
  286. DSoundPlaybackData *data = NULL;
  287. LPGUID guid = NULL;
  288. HRESULT hr;
  289. if(!PlaybackDeviceList)
  290. {
  291. hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
  292. if(FAILED(hr))
  293. ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
  294. }
  295. if(!deviceName && NumPlaybackDevices > 0)
  296. {
  297. deviceName = PlaybackDeviceList[0].name;
  298. guid = &PlaybackDeviceList[0].guid;
  299. }
  300. else
  301. {
  302. ALuint i;
  303. for(i = 0;i < NumPlaybackDevices;i++)
  304. {
  305. if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
  306. {
  307. guid = &PlaybackDeviceList[i].guid;
  308. break;
  309. }
  310. }
  311. if(i == NumPlaybackDevices)
  312. return ALC_INVALID_VALUE;
  313. }
  314. //Initialise requested device
  315. data = calloc(1, sizeof(DSoundPlaybackData));
  316. if(!data)
  317. return ALC_OUT_OF_MEMORY;
  318. hr = DS_OK;
  319. data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  320. if(data->NotifyEvent == NULL)
  321. hr = E_FAIL;
  322. //DirectSound Init code
  323. if(SUCCEEDED(hr))
  324. hr = DirectSoundCreate(guid, &data->DS, NULL);
  325. if(SUCCEEDED(hr))
  326. hr = IDirectSound_SetCooperativeLevel(data->DS, GetForegroundWindow(), DSSCL_PRIORITY);
  327. if(FAILED(hr))
  328. {
  329. if(data->DS)
  330. IDirectSound_Release(data->DS);
  331. if(data->NotifyEvent)
  332. CloseHandle(data->NotifyEvent);
  333. free(data);
  334. ERR("Device init failed: 0x%08lx\n", hr);
  335. return ALC_INVALID_VALUE;
  336. }
  337. device->DeviceName = strdup(deviceName);
  338. device->ExtraData = data;
  339. return ALC_NO_ERROR;
  340. }
  341. static void DSoundClosePlayback(ALCdevice *device)
  342. {
  343. DSoundPlaybackData *data = device->ExtraData;
  344. if(data->Notifies)
  345. IDirectSoundNotify_Release(data->Notifies);
  346. data->Notifies = NULL;
  347. if(data->Buffer)
  348. IDirectSoundBuffer_Release(data->Buffer);
  349. data->Buffer = NULL;
  350. if(data->PrimaryBuffer != NULL)
  351. IDirectSoundBuffer_Release(data->PrimaryBuffer);
  352. data->PrimaryBuffer = NULL;
  353. IDirectSound_Release(data->DS);
  354. CloseHandle(data->NotifyEvent);
  355. free(data);
  356. device->ExtraData = NULL;
  357. }
  358. static ALCboolean DSoundResetPlayback(ALCdevice *device)
  359. {
  360. DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
  361. DSBUFFERDESC DSBDescription;
  362. WAVEFORMATEXTENSIBLE OutputType;
  363. DWORD speakers;
  364. HRESULT hr;
  365. memset(&OutputType, 0, sizeof(OutputType));
  366. if(data->Notifies)
  367. IDirectSoundNotify_Release(data->Notifies);
  368. data->Notifies = NULL;
  369. if(data->Buffer)
  370. IDirectSoundBuffer_Release(data->Buffer);
  371. data->Buffer = NULL;
  372. if(data->PrimaryBuffer != NULL)
  373. IDirectSoundBuffer_Release(data->PrimaryBuffer);
  374. data->PrimaryBuffer = NULL;
  375. switch(device->FmtType)
  376. {
  377. case DevFmtByte:
  378. device->FmtType = DevFmtUByte;
  379. break;
  380. case DevFmtFloat:
  381. if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST))
  382. break;
  383. /* fall-through */
  384. case DevFmtUShort:
  385. device->FmtType = DevFmtShort;
  386. break;
  387. case DevFmtUInt:
  388. device->FmtType = DevFmtInt;
  389. break;
  390. case DevFmtUByte:
  391. case DevFmtShort:
  392. case DevFmtInt:
  393. break;
  394. }
  395. hr = IDirectSound_GetSpeakerConfig(data->DS, &speakers);
  396. if(SUCCEEDED(hr))
  397. {
  398. if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
  399. {
  400. speakers = DSSPEAKER_CONFIG(speakers);
  401. if(speakers == DSSPEAKER_MONO)
  402. device->FmtChans = DevFmtMono;
  403. else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
  404. device->FmtChans = DevFmtStereo;
  405. else if(speakers == DSSPEAKER_QUAD)
  406. device->FmtChans = DevFmtQuad;
  407. else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND)
  408. device->FmtChans = DevFmtX51;
  409. else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
  410. device->FmtChans = DevFmtX71;
  411. else
  412. ERR("Unknown system speaker config: 0x%lx\n", speakers);
  413. }
  414. switch(device->FmtChans)
  415. {
  416. case DevFmtMono:
  417. OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  418. break;
  419. case DevFmtStereo:
  420. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  421. SPEAKER_FRONT_RIGHT;
  422. break;
  423. case DevFmtQuad:
  424. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  425. SPEAKER_FRONT_RIGHT |
  426. SPEAKER_BACK_LEFT |
  427. SPEAKER_BACK_RIGHT;
  428. break;
  429. case DevFmtX51:
  430. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  431. SPEAKER_FRONT_RIGHT |
  432. SPEAKER_FRONT_CENTER |
  433. SPEAKER_LOW_FREQUENCY |
  434. SPEAKER_BACK_LEFT |
  435. SPEAKER_BACK_RIGHT;
  436. break;
  437. case DevFmtX51Side:
  438. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  439. SPEAKER_FRONT_RIGHT |
  440. SPEAKER_FRONT_CENTER |
  441. SPEAKER_LOW_FREQUENCY |
  442. SPEAKER_SIDE_LEFT |
  443. SPEAKER_SIDE_RIGHT;
  444. break;
  445. case DevFmtX61:
  446. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  447. SPEAKER_FRONT_RIGHT |
  448. SPEAKER_FRONT_CENTER |
  449. SPEAKER_LOW_FREQUENCY |
  450. SPEAKER_BACK_CENTER |
  451. SPEAKER_SIDE_LEFT |
  452. SPEAKER_SIDE_RIGHT;
  453. break;
  454. case DevFmtX71:
  455. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  456. SPEAKER_FRONT_RIGHT |
  457. SPEAKER_FRONT_CENTER |
  458. SPEAKER_LOW_FREQUENCY |
  459. SPEAKER_BACK_LEFT |
  460. SPEAKER_BACK_RIGHT |
  461. SPEAKER_SIDE_LEFT |
  462. SPEAKER_SIDE_RIGHT;
  463. break;
  464. }
  465. retry_open:
  466. hr = S_OK;
  467. OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  468. OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
  469. OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  470. OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
  471. OutputType.Format.nSamplesPerSec = device->Frequency;
  472. OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
  473. OutputType.Format.cbSize = 0;
  474. }
  475. if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  476. {
  477. OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  478. OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
  479. OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  480. if(device->FmtType == DevFmtFloat)
  481. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  482. else
  483. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  484. if(data->PrimaryBuffer)
  485. IDirectSoundBuffer_Release(data->PrimaryBuffer);
  486. data->PrimaryBuffer = NULL;
  487. }
  488. else
  489. {
  490. if(SUCCEEDED(hr) && !data->PrimaryBuffer)
  491. {
  492. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  493. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  494. DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
  495. hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->PrimaryBuffer, NULL);
  496. }
  497. if(SUCCEEDED(hr))
  498. hr = IDirectSoundBuffer_SetFormat(data->PrimaryBuffer,&OutputType.Format);
  499. }
  500. if(SUCCEEDED(hr))
  501. {
  502. if(device->NumUpdates > MAX_UPDATES)
  503. {
  504. device->UpdateSize = (device->UpdateSize*device->NumUpdates +
  505. MAX_UPDATES-1) / MAX_UPDATES;
  506. device->NumUpdates = MAX_UPDATES;
  507. }
  508. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  509. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  510. DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
  511. DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
  512. OutputType.Format.nBlockAlign;
  513. DSBDescription.lpwfxFormat=&OutputType.Format;
  514. hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->Buffer, NULL);
  515. if(FAILED(hr) && device->FmtType == DevFmtFloat)
  516. {
  517. device->FmtType = DevFmtShort;
  518. goto retry_open;
  519. }
  520. }
  521. if(SUCCEEDED(hr))
  522. {
  523. hr = IDirectSoundBuffer_QueryInterface(data->Buffer, &IID_IDirectSoundNotify, (LPVOID *)&data->Notifies);
  524. if(SUCCEEDED(hr))
  525. {
  526. DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
  527. ALuint i;
  528. for(i = 0;i < device->NumUpdates;++i)
  529. {
  530. notifies[i].dwOffset = i * device->UpdateSize *
  531. OutputType.Format.nBlockAlign;
  532. notifies[i].hEventNotify = data->NotifyEvent;
  533. }
  534. if(IDirectSoundNotify_SetNotificationPositions(data->Notifies, device->NumUpdates, notifies) != DS_OK)
  535. hr = E_FAIL;
  536. }
  537. }
  538. if(FAILED(hr))
  539. {
  540. if(data->Notifies != NULL)
  541. IDirectSoundNotify_Release(data->Notifies);
  542. data->Notifies = NULL;
  543. if(data->Buffer != NULL)
  544. IDirectSoundBuffer_Release(data->Buffer);
  545. data->Buffer = NULL;
  546. if(data->PrimaryBuffer != NULL)
  547. IDirectSoundBuffer_Release(data->PrimaryBuffer);
  548. data->PrimaryBuffer = NULL;
  549. return ALC_FALSE;
  550. }
  551. ResetEvent(data->NotifyEvent);
  552. SetDefaultWFXChannelOrder(device);
  553. return ALC_TRUE;
  554. }
  555. static ALCboolean DSoundStartPlayback(ALCdevice *device)
  556. {
  557. DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
  558. if(!StartThread(&data->thread, DSoundPlaybackProc, device))
  559. return ALC_FALSE;
  560. return ALC_TRUE;
  561. }
  562. static void DSoundStopPlayback(ALCdevice *device)
  563. {
  564. DSoundPlaybackData *data = device->ExtraData;
  565. if(!data->thread)
  566. return;
  567. data->killNow = 1;
  568. StopThread(data->thread);
  569. data->thread = NULL;
  570. data->killNow = 0;
  571. IDirectSoundBuffer_Stop(data->Buffer);
  572. }
  573. static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
  574. {
  575. DSoundCaptureData *data = NULL;
  576. WAVEFORMATEXTENSIBLE InputType;
  577. DSCBUFFERDESC DSCBDescription;
  578. LPGUID guid = NULL;
  579. HRESULT hr, hrcom;
  580. ALuint samples;
  581. if(!CaptureDeviceList)
  582. {
  583. /* Initialize COM to prevent name truncation */
  584. hrcom = CoInitialize(NULL);
  585. hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
  586. if(FAILED(hr))
  587. ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
  588. if(SUCCEEDED(hrcom))
  589. CoUninitialize();
  590. }
  591. if(!deviceName && NumCaptureDevices > 0)
  592. {
  593. deviceName = CaptureDeviceList[0].name;
  594. guid = &CaptureDeviceList[0].guid;
  595. }
  596. else
  597. {
  598. ALuint i;
  599. for(i = 0;i < NumCaptureDevices;i++)
  600. {
  601. if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
  602. {
  603. guid = &CaptureDeviceList[i].guid;
  604. break;
  605. }
  606. }
  607. if(i == NumCaptureDevices)
  608. return ALC_INVALID_VALUE;
  609. }
  610. switch(device->FmtType)
  611. {
  612. case DevFmtByte:
  613. case DevFmtUShort:
  614. case DevFmtUInt:
  615. WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
  616. return ALC_INVALID_ENUM;
  617. case DevFmtUByte:
  618. case DevFmtShort:
  619. case DevFmtInt:
  620. case DevFmtFloat:
  621. break;
  622. }
  623. //Initialise requested device
  624. data = calloc(1, sizeof(DSoundCaptureData));
  625. if(!data)
  626. return ALC_OUT_OF_MEMORY;
  627. hr = DS_OK;
  628. //DirectSoundCapture Init code
  629. if(SUCCEEDED(hr))
  630. hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL);
  631. if(SUCCEEDED(hr))
  632. {
  633. memset(&InputType, 0, sizeof(InputType));
  634. switch(device->FmtChans)
  635. {
  636. case DevFmtMono:
  637. InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  638. break;
  639. case DevFmtStereo:
  640. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  641. SPEAKER_FRONT_RIGHT;
  642. break;
  643. case DevFmtQuad:
  644. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  645. SPEAKER_FRONT_RIGHT |
  646. SPEAKER_BACK_LEFT |
  647. SPEAKER_BACK_RIGHT;
  648. break;
  649. case DevFmtX51:
  650. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  651. SPEAKER_FRONT_RIGHT |
  652. SPEAKER_FRONT_CENTER |
  653. SPEAKER_LOW_FREQUENCY |
  654. SPEAKER_BACK_LEFT |
  655. SPEAKER_BACK_RIGHT;
  656. break;
  657. case DevFmtX51Side:
  658. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  659. SPEAKER_FRONT_RIGHT |
  660. SPEAKER_FRONT_CENTER |
  661. SPEAKER_LOW_FREQUENCY |
  662. SPEAKER_SIDE_LEFT |
  663. SPEAKER_SIDE_RIGHT;
  664. break;
  665. case DevFmtX61:
  666. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  667. SPEAKER_FRONT_RIGHT |
  668. SPEAKER_FRONT_CENTER |
  669. SPEAKER_LOW_FREQUENCY |
  670. SPEAKER_BACK_CENTER |
  671. SPEAKER_SIDE_LEFT |
  672. SPEAKER_SIDE_RIGHT;
  673. break;
  674. case DevFmtX71:
  675. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  676. SPEAKER_FRONT_RIGHT |
  677. SPEAKER_FRONT_CENTER |
  678. SPEAKER_LOW_FREQUENCY |
  679. SPEAKER_BACK_LEFT |
  680. SPEAKER_BACK_RIGHT |
  681. SPEAKER_SIDE_LEFT |
  682. SPEAKER_SIDE_RIGHT;
  683. break;
  684. }
  685. InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  686. InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
  687. InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  688. InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
  689. InputType.Format.nSamplesPerSec = device->Frequency;
  690. InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
  691. InputType.Format.cbSize = 0;
  692. if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  693. {
  694. InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  695. InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  696. InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
  697. if(device->FmtType == DevFmtFloat)
  698. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  699. else
  700. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  701. }
  702. samples = device->UpdateSize * device->NumUpdates;
  703. samples = maxu(samples, 100 * device->Frequency / 1000);
  704. memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
  705. DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
  706. DSCBDescription.dwFlags = 0;
  707. DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
  708. DSCBDescription.lpwfxFormat = &InputType.Format;
  709. hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL);
  710. }
  711. if(SUCCEEDED(hr))
  712. {
  713. data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
  714. if(data->Ring == NULL)
  715. hr = DSERR_OUTOFMEMORY;
  716. }
  717. if(FAILED(hr))
  718. {
  719. ERR("Device init failed: 0x%08lx\n", hr);
  720. DestroyRingBuffer(data->Ring);
  721. data->Ring = NULL;
  722. if(data->DSCbuffer != NULL)
  723. IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
  724. data->DSCbuffer = NULL;
  725. if(data->DSC)
  726. IDirectSoundCapture_Release(data->DSC);
  727. data->DSC = NULL;
  728. free(data);
  729. return ALC_INVALID_VALUE;
  730. }
  731. data->BufferBytes = DSCBDescription.dwBufferBytes;
  732. SetDefaultWFXChannelOrder(device);
  733. device->DeviceName = strdup(deviceName);
  734. device->ExtraData = data;
  735. return ALC_NO_ERROR;
  736. }
  737. static void DSoundCloseCapture(ALCdevice *device)
  738. {
  739. DSoundCaptureData *data = device->ExtraData;
  740. DestroyRingBuffer(data->Ring);
  741. data->Ring = NULL;
  742. if(data->DSCbuffer != NULL)
  743. {
  744. IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
  745. IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
  746. data->DSCbuffer = NULL;
  747. }
  748. IDirectSoundCapture_Release(data->DSC);
  749. data->DSC = NULL;
  750. free(data);
  751. device->ExtraData = NULL;
  752. }
  753. static void DSoundStartCapture(ALCdevice *device)
  754. {
  755. DSoundCaptureData *data = device->ExtraData;
  756. HRESULT hr;
  757. hr = IDirectSoundCaptureBuffer_Start(data->DSCbuffer, DSCBSTART_LOOPING);
  758. if(FAILED(hr))
  759. {
  760. ERR("start failed: 0x%08lx\n", hr);
  761. aluHandleDisconnect(device);
  762. }
  763. }
  764. static void DSoundStopCapture(ALCdevice *device)
  765. {
  766. DSoundCaptureData *data = device->ExtraData;
  767. HRESULT hr;
  768. hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer);
  769. if(FAILED(hr))
  770. {
  771. ERR("stop failed: 0x%08lx\n", hr);
  772. aluHandleDisconnect(device);
  773. }
  774. }
  775. static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
  776. {
  777. DSoundCaptureData *data = Device->ExtraData;
  778. ReadRingBuffer(data->Ring, pBuffer, lSamples);
  779. return ALC_NO_ERROR;
  780. }
  781. static ALCuint DSoundAvailableSamples(ALCdevice *Device)
  782. {
  783. DSoundCaptureData *data = Device->ExtraData;
  784. DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
  785. VOID *ReadPtr1, *ReadPtr2;
  786. DWORD ReadCnt1, ReadCnt2;
  787. DWORD FrameSize;
  788. HRESULT hr;
  789. if(!Device->Connected)
  790. goto done;
  791. FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
  792. BufferBytes = data->BufferBytes;
  793. LastCursor = data->Cursor;
  794. hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor);
  795. if(SUCCEEDED(hr))
  796. {
  797. NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
  798. if(NumBytes == 0)
  799. goto done;
  800. hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes,
  801. &ReadPtr1, &ReadCnt1,
  802. &ReadPtr2, &ReadCnt2, 0);
  803. }
  804. if(SUCCEEDED(hr))
  805. {
  806. WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize);
  807. if(ReadPtr2 != NULL)
  808. WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize);
  809. hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer,
  810. ReadPtr1, ReadCnt1,
  811. ReadPtr2, ReadCnt2);
  812. data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
  813. }
  814. if(FAILED(hr))
  815. {
  816. ERR("update failed: 0x%08lx\n", hr);
  817. aluHandleDisconnect(Device);
  818. }
  819. done:
  820. return RingBufferSize(data->Ring);
  821. }
  822. static const BackendFuncs DSoundFuncs = {
  823. DSoundOpenPlayback,
  824. DSoundClosePlayback,
  825. DSoundResetPlayback,
  826. DSoundStartPlayback,
  827. DSoundStopPlayback,
  828. DSoundOpenCapture,
  829. DSoundCloseCapture,
  830. DSoundStartCapture,
  831. DSoundStopCapture,
  832. DSoundCaptureSamples,
  833. DSoundAvailableSamples,
  834. ALCdevice_GetLatencyDefault
  835. };
  836. ALCboolean alcDSoundInit(BackendFuncs *FuncList)
  837. {
  838. if(!DSoundLoad())
  839. return ALC_FALSE;
  840. *FuncList = DSoundFuncs;
  841. return ALC_TRUE;
  842. }
  843. void alcDSoundDeinit(void)
  844. {
  845. ALuint i;
  846. for(i = 0;i < NumPlaybackDevices;++i)
  847. free(PlaybackDeviceList[i].name);
  848. free(PlaybackDeviceList);
  849. PlaybackDeviceList = NULL;
  850. NumPlaybackDevices = 0;
  851. for(i = 0;i < NumCaptureDevices;++i)
  852. free(CaptureDeviceList[i].name);
  853. free(CaptureDeviceList);
  854. CaptureDeviceList = NULL;
  855. NumCaptureDevices = 0;
  856. if(ds_handle)
  857. CloseLib(ds_handle);
  858. ds_handle = NULL;
  859. }
  860. void alcDSoundProbe(enum DevProbe type)
  861. {
  862. HRESULT hr, hrcom;
  863. ALuint i;
  864. switch(type)
  865. {
  866. case ALL_DEVICE_PROBE:
  867. for(i = 0;i < NumPlaybackDevices;++i)
  868. free(PlaybackDeviceList[i].name);
  869. free(PlaybackDeviceList);
  870. PlaybackDeviceList = NULL;
  871. NumPlaybackDevices = 0;
  872. hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
  873. if(FAILED(hr))
  874. ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
  875. else
  876. {
  877. for(i = 0;i < NumPlaybackDevices;i++)
  878. AppendAllDevicesList(PlaybackDeviceList[i].name);
  879. }
  880. break;
  881. case CAPTURE_DEVICE_PROBE:
  882. for(i = 0;i < NumCaptureDevices;++i)
  883. free(CaptureDeviceList[i].name);
  884. free(CaptureDeviceList);
  885. CaptureDeviceList = NULL;
  886. NumCaptureDevices = 0;
  887. /* Initialize COM to prevent name truncation */
  888. hrcom = CoInitialize(NULL);
  889. hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
  890. if(FAILED(hr))
  891. ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
  892. else
  893. {
  894. for(i = 0;i < NumCaptureDevices;i++)
  895. AppendCaptureDeviceList(CaptureDeviceList[i].name);
  896. }
  897. if(SUCCEEDED(hrcom))
  898. CoUninitialize();
  899. break;
  900. }
  901. }