diff --git a/VisualC/SDL/SDL_VS2012_WinRT.vcxproj b/VisualC/SDL/SDL_VS2012_WinRT.vcxproj
index cddcbdff9..73d04e207 100644
--- a/VisualC/SDL/SDL_VS2012_WinRT.vcxproj
+++ b/VisualC/SDL/SDL_VS2012_WinRT.vcxproj
@@ -37,6 +37,22 @@
+
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
@@ -206,6 +222,8 @@
+
+
@@ -384,7 +402,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
@@ -398,7 +416,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
@@ -412,7 +430,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
@@ -426,7 +444,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
@@ -440,7 +458,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
@@ -454,7 +472,7 @@
Console
false
false
- d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)
+ xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
diff --git a/include/SDL_config_windowsrt.h b/include/SDL_config_windowsrt.h
index 3f12a130c..fb7fdb3b9 100644
--- a/include/SDL_config_windowsrt.h
+++ b/include/SDL_config_windowsrt.h
@@ -144,7 +144,7 @@ typedef unsigned int uintptr_t;
#endif
/* Enable various audio drivers */
-//#define SDL_AUDIO_DRIVER_XAUDIO2 1 // TODO, WinRT: see if SDL's XAudio2 driver can compile
+#define SDL_AUDIO_DRIVER_XAUDIO2 1
#define SDL_AUDIO_DRIVER_DISK 1
#define SDL_AUDIO_DRIVER_DUMMY 1
diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c
index d42d89638..f2302f575 100644
--- a/src/audio/xaudio2/SDL_xaudio2.c
+++ b/src/audio/xaudio2/SDL_xaudio2.c
@@ -18,22 +18,90 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
+
+/* WinRT NOTICE:
+
+ A number of changes were warranted to SDL's XAudio2 backend in order to
+ get it compiling for Windows RT.
+
+ When compiling for WinRT, XAudio2.h requires that it be compiled in a C++
+ file, and not a straight C file. Trying to compile it as C leads to lots
+ of errors, at least with MSVC 2012 and Windows SDK 8.0, as of Nov 22, 2012.
+ To address this specific issue, a few changes were made to SDL_xaudio2.c:
+
+ 1. SDL_xaudio2.c is compiled as a C++ file in WinRT builds. Exported
+ symbols, namely XAUDIO2_bootstrap, uses 'extern "C"' to make sure the
+ rest of SDL can access it. Non-WinRT builds continue to compile
+ SDL_xaudio2.c as a C file.
+ 2. A macro redefines variables named 'this' to '_this', to prevent compiler
+ errors (C2355 in Visual C++) related to 'this' being a reserverd keyword.
+ This hack may need to be altered in the future, particularly if C++'s
+ 'this' keyword needs to be used (within SDL_xaudio2.c). At the time
+ WinRT support was initially added to SDL's XAudio2 backend, this
+ capability was not needed.
+ 3. The C-style macros to invoke XAudio2's COM-based methods were
+ rewritten to be C++-friendly. These are provided in the file,
+ SDL_xaudio2_winrthelpers.h.
+ 4. IXAudio2::CreateSourceVoice, when used in C++, requires its callbacks to
+ be specified via a C++ class. SDL's XAudio2 backend was written with
+ C-style callbacks. A class to bridge these two interfaces,
+ SDL_XAudio2VoiceCallback, was written to make XAudio2 happy. Its methods
+ just call SDL's existing, C-style callbacks.
+ 5. Multiple checks for the __cplusplus macro were made, in appropriate
+ places.
+
+
+ A few additional changes to SDL's XAudio2 backend were warranted by API
+ changes to Windows. Many, but not all of these are documented by Microsoft
+ at:
+ http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
+
+ 1. Windows' thread synchronization function, CreateSemaphore, was removed
+ from Windows RT. SDL's semaphore API was substituted instead.
+ 2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails
+ were removed from the XAudio2 API. Microsoft is telling developers to
+ use APIs in Windows::Foundation instead.
+ For SDL, the missing methods were reimplemented using the APIs Microsoft
+ said to use.
+ 3. CoInitialize and CoUninitialize are not available in Windows RT.
+ These calls were removed, as COM will have been initialized earlier,
+ at least by the call to the WinRT app's main function
+ (aka 'int main(Platform::Array^)). (DLudwig:
+ This was my understanding of how WinRT: the 'main' function uses
+ a tag of [MTAThread], which should initialize COM. My understanding
+ of COM is somewhat limited, and I may be incorrect here.)
+ 4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex'
+ argument to a string-based one, 'szDeviceId'. In Windows RT, the
+ string-based argument will be used.
+*/
+
#include "SDL_config.h"
#if SDL_AUDIO_DRIVER_XAUDIO2
+#ifdef __cplusplus
+extern "C" {
+#endif
#include "../../core/windows/SDL_windows.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_assert.h"
+#ifdef __cplusplus
+}
+#endif
+#if defined(__WINRT__)
+# define SDL_XAUDIO2_HAS_SDK 1
+#endif
+#if defined(__WIN32__)
#include /* XAudio2 exists as of the March 2008 DirectX SDK */
#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
#else
# define SDL_XAUDIO2_HAS_SDK 1
#endif
+#endif
#ifdef SDL_XAUDIO2_HAS_SDK
@@ -43,12 +111,17 @@
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
+#ifdef __cplusplus
+#define this _this
+#include "SDL_xaudio2_winrthelpers.h"
+#endif
+
struct SDL_PrivateAudioData
{
IXAudio2 *ixa2;
IXAudio2SourceVoice *source;
IXAudio2MasteringVoice *mastering;
- HANDLE semaphore;
+ SDL_sem * semaphore;
Uint8 *mixbuf;
int mixlen;
Uint8 *nextbuf;
@@ -102,7 +175,7 @@ VoiceCBOnBufferEnd(THIS_ void *data)
{
/* Just signal the SDL audio thread and get out of XAudio2's way. */
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
- ReleaseSemaphore(this->hidden->semaphore, 1, NULL);
+ SDL_SemPost(this->hidden->semaphore);
}
static void STDMETHODCALLTYPE
@@ -119,6 +192,33 @@ static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
+#if defined(__cplusplus)
+class SDL_XAudio2VoiceCallback : public IXAudio2VoiceCallback
+{
+public:
+ STDMETHOD_(void, OnBufferEnd)(void *pBufferContext) {
+ VoiceCBOnBufferEnd(pBufferContext);
+ }
+ STDMETHOD_(void, OnBufferStart)(void *pBufferContext) {
+ VoiceCBOnBufferEnd(pBufferContext);
+ }
+ STDMETHOD_(void, OnLoopEnd)(void *pBufferContext) {
+ VoiceCBOnLoopEnd(pBufferContext);
+ }
+ STDMETHOD_(void, OnStreamEnd)() {
+ VoiceCBOnStreamEnd();
+ }
+ STDMETHOD_(void, OnVoiceError)(void *pBufferContext, HRESULT Error) {
+ VoiceCBOnVoiceError(pBufferContext, Error);
+ }
+ STDMETHOD_(void, OnVoiceProcessingPassEnd)() {
+ VoiceCBOnVoiceProcessPassEnd();
+ }
+ STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32 BytesRequired) {
+ VoiceCBOnVoiceProcessPassStart(BytesRequired);
+ }
+};
+#endif
static Uint8 *
XAUDIO2_GetDeviceBuf(_THIS)
@@ -168,7 +268,7 @@ static void
XAUDIO2_WaitDevice(_THIS)
{
if (this->enabled) {
- WaitForSingleObject(this->hidden->semaphore, INFINITE);
+ SDL_SemWait(this->hidden->semaphore);
}
}
@@ -181,7 +281,7 @@ XAUDIO2_WaitDone(_THIS)
IXAudio2SourceVoice_Discontinuity(source);
IXAudio2SourceVoice_GetState(source, &state);
while (state.BuffersQueued > 0) {
- WaitForSingleObject(this->hidden->semaphore, INFINITE);
+ SDL_SemWait(this->hidden->semaphore);
IXAudio2SourceVoice_GetState(source, &state);
}
}
@@ -230,8 +330,15 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
IXAudio2 *ixa2 = NULL;
IXAudio2SourceVoice *source = NULL;
+#if defined(__WINRT__)
+ WCHAR devId[256];
+#else
UINT32 devId = 0; /* 0 == system default device. */
+#endif
+#if defined(__cplusplus)
+ static SDL_XAudio2VoiceCallback callbacks;
+#else
static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
VoiceCBOnVoiceProcessPassStart,
VoiceCBOnVoiceProcessPassEnd,
@@ -243,6 +350,11 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
};
static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
+#endif // ! defined(__cplusplus)
+
+#if defined(__WINRT__)
+ SDL_zero(devId);
+#endif
if (iscapture) {
SDL_SetError("XAudio2: capture devices unsupported.");
@@ -269,7 +381,11 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
const int match = (SDL_strcmp(str, devname) == 0);
SDL_free(str);
if (match) {
+#if defined(__WINRT__)
+ wcsncpy_s(devId, ARRAYSIZE(devId), details.DeviceID, _TRUNCATE);
+#else
devId = i;
+#endif
break;
}
}
@@ -294,7 +410,7 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->ixa2 = ixa2;
- this->hidden->semaphore = CreateSemaphore(NULL, 1, 2, NULL);
+ this->hidden->semaphore = SDL_CreateSemaphore(1);
if (this->hidden->semaphore == NULL) {
XAUDIO2_CloseDevice(this);
SDL_SetError("XAudio2: CreateSemaphore() failed!");
@@ -395,7 +511,9 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
static void
XAUDIO2_Deinitialize(void)
{
+#if defined(__WIN32__)
WIN_CoUninitialize();
+#endif
}
#endif /* SDL_XAUDIO2_HAS_SDK */
@@ -410,13 +528,17 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
#else
/* XAudio2Create() is a macro that uses COM; we don't load the .dll */
IXAudio2 *ixa2 = NULL;
+#if defined(__WIN32__)
if (FAILED(WIN_CoInitialize())) {
SDL_SetError("XAudio2: CoInitialize() failed");
return 0;
}
+#endif
if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
+#if defined(__WIN32__)
WIN_CoUninitialize();
+#endif
SDL_SetError("XAudio2: XAudio2Create() failed");
return 0; /* not available. */
}
@@ -436,6 +558,9 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
#endif
}
+#if defined(__cplusplus)
+extern "C"
+#endif
AudioBootStrap XAUDIO2_bootstrap = {
"xaudio2", "XAudio2", XAUDIO2_Init, 0
};
diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
new file mode 100644
index 000000000..2fbf63c8b
--- /dev/null
+++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
@@ -0,0 +1,41 @@
+
+#include
+#include "SDL_xaudio2_winrthelpers.h"
+
+using Windows::Devices::Enumeration::DeviceClass;
+using Windows::Devices::Enumeration::DeviceInformation;
+using Windows::Devices::Enumeration::DeviceInformationCollection;
+
+HRESULT IXAudio2_GetDeviceCount(IXAudio2 * ixa2, UINT32 * devcount)
+{
+ auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
+ while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
+ {
+ }
+
+ DeviceInformationCollection^ devices = operation->GetResults();
+ *devcount = devices->Size;
+ return S_OK;
+}
+
+HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details)
+{
+ auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
+ while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
+ {
+ }
+
+ DeviceInformationCollection^ devices = operation->GetResults();
+ if (index >= devices->Size)
+ {
+ return XAUDIO2_E_INVALID_CALL;
+ }
+
+ DeviceInformation^ d = devices->GetAt(index);
+ if (details)
+ {
+ wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), d->Id->Data(), _TRUNCATE);
+ wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), d->Name->Data(), _TRUNCATE);
+ }
+ return S_OK;
+}
diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
new file mode 100644
index 000000000..a72804faa
--- /dev/null
+++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+//
+// Re-implementation of methods removed from XAudio2 (in Windows RT):
+//
+
+typedef struct XAUDIO2_DEVICE_DETAILS
+{
+ WCHAR DeviceID[256];
+ WCHAR DisplayName[256];
+ /* Other fields exist in the pre-Windows 8 version of this struct, however
+ they weren't used by SDL, so they weren't added.
+ */
+} XAUDIO2_DEVICE_DETAILS;
+
+HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount);
+HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details);
+
+
+//
+// C-style macros to call XAudio2's methods in C++:
+//
+
+#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G))
+#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H))
+#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C))
+#define IXAudio2_Release(A) (A)->Release()
+#define IXAudio2_StartEngine(A) (A)->StartEngine()
+#define IXAudio2_StopEngine(A) (A)->StopEngine()
+
+#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice()
+
+#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice()
+#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity()
+#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers()
+#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B))
+#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C))
+#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C))
+#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C))
diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h
index c7c6f9576..d4a7ecff9 100644
--- a/src/core/windows/SDL_windows.h
+++ b/src/core/windows/SDL_windows.h
@@ -24,6 +24,7 @@
#ifndef _INCLUDED_WINDOWS_H
#define _INCLUDED_WINDOWS_H
+#if defined(__WIN32__)
#define WIN32_LEAN_AND_MEAN
#define STRICT
#ifndef UNICODE
@@ -31,6 +32,7 @@
#endif
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
+#endif
#include