src/audio/xaudio2/SDL_xaudio2.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10737 3406a0f8b041
child 10877 3366ca004d17
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
slouken@8582
     1
/*
slouken@8582
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@8582
     4
slouken@8582
     5
  This software is provided 'as-is', without any express or implied
slouken@8582
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@8582
     7
  arising from the use of this software.
slouken@8582
     8
slouken@8582
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@8582
    10
  including commercial applications, and to alter it and redistribute it
slouken@8582
    11
  freely, subject to the following restrictions:
slouken@8582
    12
slouken@8582
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@8582
    14
     claim that you wrote the original software. If you use this software
slouken@8582
    15
     in a product, an acknowledgment in the product documentation would be
slouken@8582
    16
     appreciated but is not required.
slouken@8582
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@8582
    18
     misrepresented as being the original software.
slouken@8582
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@8582
    20
*/
slouken@8582
    21
slouken@8582
    22
/* WinRT NOTICE:
slouken@8582
    23
slouken@8582
    24
   A few changes to SDL's XAudio2 backend were warranted by API
slouken@8582
    25
   changes to Windows.  Many, but not all of these are documented by Microsoft
slouken@8582
    26
   at:
slouken@8582
    27
   http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
slouken@8582
    28
slouken@8582
    29
   1. Windows' thread synchronization function, CreateSemaphore, was removed
slouken@8582
    30
      from WinRT.  SDL's semaphore API was substituted instead.
slouken@8582
    31
   2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails
slouken@8582
    32
      were removed from the XAudio2 API.  Microsoft is telling developers to
slouken@8582
    33
      use APIs in Windows::Foundation instead.
slouken@8582
    34
      For SDL, the missing methods were reimplemented using the APIs Microsoft
slouken@8582
    35
      said to use.
slouken@8582
    36
   3. CoInitialize and CoUninitialize are not available in WinRT.
slouken@8582
    37
      These calls were removed, as COM will have been initialized earlier,
slouken@8582
    38
      at least by the call to the WinRT app's main function
slouken@8582
    39
      (aka 'int main(Platform::Array<Platform::String^>^)).  (DLudwig:
slouken@8582
    40
      This was my understanding of how WinRT: the 'main' function uses
slouken@8582
    41
      a tag of [MTAThread], which should initialize COM.  My understanding
slouken@8582
    42
      of COM is somewhat limited, and I may be incorrect here.)
slouken@8582
    43
   4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex'
slouken@8582
    44
      argument to a string-based one, 'szDeviceId'.  In WinRT, the
slouken@8582
    45
      string-based argument will be used.
slouken@8582
    46
*/
icculus@8093
    47
#include "../../SDL_internal.h"
slouken@8582
    48
slouken@8582
    49
#if SDL_AUDIO_DRIVER_XAUDIO2
slouken@8582
    50
slouken@8582
    51
#include "../../core/windows/SDL_windows.h"
slouken@8582
    52
#include "SDL_audio.h"
slouken@8582
    53
#include "../SDL_audio_c.h"
slouken@8582
    54
#include "../SDL_sysaudio.h"
slouken@8582
    55
#include "SDL_assert.h"
slouken@8582
    56
slouken@8582
    57
#ifdef __GNUC__
slouken@8582
    58
/* The configure script already did any necessary checking */
slouken@8582
    59
#  define SDL_XAUDIO2_HAS_SDK 1
slouken@8582
    60
#elif defined(__WINRT__)
dludwig@9931
    61
/* WinRT always has access to the XAudio 2 SDK (albeit with a header file
dludwig@9931
    62
   that doesn't compile as C code).
dludwig@9931
    63
*/
slouken@8582
    64
#  define SDL_XAUDIO2_HAS_SDK
dludwig@9931
    65
