summaryrefslogtreecommitdiffstats
path: root/Alc/mmdevapi.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2011-05-17 04:54:09 -0700
committerChris Robinson <[email protected]>2011-05-17 04:54:09 -0700
commit2abeed069bdca3d2778898ef63d4a4d22b4bf319 (patch)
treed54662430de7ca43c6d6695bd52daac6fc19d842 /Alc/mmdevapi.c
parent569106acd35913882d430c473303ed9dcc5a1ba0 (diff)
Improve handling of format support for MMDevApi
Diffstat (limited to 'Alc/mmdevapi.c')
-rw-r--r--Alc/mmdevapi.c281
1 files changed, 192 insertions, 89 deletions
diff --git a/Alc/mmdevapi.c b/Alc/mmdevapi.c
index 052ff6f3..9feef4ad 100644
--- a/Alc/mmdevapi.c
+++ b/Alc/mmdevapi.c
@@ -66,6 +66,42 @@ typedef struct {
static const ALCchar mmDevice[] = "WASAPI Default";
+static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in)
+{
+ memset(out, 0, sizeof(*out));
+ if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ *out = *(WAVEFORMATEXTENSIBLE*)in;
+ else if(in->wFormatTag == WAVE_FORMAT_PCM)
+ {
+ out->Format = *in;
+ out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ out->Format.cbSize = sizeof(*out) - sizeof(*in);
+ if(out->Format.nChannels == 1)
+ out->dwChannelMask = MONO;
+ else if(out->Format.nChannels == 2)
+ out->dwChannelMask = STEREO;
+ out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }
+ else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
+ {
+ out->Format = *in;
+ out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ out->Format.cbSize = sizeof(*out) - sizeof(*in);
+ if(out->Format.nChannels == 1)
+ out->dwChannelMask = MONO;
+ else if(out->Format.nChannels == 2)
+ out->dwChannelMask = STEREO;
+ out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ }
+ else
+ {
+ AL_PRINT("Unhandled format tag: 0x%04x\n", in->wFormatTag);
+ return ALC_FALSE;
+ }
+ return ALC_TRUE;
+}
+
+
static void *MMDevApiLoad(void)
{
if(!Enumerator)
@@ -218,96 +254,32 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
return ALC_FALSE;
}
- if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
- device->Frequency = wfx->nSamplesPerSec;
- if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
+ if(!MakeExtensible(&OutputType, wfx))
{
- if(wfx->wFormatTag == WAVE_FORMAT_PCM)
- {
- if(wfx->nChannels == 1)
- device->FmtChans = DevFmtMono;
- else if(wfx->nChannels == 2)
- device->FmtChans = DevFmtStereo;
- else
- {
- AL_PRINT("Unhandled PCM channels: %d\n", wfx->nChannels);
- device->FmtChans = DevFmtStereo;
- }
- }
- else if(wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
- {
- WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
-
- if(wfe->Format.nChannels == 1 && wfe->dwChannelMask == MONO)
- device->FmtChans = DevFmtMono;
- else if(wfe->Format.nChannels == 2 && wfe->dwChannelMask == STEREO)
- device->FmtChans = DevFmtStereo;
- else if(wfe->Format.nChannels == 4 && wfe->dwChannelMask == QUAD)
- device->FmtChans = DevFmtQuad;
- else if(wfe->Format.nChannels == 6 && wfe->dwChannelMask == X5DOT1)
- device->FmtChans = DevFmtX51;
- else if(wfe->Format.nChannels == 7 && wfe->dwChannelMask == X6DOT1)
- device->FmtChans = DevFmtX61;
- else if(wfe->Format.nChannels == 8 && wfe->dwChannelMask == X7DOT1)
- device->FmtChans = DevFmtX71;
- else
- {
- AL_PRINT("Unhandled extensible channels: %d -- 0x%08lx\n", wfe->Format.nChannels, wfe->dwChannelMask);
- device->FmtChans = DevFmtStereo;
- }
- }
- }
-
- if(wfx->wFormatTag == WAVE_FORMAT_PCM)
- {
- if(wfx->wBitsPerSample == 8)
- device->FmtType = DevFmtUByte;
- else if(wfx->wBitsPerSample == 16)
- device->FmtType = DevFmtShort;
- }
- else if(wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
- {
- WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
-
- if(IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
- {
- if(wfx->wBitsPerSample == 8)
- device->FmtType = DevFmtUByte;
- else if(wfx->wBitsPerSample == 16)
- device->FmtType = DevFmtShort;
- }
- else if(IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
- device->FmtType = DevFmtFloat;
+ CoTaskMemFree(wfx);
+ return ALC_FALSE;
}
-
CoTaskMemFree(wfx);
wfx = NULL;
- SetDefaultWFXChannelOrder(device);
-
- memset(&OutputType, 0, sizeof(OutputType));
- OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
-
- switch(device->FmtType)
+ if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
+ device->Frequency = OutputType.Format.nSamplesPerSec;
+ if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
- case DevFmtByte:
- device->FmtType = DevFmtUByte;
- /* fall-through */
- case DevFmtUByte:
- OutputType.Format.wBitsPerSample = 8;
- OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- break;
- case DevFmtUShort:
- device->FmtType = DevFmtShort;
- /* fall-through */
- case DevFmtShort:
- OutputType.Format.wBitsPerSample = 16;
- OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- break;
- case DevFmtFloat:
- OutputType.Format.wBitsPerSample = 32;
- OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- break;
+ if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
+ device->FmtChans = DevFmtMono;
+ else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
+ device->FmtChans = DevFmtStereo;
+ else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
+ device->FmtChans = DevFmtQuad;
+ else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
+ device->FmtChans = DevFmtX51;
+ else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
+ device->FmtChans = DevFmtX61;
+ else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+ device->FmtChans = DevFmtX71;
+ else
+ AL_PRINT("Unhandled channel config: %d -- 0x%08x\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
}
switch(device->FmtChans)
@@ -337,11 +309,143 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
OutputType.dwChannelMask = X7DOT1;
break;
}
-
- OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ device->FmtType = DevFmtUByte;
+ /* fall-through */
+ case DevFmtUByte:
+ OutputType.Format.wBitsPerSample = 8;
+ OutputType.Samples.wValidBitsPerSample = 8;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ OutputType.Format.wBitsPerSample = 16;
+ OutputType.Samples.wValidBitsPerSample = 16;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case DevFmtFloat:
+ OutputType.Format.wBitsPerSample = 32;
+ OutputType.Samples.wValidBitsPerSample = 32;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ break;
+ }
OutputType.Format.nSamplesPerSec = device->Frequency;
- OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
- OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format);
+
+ OutputType.Format.nBlockAlign = OutputType.Format.nChannels *
+ OutputType.Format.wBitsPerSample / 8;
+ OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
+ OutputType.Format.nBlockAlign;
+
+ hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
+ if(FAILED(hr))
+ hr = IAudioClient_GetMixFormat(data->client, &wfx);
+ if(FAILED(hr))
+ {
+ AL_PRINT("Failed to find a supported format\n");
+ return ALC_FALSE;
+ }
+
+ if(wfx != NULL)
+ {
+ if(!MakeExtensible(&OutputType, wfx))
+ {
+ CoTaskMemFree(wfx);
+ return ALC_FALSE;
+ }
+ CoTaskMemFree(wfx);
+ wfx = NULL;
+
+ if(device->Frequency != OutputType.Format.nSamplesPerSec)
+ {
+ if((device->Flags&DEVICE_FREQUENCY_REQUEST))
+ AL_PRINT("Failed to set %dhz, got %dhz instead\n", device->Frequency, OutputType.Format.nSamplesPerSec);
+ device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
+ device->Frequency = OutputType.Format.nSamplesPerSec;
+ }
+
+ if(!((device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) ||
+ (device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) ||
+ (device->FmtChans == DevFmtQuad && OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) ||
+ (device->FmtChans == DevFmtX51 && OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) ||
+ (device->FmtChans == DevFmtX61 && OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) ||
+ (device->FmtChans == DevFmtX71 && OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)))
+ {
+ if((device->Flags&DEVICE_CHANNELS_REQUEST))
+ AL_PRINT("Failed to set %s, got %d channels (0x%08x) instead\n", DevFmtChannelsString(device->FmtChans), OutputType.Format.nChannels, OutputType.dwChannelMask);
+ device->Flags &= ~DEVICE_CHANNELS_REQUEST;
+
+ if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
+ device->FmtChans = DevFmtMono;
+ else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
+ device->FmtChans = DevFmtStereo;
+ else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
+ device->FmtChans = DevFmtQuad;
+ else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
+ device->FmtChans = DevFmtX51;
+ else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
+ device->FmtChans = DevFmtX61;
+ else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+ device->FmtChans = DevFmtX71;
+ else
+ {
+ AL_PRINT("Unhandled extensible channels: %d -- 0x%08x\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
+ device->FmtChans = DevFmtStereo;
+ OutputType.Format.nChannels = 2;
+ OutputType.dwChannelMask = STEREO;
+ }
+ }
+
+ if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
+ {
+ if(OutputType.Samples.wValidBitsPerSample == 0)
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ if(OutputType.Samples.wValidBitsPerSample != OutputType.Format.wBitsPerSample ||
+ !((device->FmtType == DevFmtUByte && OutputType.Format.wBitsPerSample == 8) ||
+ (device->FmtType == DevFmtShort && OutputType.Format.wBitsPerSample == 16)))
+ {
+ AL_PRINT("Failed to set %s, got %d/%d-bit instead\n", DevFmtTypeString(device->FmtType), OutputType.Samples.wValidBitsPerSample, OutputType.Format.wBitsPerSample);
+ if(OutputType.Format.wBitsPerSample == 8)
+ device->FmtType = DevFmtUByte;
+ else if(OutputType.Format.wBitsPerSample == 16)
+ device->FmtType = DevFmtShort;
+ else
+ {
+ device->FmtType = DevFmtShort;
+ OutputType.Format.wBitsPerSample = 16;
+ }
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ }
+ }
+ else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
+ {
+ if(OutputType.Samples.wValidBitsPerSample == 0)
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ if(OutputType.Samples.wValidBitsPerSample != OutputType.Format.wBitsPerSample ||
+ !((device->FmtType == DevFmtFloat && OutputType.Format.wBitsPerSample == 32)))
+ {
+ AL_PRINT("Failed to set %s, got %d/%d-bit instead\n", DevFmtTypeString(device->FmtType), OutputType.Samples.wValidBitsPerSample, OutputType.Format.wBitsPerSample);
+ if(OutputType.Format.wBitsPerSample != 32)
+ {
+ device->FmtType = DevFmtFloat;
+ OutputType.Format.wBitsPerSample = 32;
+ }
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ }
+ }
+ else
+ {
+ AL_PRINT("Unhandled format sub-type\n");
+ device->FmtType = DevFmtShort;
+ OutputType.Format.wBitsPerSample = 16;
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ }
+ }
+
+ SetDefaultWFXChannelOrder(device);
hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED, 0,
@@ -354,7 +458,6 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
return ALC_FALSE;
}
-
hr = IAudioClient_Start(data->client);
if(FAILED(hr))
{