zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_xaudio2.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "SDL_config.h"
22 
23 #if SDL_AUDIO_DRIVER_XAUDIO2
24 
25 #include "../../core/windows/SDL_windows.h"
26 #include "SDL_audio.h"
27 #include "../SDL_audio_c.h"
28 #include "../SDL_sysaudio.h"
29 #include "SDL_assert.h"
30 
31 #ifdef __GNUC__
32 /* The configure script already did any necessary checking */
33 # define SDL_XAUDIO2_HAS_SDK 1
34 #else
35 #include <dxsdkver.h> /* XAudio2 exists as of the March 2008 DirectX SDK */
36 #if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
37 # pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
38 #else
39 # define SDL_XAUDIO2_HAS_SDK 1
40 #endif
41 #endif /* __GNUC__ */
42 
43 #ifdef SDL_XAUDIO2_HAS_SDK
44 
45 #define INITGUID 1
46 #include <xaudio2.h>
47 
48 /* Hidden "this" pointer for the audio functions */
49 #define _THIS SDL_AudioDevice *this
50 
52 {
53  IXAudio2 *ixa2;
54  IXAudio2SourceVoice *source;
55  IXAudio2MasteringVoice *mastering;
56  HANDLE semaphore;
57  Uint8 *mixbuf;
58  int mixlen;
59  Uint8 *nextbuf;
60 };
61 
62 
63 static void
64 XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
65 {
66  IXAudio2 *ixa2 = NULL;
67  UINT32 devcount = 0;
68  UINT32 i = 0;
69 
70  if (iscapture) {
71  SDL_SetError("XAudio2: capture devices unsupported.");
72  return;
73  } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
74  SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
75  return;
76  } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
77  SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
78  IXAudio2_Release(ixa2);
79  return;
80  }
81 
82  for (i = 0; i < devcount; i++) {
83  XAUDIO2_DEVICE_DETAILS details;
84  if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
85  char *str = WIN_StringToUTF8(details.DisplayName);
86  if (str != NULL) {
87  addfn(str);
88  SDL_free(str); /* addfn() made a copy of the string. */
89  }
90  }
91  }
92 
93  IXAudio2_Release(ixa2);
94 }
95 
96 static void STDMETHODCALLTYPE
97 VoiceCBOnBufferEnd(THIS_ void *data)
98 {
99  /* Just signal the SDL audio thread and get out of XAudio2's way. */
100  SDL_AudioDevice *this = (SDL_AudioDevice *) data;
101  ReleaseSemaphore(this->hidden->semaphore, 1, NULL);
102 }
103 
104 static void STDMETHODCALLTYPE
105 VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
106 {
107  /* !!! FIXME: attempt to recover, or mark device disconnected. */
108  SDL_assert(0 && "write me!");
109 }
110 
111 /* no-op callbacks... */
112 static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {}
113 static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {}
114 static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
115 static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
116 static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
117 
118 
119 static Uint8 *
120 XAUDIO2_GetDeviceBuf(_THIS)
121 {
122  return this->hidden->nextbuf;
123 }
124 
125 static void
126 XAUDIO2_PlayDevice(_THIS)
127 {
129  Uint8 *mixbuf = this->hidden->mixbuf;
130  Uint8 *nextbuf = this->hidden->nextbuf;
131  const int mixlen = this->hidden->mixlen;
132  IXAudio2SourceVoice *source = this->hidden->source;
133  HRESULT result = S_OK;
134 
135  if (!this->enabled) { /* shutting down? */
136  return;
137  }
138 
139  /* Submit the next filled buffer */
140  SDL_zero(buffer);
141  buffer.AudioBytes = mixlen;
142  buffer.pAudioData = nextbuf;
143  buffer.pContext = this;
144 
145  if (nextbuf == mixbuf) {
146  nextbuf += mixlen;
147  } else {
148  nextbuf = mixbuf;
149  }
150  this->hidden->nextbuf = nextbuf;
151 
152  result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL);
153  if (result == XAUDIO2_E_DEVICE_INVALIDATED) {
154  /* !!! FIXME: possibly disconnected or temporary lost. Recover? */
155  }
156 
157  if (result != S_OK) { /* uhoh, panic! */
159  this->enabled = 0;
160  }
161 }
162 
163 static void
164 XAUDIO2_WaitDevice(_THIS)
165 {
166  if (this->enabled) {
167  WaitForSingleObject(this->hidden->semaphore, INFINITE);
168  }
169 }
170 
171 static void
172 XAUDIO2_WaitDone(_THIS)
173 {
174  IXAudio2SourceVoice *source = this->hidden->source;
175  XAUDIO2_VOICE_STATE state;
176  SDL_assert(!this->enabled); /* flag that stops playing. */
178  IXAudio2SourceVoice_GetState(source, &state);
179  while (state.BuffersQueued > 0) {
180  WaitForSingleObject(this->hidden->semaphore, INFINITE);
181  IXAudio2SourceVoice_GetState(source, &state);
182  }
183 }
184 
185 
186 static void
187 XAUDIO2_CloseDevice(_THIS)
188 {
189  if (this->hidden != NULL) {
190  IXAudio2 *ixa2 = this->hidden->ixa2;
191  IXAudio2SourceVoice *source = this->hidden->source;
192  IXAudio2MasteringVoice *mastering = this->hidden->mastering;
193 
194  if (source != NULL) {
198  }
199  if (ixa2 != NULL) {
200  IXAudio2_StopEngine(ixa2);
201  }
202  if (mastering != NULL) {
204  }
205  if (ixa2 != NULL) {
206  IXAudio2_Release(ixa2);
207  }
208  SDL_free(this->hidden->mixbuf);
209  if (this->hidden->semaphore != NULL) {
210  CloseHandle(this->hidden->semaphore);
211  }
212 
213  SDL_free(this->hidden);
214  this->hidden = NULL;
215  }
216 }
217 
218 static int
219 XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
220 {
221  HRESULT result = S_OK;
222  WAVEFORMATEX waveformat;
223  int valid_format = 0;
224  SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
225  IXAudio2 *ixa2 = NULL;
226  IXAudio2SourceVoice *source = NULL;
227  UINT32 devId = 0; /* 0 == system default device. */
228 
229  static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
230  VoiceCBOnVoiceProcessPassStart,
231  VoiceCBOnVoiceProcessPassEnd,
232  VoiceCBOnStreamEnd,
233  VoiceCBOnBufferStart,
234  VoiceCBOnBufferEnd,
235  VoiceCBOnLoopEnd,
236  VoiceCBOnVoiceError
237  };
238 
239  static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
240 
241  if (iscapture) {
242  return SDL_SetError("XAudio2: capture devices unsupported.");
243  } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
244  return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
245  }
246 
247  if (devname != NULL) {
248  UINT32 devcount = 0;
249  UINT32 i = 0;
250 
251  if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
252  IXAudio2_Release(ixa2);
253  return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed.");
254  }
255  for (i = 0; i < devcount; i++) {
256  XAUDIO2_DEVICE_DETAILS details;
257  if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
258  char *str = WIN_StringToUTF8(details.DisplayName);
259  if (str != NULL) {
260  const int match = (SDL_strcmp(str, devname) == 0);
261  SDL_free(str);
262  if (match) {
263  devId = i;
264  break;
265  }
266  }
267  }
268  }
269 
270  if (i == devcount) {
271  IXAudio2_Release(ixa2);
272  return SDL_SetError("XAudio2: Requested device not found.");
273  }
274  }
275 
276  /* Initialize all variables that we clean on shutdown */
277  this->hidden = (struct SDL_PrivateAudioData *)
278  SDL_malloc((sizeof *this->hidden));
279  if (this->hidden == NULL) {
280  IXAudio2_Release(ixa2);
281  return SDL_OutOfMemory();
282  }
283  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
284 
285  this->hidden->ixa2 = ixa2;
286  this->hidden->semaphore = CreateSemaphore(NULL, 1, 2, NULL);
287  if (this->hidden->semaphore == NULL) {
288  XAUDIO2_CloseDevice(this);
289  return SDL_SetError("XAudio2: CreateSemaphore() failed!");
290  }
291 
292  while ((!valid_format) && (test_format)) {
293  switch (test_format) {
294  case AUDIO_U8:
295  case AUDIO_S16:
296  case AUDIO_S32:
297  case AUDIO_F32:
298  this->spec.format = test_format;
299  valid_format = 1;
300  break;
301  }
302  test_format = SDL_NextAudioFormat();
303  }
304 
305  if (!valid_format) {
306  XAUDIO2_CloseDevice(this);
307  return SDL_SetError("XAudio2: Unsupported audio format");
308  }
309 
310  /* Update the fragment size as size in bytes */
311  SDL_CalculateAudioSpec(&this->spec);
312 
313  /* We feed a Source, it feeds the Mastering, which feeds the device. */
314  this->hidden->mixlen = this->spec.size;
315  this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
316  if (this->hidden->mixbuf == NULL) {
317  XAUDIO2_CloseDevice(this);
318  return SDL_OutOfMemory();
319  }
320  this->hidden->nextbuf = this->hidden->mixbuf;
321  SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
322 
323  /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
324  Xbox360, this means 5.1 output, but on Windows, it means "figure out
325  what the system has." It might be preferable to let XAudio2 blast
326  stereo output to appropriate surround sound configurations
327  instead of clamping to 2 channels, even though we'll configure the
328  Source Voice for whatever number of channels you supply. */
329  result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
331  this->spec.freq, 0, devId, NULL);
332  if (result != S_OK) {
333  XAUDIO2_CloseDevice(this);
334  return SDL_SetError("XAudio2: Couldn't create mastering voice");
335  }
336 
337  SDL_zero(waveformat);
338  if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
339  waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
340  } else {
341  waveformat.wFormatTag = WAVE_FORMAT_PCM;
342  }
343  waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
344  waveformat.nChannels = this->spec.channels;
345  waveformat.nSamplesPerSec = this->spec.freq;
346  waveformat.nBlockAlign =
347  waveformat.nChannels * (waveformat.wBitsPerSample / 8);
348  waveformat.nAvgBytesPerSec =
349  waveformat.nSamplesPerSec * waveformat.nBlockAlign;
350 
351  result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
354  1.0f, &callbacks, NULL, NULL);
355  if (result != S_OK) {
356  XAUDIO2_CloseDevice(this);
357  return SDL_SetError("XAudio2: Couldn't create source voice");
358  }
359  this->hidden->source = source;
360 
361  /* Start everything playing! */
362  result = IXAudio2_StartEngine(ixa2);
363  if (result != S_OK) {
364  XAUDIO2_CloseDevice(this);
365  return SDL_SetError("XAudio2: Couldn't start engine");
366  }
367 
368  result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
369  if (result != S_OK) {
370  XAUDIO2_CloseDevice(this);
371  return SDL_SetError("XAudio2: Couldn't start source voice");
372  }
373 
374  return 0; /* good to go. */
375 }
376 
377 static void
378 XAUDIO2_Deinitialize(void)
379 {
381 }
382 
383 #endif /* SDL_XAUDIO2_HAS_SDK */
384 
385 
386 static int
387 XAUDIO2_Init(SDL_AudioDriverImpl * impl)
388 {
389 #ifndef SDL_XAUDIO2_HAS_SDK
390  SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK).");
391  return 0; /* no XAudio2 support, ever. Update your SDK! */
392 #else
393  /* XAudio2Create() is a macro that uses COM; we don't load the .dll */
394  IXAudio2 *ixa2 = NULL;
395  if (FAILED(WIN_CoInitialize())) {
396  SDL_SetError("XAudio2: CoInitialize() failed");
397  return 0;
398  }
399 
400  if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
402  SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
403  return 0; /* not available. */
404  }
405  IXAudio2_Release(ixa2);
406 
407  /* Set the function pointers */
408  impl->DetectDevices = XAUDIO2_DetectDevices;
409  impl->OpenDevice = XAUDIO2_OpenDevice;
410  impl->PlayDevice = XAUDIO2_PlayDevice;
411  impl->WaitDevice = XAUDIO2_WaitDevice;
412  impl->WaitDone = XAUDIO2_WaitDone;
413  impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
414  impl->CloseDevice = XAUDIO2_CloseDevice;
415  impl->Deinitialize = XAUDIO2_Deinitialize;
416 
417  return 1; /* this audio target is available. */
418 #endif
419 }
420 
422  "xaudio2", "XAudio2", XAUDIO2_Init, 0
423 };
424 
425 #endif /* SDL_AUDIO_DRIVER_XAUDIO2 */
426 
427 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
void * pContext
Definition: XAudio2.h:317
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
WORD nChannels
Definition: audiodefs.h:43
void(* SDL_AddAudioDevice)(const char *name)
Definition: SDL_sysaudio.h:34
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
GLclampf f
Definition: glew.h:3390
typedef HRESULT(WINAPI *LPD3DXIMTSIGNALCALLBACK)(CONST D3DXVECTOR2 *uv
#define IXAudio2_StopEngine(This)
Definition: XAudio2.h:1037
DWORD nAvgBytesPerSec
Definition: audiodefs.h:45
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define IXAudio2SourceVoice_Discontinuity(This)
Definition: XAudio2.h:1087
#define IXAudio2SourceVoice_FlushSourceBuffers(This)
Definition: XAudio2.h:1086
DECLSPEC void SDLCALL SDL_free(void *mem)
#define IXAudio2SourceVoice_GetState(This, pVoiceState)
Definition: XAudio2.h:1089
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
void(* WaitDone)(_THIS)
Definition: SDL_sysaudio.h:44
#define IXAudio2_GetDeviceCount(This, puCount)
Definition: XAudio2.h:1030
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
UINT32 AudioBytes
Definition: XAudio2.h:307
#define IXAudio2_StartEngine(This)
Definition: XAudio2.h:1036
#define IXAudio2_Release(This)
Definition: XAudio2.h:1029
#define IXAudio2_CreateSourceVoice(This, ppSourceVoice, pSourceFormat, Flags, MaxFrequencyRatio, pCallback, pSendList, pEffectChain)
Definition: XAudio2.h:1033
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
#define XAUDIO2_DEFAULT_CHANNELS
Definition: XAudio2.h:107
EGLContext EGLenum EGLClientBuffer buffer
Definition: eglext.h:87
#define AUDIO_U8
Definition: SDL_audio.h:89
void(* DetectDevices)(int iscapture, SDL_AddAudioDevice addfn)
Definition: SDL_sysaudio.h:38
UINT32 BuffersQueued
Definition: XAudio2.h:343
#define IXAudio2_CreateMasteringVoice(This, ppMasteringVoice, InputChannels, InputSampleRate, Flags, DeviceIndex, pEffectChain)
Definition: XAudio2.h:1035
__inline HRESULT XAudio2Create(__deref_out IXAudio2 **ppXAudio2, UINT32 Flags X2DEFAULT(0), XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR))
Definition: XAudio2.h:1228
GLuint64EXT * result
Definition: glew.h:12708
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
HRESULT WIN_CoInitialize(void)
#define _THIS
#define IXAudio2SourceVoice_Start(This, Flags, OperationSet)
Definition: XAudio2.h:1083
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
#define AUDIO_S32
Definition: SDL_audio.h:105
#define XAUDIO2_COMMIT_NOW
Definition: XAudio2.h:102
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
#define IXAudio2SourceVoice_DestroyVoice
Definition: XAudio2.h:1082
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:41
WORD nBlockAlign
Definition: audiodefs.h:46
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:48
#define XAUDIO2_E_DEVICE_INVALIDATED
Definition: XAudio2.h:140
#define WAVE_FORMAT_PCM
Definition: makehrtf.c:177
DWORD nSamplesPerSec
Definition: audiodefs.h:44
#define IXAudio2_GetDeviceDetails(This, Index, pDeviceDetails)
Definition: XAudio2.h:1031
#define SDL_assert(condition)
Definition: SDL_assert.h:159
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
void WIN_CoUninitialize(void)
#define WAVE_FORMAT_IEEE_FLOAT
Definition: winmm.c:34
WCHAR DisplayName[256]
Definition: XAudio2.h:241
WORD wBitsPerSample
Definition: audiodefs.h:47
#define XAUDIO2_VOICE_NOPITCH
Definition: XAudio2.h:112
#define IXAudio2SourceVoice_SubmitSourceBuffer(This, pBuffer, pBufferWMA)
Definition: XAudio2.h:1085
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
WORD wFormatTag
Definition: audiodefs.h:42
#define IXAudio2SourceVoice_Stop(This, Flags, OperationSet)
Definition: XAudio2.h:1084
AudioBootStrap XAUDIO2_bootstrap
#define AUDIO_S16
Definition: SDL_audio.h:96
GLdouble GLdouble GLdouble b
Definition: glew.h:8383
const BYTE * pAudioData
Definition: XAudio2.h:308
#define str(s)
#define SDL_zero(x)
Definition: SDL_stdinc.h:254
#define AUDIO_F32
Definition: SDL_audio.h:114
#define XAUDIO2_VOICE_NOSRC
Definition: XAudio2.h:113
int i
Definition: pngrutil.c:1377
GLsizei GLsizei GLchar * source
Definition: gl2ext.h:994
#define IXAudio2MasteringVoice_DestroyVoice
Definition: XAudio2.h:1134