#include "SDL_xaudio2.h"    /* ... compiles as C code, in contrast to XAudio2 headers
dludwig@9931
    66
                               in the Windows SDK, v.10.0.10240.0 (Win 10's initial SDK)
dludwig@9931
    67
                             */
slouken@8582
    68
#else
slouken@9963
    69
/* XAudio2 exists in the last DirectX SDK as well as the latest Windows SDK.
slouken@9963
    70
   To enable XAudio2 support, you will need to add the location of your DirectX SDK headers to
slouken@9963
    71
   the SDL projects additional include directories and then set SDL_XAUDIO2_HAS_SDK=1 as a
slouken@9963
    72
   preprocessor define
slouken@8582
    73
 */
alfred@9778
    74
#if 0 /* See comment above */
slouken@8582
    75
#include <dxsdkver.h>
slouken@8582
    76
#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
slouken@8582
    77
#  pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
slouken@8582
    78
#else
slouken@8582
    79
#  define SDL_XAUDIO2_HAS_SDK 1
slouken@8582
    80
#endif
alfred@9778
    81
#endif /* 0 */
slouken@10734
    82
#endif /* __GNUC__ */
slouken@8582
    83
slouken@8582
    84
#ifdef SDL_XAUDIO2_HAS_SDK
slouken@8582
    85
slouken@8582
    86
/* Check to see if we're compiling for XAudio 2.8, or higher. */
slouken@8582
    87
#ifdef WINVER
slouken@8582
    88
#if WINVER >= 0x0602  /* Windows 8 SDK or higher? */
slouken@8582
    89
#define SDL_XAUDIO2_WIN8 1
slouken@8582
    90
#endif
slouken@8582
    91
#endif
slouken@8582
    92
dludwig@9931
    93
#if !defined(_SDL_XAUDIO2_H)
slouken@8582
    94
#define INITGUID 1
slouken@8582
    95
#include <xaudio2.h>
dludwig@9931
    96
#endif
slouken@8582
    97
slouken@8582
    98
/* Hidden "this" pointer for the audio functions */
slouken@8582
    99
#define _THIS   SDL_AudioDevice *this
slouken@8582
   100
slouken@8582
   101
#ifdef __WINRT__
slouken@8582
   102
#include "SDL_xaudio2_winrthelpers.h"
slouken@8582
   103
#endif
slouken@8582
   104
slouken@8582
   105
/* Fixes bug 1210 where some versions of gcc need named parameters */
slouken@8582
   106
#ifdef __GNUC__
slouken@8582
   107
#ifdef THIS
slouken@8582
   108
#undef THIS
slouken@8582
   109
#endif
slouken@8582
   110
#define THIS    INTERFACE *p
slouken@8582
   111
#ifdef THIS_
slouken@8582
   112
#undef THIS_
slouken@8582
   113
#endif
slouken@8582
   114
#define THIS_   INTERFACE *p,
slouken@8582
   115
#endif
slouken@8582
   116
slouken@8582
   117
struct SDL_PrivateAudioData
slouken@8582
   118
{
slouken@8582
   119
    IXAudio2 *ixa2;
slouken@8582
   120
    IXAudio2SourceVoice *source;
slouken@8582
   121
    IXAudio2MasteringVoice *mastering;
slouken@8582
   122
    SDL_sem * semaphore;
slouken@8582
   123
    Uint8 *mixbuf;
slouken@8582
   124
    int mixlen;
slouken@8582
   125
    Uint8 *nextbuf;
slouken@8582
   126
};
slouken@8582
   127
slouken@8582
   128
slouken@8582
   129
static void
icculus@9394
   130
XAUDIO2_DetectDevices(void)
slouken@8582
   131
{
slouken@8582
   132
    IXAudio2 *ixa2 = NULL;
slouken@8582
   133
    UINT32 devcount = 0;
slouken@8582
   134
    UINT32 i = 0;
slouken@8582
   135
icculus@9394
   136
    if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
slouken@8582
   137
        SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
slouken@8582
   138
        return;
slouken@8582
   139
    } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
slouken@8582
   140
        SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
slouken@8582
   141
        IXAudio2_Release(ixa2);
slouken@8582
   142
        return;
slouken@8582
   143
    }
slouken@8582
   144
