WinRT: got the XAudio2 backend compiling (but not running, yet)

This commit is contained in:
David Ludwig 2012-11-22 22:34:50 -05:00
parent 7fe2bdd83a
commit c4d055488f
6 changed files with 238 additions and 12 deletions

View file

@ -37,6 +37,22 @@
<ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c" />
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\xaudio2\SDL_xaudio2.c">
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsCpp</CompileAs>
</ClCompile>
<ClCompile Include="..\..\src\audio\xaudio2\SDL_xaudio2_winrthelpers.cpp">
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsWinRT>
</ClCompile>
<ClCompile Include="..\..\src\cpuinfo\SDL_cpuinfo.c" />
<ClCompile Include="..\..\src\events\SDL_clipboardevents.c" />
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
@ -206,6 +222,8 @@
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
<ClInclude Include="..\..\src\audio\xaudio2\SDL_xaudio2_winrthelpers.h" />
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
<ClInclude Include="..\..\src\events\blank_cursor.h" />
<ClInclude Include="..\..\src\events\default_cursor.h" />
<ClInclude Include="..\..\src\events\SDL_clipboardevents_c.h" />
@ -384,7 +402,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -398,7 +416,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
@ -412,7 +430,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
@ -426,7 +444,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -440,7 +458,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -454,7 +472,7 @@
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View file

@ -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

View file

@ -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<Platform::String^>^)). (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 <dxsdkver.h> /* 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
};

View file

@ -0,0 +1,41 @@
#include <xaudio2.h>
#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;
}

View file

@ -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))

View file

@ -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 <windows.h>