slouken@8582
   145
    for (i = 0; i < devcount; i++) {
slouken@8582
   146
        XAUDIO2_DEVICE_DETAILS details;
slouken@8582
   147
        if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
slouken@8582
   148
            char *str = WIN_StringToUTF8(details.DisplayName);
slouken@8582
   149
            if (str != NULL) {
icculus@9410
   150
                SDL_AddAudioDevice(SDL_FALSE, str, (void *) ((size_t) i+1));
icculus@9394
   151
                SDL_free(str);  /* SDL_AddAudioDevice made a copy of the string. */
slouken@8582
   152
            }
slouken@8582
   153
        }
slouken@8582
   154
    }
slouken@8582
   155
slouken@8582
   156
    IXAudio2_Release(ixa2);
slouken@8582
   157
}
slouken@8582
   158
slouken@8582
   159
static void STDMETHODCALLTYPE
slouken@8582
   160
VoiceCBOnBufferEnd(THIS_ void *data)
slouken@8582
   161
{
slouken@8582
   162
    /* Just signal the SDL audio thread and get out of XAudio2's way. */
slouken@8582
   163
    SDL_AudioDevice *this = (SDL_AudioDevice *) data;
slouken@8582
   164
    SDL_SemPost(this->hidden->semaphore);
slouken@8582
   165
}
slouken@8582
   166
slouken@8582
   167
static void STDMETHODCALLTYPE
slouken@8582
   168
VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
slouken@8582
   169
{
icculus@9394
   170
    SDL_AudioDevice *this = (SDL_AudioDevice *) data;
icculus@9394
   171
    SDL_OpenedAudioDeviceDisconnected(this);
slouken@8582
   172
}
slouken@8582
   173
slouken@8582
   174
/* no-op callbacks... */
slouken@8582
   175
static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {}
slouken@8582
   176
static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {}
slouken@8582
   177
static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
slouken@8582
   178
static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
slouken@8582
   179
static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
slouken@8582
   180
slouken@8582
   181
slouken@8582
   182
static Uint8 *
slouken@8582
   183
XAUDIO2_GetDeviceBuf(_THIS)
slouken@8582
   184
{
slouken@8582
   185
    return this->hidden->nextbuf;
slouken@8582
   186
}
slouken@8582
   187
slouken@8582
   188
static void
slouken@8582
   189
XAUDIO2_PlayDevice(_THIS)
slouken@8582
   190
{
slouken@8582
   191
    XAUDIO2_BUFFER buffer;
slouken@8582
   192
    Uint8 *mixbuf = this->hidden->mixbuf;
slouken@8582
   193
    Uint8 *nextbuf = this->hidden->nextbuf;
slouken@8582
   194
    const int mixlen = this->hidden->mixlen;
slouken@8582
   195
    IXAudio2SourceVoice *source = this->hidden->source;
slouken@8582
   196
    HRESULT result = S_OK;
slouken@8582
   197
icculus@10238
   198
    if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */
slouken@8582
   199
        return;
slouken@8582
   200
    }
slouken@8582
   201
slouken@8582
   202
    /* Submit the next filled buffer */
slouken@8582
   203
    SDL_zero(buffer);
slouken@8582
   204
    buffer.AudioBytes = mixlen;
slouken@8582
   205
    buffer.pAudioData = nextbuf;
slouken@8582
   206
    buffer.pContext = this;
slouken@8582
   207
slouken@8582
   208
    if (nextbuf == mixbuf) {
slouken@8582
   209
        nextbuf += mixlen;
slouken@8582
   210
    } else {
slouken@8582
   211
        nextbuf = mixbuf;
slouken@8582
   212
    }
slouken@8582
   213
    this->hidden->nextbuf = nextbuf;
slouken@8582
   214
slouken@8582
   215
    result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL);
slouken@8582
   216
    if (result == XAUDIO2_E_DEVICE_INVALIDATED) {
slouken@8582
   217
        /* !!! FIXME: possibly disconnected or temporary lost. Recover? */
slouken@8582
   218
    }
slouken@8582
   219
slouken@8582
   220
    if (result != S_OK) {  /* uhoh, panic! */
slouken@8582
   221
        IXAudio2SourceVoice_FlushSourceBuffers(source);
icculus@9394
   222
        SDL_OpenedAudioDeviceDisconnected(this);
slouken@8582
   223
    }
slouken@8582
   224
}
slouken@8582
   225
slouken@8582
   226
static void
slouken@8582
   227
XAUDIO2_WaitDevice(_THIS)
slouken@8582
   228
{
icculus@10238
   229
    if (SDL_AtomicGet(&this->enabled)) {
slouken@8582
   230
        SDL_SemWait(this->hidden->semaphore);
slouken@8582
   231
    }
slouken@8582
   232
}
slouken@8582
   233
slouken@8582
   234
static void
icculus@10473
   235
XAUDIO2_PrepareToClose(_THIS)
slouken@8582
   236
{
slouken@8582
   237
    IXAudio2SourceVoice *source = this->hidden->source;
icculus@10473
   238
    if (source) {
icculus@10473
   239
        IXAudio2SourceVoice_Discontinuity(source);
slouken@8582
   240
    }
slouken@8582
   241
}
slouken@8582
   242
slouken@8582
   243
static void
slouken@8582
   244
XAUDIO2_CloseDevice(_THIS)
slouken@8582
   245
{
icculus@10255
   246
    IXAudio2 *ixa2 = this->hidden->ixa2;
icculus@10255
   247
    IXAudio2SourceVoice *source = this->hidden->source;
icculus@10255
   248
    IXAudio2MasteringVoice *mastering = this->hidden->mastering;
slouken@8582
   249
icculus@10255
   250
    if (source != NULL) {
icculus@10255
   251
        IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
icculus@10255
   252
        IXAudio2SourceVoice_FlushSourceBuffers(source);
icculus@10255
   253
        IXAudio2SourceVoice_DestroyVoice(source);
icculus@10255
   254
    }
icculus@10255
   255
    if (ixa2 != NULL) {
icculus@10255
   256
        IXAudio2_StopEngine(ixa2);
icculus@10255
   257
    }
icculus@10255
   258
    if (mastering != NULL) {
icculus@10255
   259
        IXAudio2MasteringVoice_DestroyVoice(mastering);
icculus@10255
   260
    }
icculus@10255
   261
    if (ixa2 != NULL) {
icculus@10255
   262
        IXAudio2_Release(ixa2);
icculus@10255
   263
    }
icculus@10255
   264
    if (this->hidden->semaphore != NULL) {
icculus@10255
   265
        SDL_DestroySemaphore(this->hidden->semaphore);
icculus@10255
   266
    }
slouken@8582
   267
icculus@10255
   268
    SDL_free(this->hidden->mixbuf);
icculus@10255
   269
    SDL_free(this->hidden);
slouken@8582
   270
}
slouken@8582
   271
slouken@8582
   272
static int
icculus@9394
   273
XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
slouken@8582
   274
{
slouken@8582
   275
    HRESULT result = S_OK;
slouken@8582
   276
    WAVEFORMATEX waveformat;
slouken@8582
   277
    int valid_format = 0;
slouken@8582
   278
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
slouken@8582
   279
    IXAudio2 *ixa2 = NULL;
slouken@8582
   280
    IXAudio2SourceVoice *source = NULL;
slouken@8582
   281
#if defined(SDL_XAUDIO2_WIN8)
slouken@8582
   282
    LPCWSTR devId = NULL;
slouken@8582
   283
#else
icculus@9410
   284
    UINT32 devId = 0;  /* 0 == system default device. */
slouken@8582
   285
#endif
slouken@8582
   286
slouken@8582
   287
    static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
slouken@8582
   288
        VoiceCBOnVoiceProcessPassStart,
slouken@8582
   289
        VoiceCBOnVoiceProcessPassEnd,
slouken@8582
   290
        VoiceCBOnStreamEnd,
slouken@8582
   291
        VoiceCBOnBufferStart,
slouken@8582
   292
        VoiceCBOnBufferEnd,
slouken@8582
   293
        VoiceCBOnLoopEnd,
slouken@8582
   294
        VoiceCBOnVoiceError
slouken@8582
   295
    };
slouken@8582
   296
slouken@8582
   297
    static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
slouken@8582
   298
icculus@9410
   299
#if defined(SDL_XAUDIO2_WIN8)
icculus@9410
   300
    /* !!! FIXME: hook up hotplugging. */
icculus@9410
   301
#else
icculus@9410
   302
    if (handle != NULL) {  /* specific device requested? */
icculus@9410
   303
        /* -1 because we increment the original value to avoid NULL. */
icculus@9410
   304
        const size_t val = ((size_t) handle) - 1;
icculus@9410
   305
        devId = (UINT32) val;
icculus@9410
   306
    }
icculus@9410
   307
#endif
icculus@9410
   308
icculus@9394
   309
    if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
slouken@8582
   310
        return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
slouken@8582
   311
    }
slouken@8582
   312
slouken@8582
   313
    /*
slouken@8582
   314
    XAUDIO2_DEBUG_CONFIGURATION debugConfig;
slouken@8582
   315
    debugConfig.TraceMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL | XAUDIO2_LOG_FUNC_CALLS | XAUDIO2_LOG_TIMING | XAUDIO2_LOG_LOCKS | XAUDIO2_LOG_MEMORY | XAUDIO2_LOG_STREAMING;
slouken@8582
   316
    debugConfig.BreakMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS;
slouken@8582
   317
    debugConfig.LogThreadID = TRUE;
slouken@8582
   318
    debugConfig.LogFileline = TRUE;
slouken@8582
   319
    debugConfig.LogFunctionName = TRUE;
slouken@8582
   320
    debugConfig.LogTiming = TRUE;
slouken@8582
   321
    ixa2->SetDebugConfiguration(&debugConfig);
slouken@8582
   322
    */
slouken@8582
   323
slouken@8582
   324
    /* Initialize all variables that we clean on shutdown */
slouken@8582
   325
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@8582
   326
        SDL_malloc((sizeof *this->hidden));
slouken@8582
   327
    if (this->hidden == NULL) {
slouken@8582
   328
        IXAudio2_Release(ixa2);
slouken@8582
   329
        return SDL_OutOfMemory();
slouken@8582
   330
    }
icculus@10257
   331
    SDL_zerop(this->hidden);
slouken@8582
   332
slouken@8582
   333
    this->hidden->ixa2 = ixa2;
slouken@8582
   334
    this->hidden->semaphore = SDL_CreateSemaphore(1);
slouken@8582
   335
    if (this->hidden->semaphore == NULL) {
slouken@8582
   336
        return SDL_SetError("XAudio2: CreateSemaphore() failed!");
slouken@8582
   337
    }
slouken@8582
   338
slouken@8582
   339
    while ((!valid_format) && (test_format)) {
slouken@8582
   340
        switch (test_format) {
slouken@8582
   341
        case AUDIO_U8:
slouken@8582
   342
        case AUDIO_S16:
slouken@8582
   343
        case AUDIO_S32:
slouken@8582
   344
        case AUDIO_F32:
slouken@8582
   345
            this->spec.format = test_format;
slouken@8582
   346
            valid_format = 1;
slouken@8582
   347
            break;
slouken@8582
   348
        }
slouken@8582
   349
        test_format = SDL_NextAudioFormat();
slouken@8582
   350
    }
slouken@8582
   351
slouken@8582
   352
    if (!valid_format) {
slouken@8582
   353
        return SDL_SetError("XAudio2: Unsupported audio format");
slouken@8582
   354
    }
slouken@8582
   355
slouken@8582
   356
    /* Update the fragment size as size in bytes */
slouken@8582
   357
    SDL_CalculateAudioSpec(&this->spec);
slouken@8582
   358
slouken@8582
   359
    /* We feed a Source, it feeds the Mastering, which feeds the device. */
slouken@8582
   360
    this->hidden->mixlen = this->spec.size;
slouken@8582
   361
    this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
slouken@8582
   362
    if (this->hidden->mixbuf == NULL) {
slouken@8582
   363
        return SDL_OutOfMemory();
slouken@8582
   364
    }
slouken@8582
   365
    this->hidden->nextbuf = this->hidden->mixbuf;
icculus@10257
   366
    SDL_memset(this->hidden->mixbuf, this->spec.silence, 2 * this->hidden->mixlen);
slouken@8582
   367
slouken@8582
   368
    /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
slouken@8582
   369
       Xbox360, this means 5.1 output, but on Windows, it means "figure out
slouken@8582
   370
       what the system has." It might be preferable to let XAudio2 blast
slouken@8582
   371
       stereo output to appropriate surround sound configurations
slouken@8582
   372
       instead of clamping to 2 channels, even though we'll configure the
slouken@8582
   373
       Source Voice for whatever number of channels you supply. */
slouken@8582
   374
#if SDL_XAUDIO2_WIN8
slouken@8582
   375
    result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
slouken@8582
   376
                                           XAUDIO2_DEFAULT_CHANNELS,
slouken@8582
   377
                                           this->spec.freq, 0, devId, NULL, AudioCategory_GameEffects);
slouken@8582
   378
#else
slouken@8582
   379
    result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
slouken@8582
   380
                                           XAUDIO2_DEFAULT_CHANNELS,
slouken@8582
   381
                                           this->spec.freq, 0, devId, NULL);
slouken@8582
   382
#endif
slouken@8582
   383
    if (result != S_OK) {
slouken@8582
   384
        return SDL_SetError("XAudio2: Couldn't create mastering voice");
slouken@8582
   385
    }
slouken@8582
   386
slouken@8582
   387
    SDL_zero(waveformat);
slouken@8582
   388
    if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
slouken@8582
   389
        waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
slouken@8582
   390
    } else {
slouken@8582
   391
        waveformat.wFormatTag = WAVE_FORMAT_PCM;
slouken@8582
   392
    }
slouken@8582
   393
    waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
slouken@8582
   394
    waveformat.nChannels = this->spec.channels;
slouken@8582
   395
    waveformat.nSamplesPerSec = this->spec.freq;
slouken@8582
   396
    waveformat.nBlockAlign =
slouken@8582
   397
        waveformat.nChannels * (waveformat.wBitsPerSample / 8);
slouken@8582
   398
    waveformat.nAvgBytesPerSec =
slouken@8582
   399
        waveformat.nSamplesPerSec * waveformat.nBlockAlign;
slouken@8582
   400
    waveformat.cbSize = sizeof(waveformat);
slouken@8582
   401
slouken@8582
   402
#ifdef __WINRT__
slouken@8582
   403
    // DLudwig: for now, make XAudio2 do sample rate conversion, just to
slouken@8582
   404
    // get the loopwave test to work.
slouken@8582
   405
    //
slouken@8582
   406
    // TODO, WinRT: consider removing WinRT-specific source-voice creation code from SDL_xaudio2.c
slouken@8582
   407
    result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
slouken@8582
   408
                                        0,
slouken@8582
   409
                                        1.0f, &callbacks, NULL, NULL);
slouken@8582
   410
#else
slouken@8582
   411
    result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
slouken@8582
   412
                                        XAUDIO2_VOICE_NOSRC |
slouken@8582
   413
                                        XAUDIO2_VOICE_NOPITCH,
slouken@8582
   414
                                        1.0f, &callbacks, NULL, NULL);
slouken@8582
   415
slouken@8582
   416
#endif
slouken@8582
   417
    if (result != S_OK) {
slouken@8582
   418
        return SDL_SetError("XAudio2: Couldn't create source voice");
slouken@8582
   419
    }
slouken@8582
   420
    this->hidden->source = source;
slouken@8582
   421
slouken@8582
   422
    /* Start everything playing! */
slouken@8582
   423
    result = IXAudio2_StartEngine(ixa2);
slouken@8582
   424
    if (result != S_OK) {
slouken@8582
   425
        return SDL_SetError("XAudio2: Couldn't start engine");
slouken@8582
   426
    }
slouken@8582
   427
slouken@8582
   428
    result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
slouken@8582
   429
    if (result != S_OK) {
slouken@8582
   430
        return SDL_SetError("XAudio2: Couldn't start source voice");
slouken@8582
   431
    }
slouken@8582
   432
slouken@8582
   433
    return 0; /* good to go. */
slouken@8582
   434
}
slouken@8582
   435
slouken@8582
   436
static void
slouken@8582
   437
XAUDIO2_Deinitialize(void)
slouken@8582
   438
{
slouken@8582
   439
#if defined(__WIN32__)
slouken@8582
   440
    WIN_CoUninitialize();
slouken@8582
   441
#endif
slouken@8582
   442
}
slouken@8582
   443
slouken@8582
   444
#endif  /* SDL_XAUDIO2_HAS_SDK */
slouken@8582
   445
slouken@8582
   446
slouken@8582
   447
static int
slouken@8582
   448
XAUDIO2_Init(SDL_AudioDriverImpl * impl)
slouken@8582
   449
{
slouken@8582
   450
#ifndef SDL_XAUDIO2_HAS_SDK
slouken@8582
   451
    SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK).");
slouken@8582
   452
    return 0;  /* no XAudio2 support, ever. Update your SDK! */
slouken@8582
   453
#else
slouken@8582
   454
    /* XAudio2Create() is a macro that uses COM; we don't load the .dll */
slouken@8582
   455
    IXAudio2 *ixa2 = NULL;
slouken@8582
   456
#if defined(__WIN32__)
slouken@8582
   457
    // TODO, WinRT: Investigate using CoInitializeEx here
slouken@8582
   458
    if (FAILED(WIN_CoInitialize())) {
slouken@8582
   459
        SDL_SetError("XAudio2: CoInitialize() failed");
slouken@8582
   460
        return 0;
slouken@8582
   461
    }
slouken@8582
   462
#endif
slouken@8582
   463
slouken@8582
   464
    if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
slouken@8582
   465
#if defined(__WIN32__)
slouken@8582
   466
        WIN_CoUninitialize();
slouken@8582
   467
#endif
slouken@8582
   468
        SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
slouken@8582
   469
        return 0;  /* not available. */
slouken@8582
   470
    }
slouken@8582
   471
    IXAudio2_Release(ixa2);
slouken@8582
   472
slouken@8582
   473
    /* Set the function pointers */
slouken@8582
   474
    impl->DetectDevices = XAUDIO2_DetectDevices;
slouken@8582
   475
    impl->OpenDevice = XAUDIO2_OpenDevice;
slouken@8582
   476
    impl->PlayDevice = XAUDIO2_PlayDevice;
slouken@8582
   477
    impl->WaitDevice = XAUDIO2_WaitDevice;
icculus@10473
   478
    impl->PrepareToClose = XAUDIO2_PrepareToClose;
slouken@8582
   479
    impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
slouken@8582
   480
    impl->CloseDevice = XAUDIO2_CloseDevice;
slouken@8582
   481
    impl->Deinitialize = XAUDIO2_Deinitialize;
slouken@8582
   482
icculus@9394
   483
    /* !!! FIXME: We can apparently use a C++ interface on Windows 8
icculus@9394
   484
     * !!! FIXME: (Windows::Devices::Enumeration::DeviceInformation) for device
icculus@9394
   485
     * !!! FIXME: detection, but it's not implemented here yet.
icculus@9394
   486
     * !!! FIXME:  see http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
icculus@9394
   487
     * !!! FIXME:  for now, force the default device.
icculus@9394
   488
     */
icculus@9394
   489
#if defined(SDL_XAUDIO2_WIN8) || defined(__WINRT__)
icculus@9394
   490
    impl->OnlyHasDefaultOutputDevice = 1;
icculus@9394
   491
#endif
icculus@9394
   492
slouken@8582
   493
    return 1;   /* this audio target is available. */
slouken@8582
   494
#endif
slouken@8582
   495
}
slouken@8582
   496
slouken@8582
   497
AudioBootStrap XAUDIO2_bootstrap = {
slouken@8582
   498
    "xaudio2", "XAudio2", XAUDIO2_Init, 0
slouken@8582
   499
};
slouken@8582
   500
slouken@8582
   501
#endif  /* SDL_AUDIO_DRIVER_XAUDIO2 */
slouken@8582
   502
slouken@8582
   503
/* vi: set ts=4 sw=4 expandtab: */