aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/wasapi.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-10-05 22:30:23 -0700
committerChris Robinson <[email protected]>2020-10-05 22:30:23 -0700
commit7fb6d64ca81d68f74a254c097d511d8863453000 (patch)
tree7393463f07febc1fd0d31c50bc62d18b90774518 /alc/backends/wasapi.cpp
parente7a44d3b7063553fa54e743a4fac116d130fbe1d (diff)
Be more robust with to-mono channel conversions
Diffstat (limited to 'alc/backends/wasapi.cpp')
-rw-r--r--alc/backends/wasapi.cpp68
1 files changed, 52 insertions, 16 deletions
diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp
index 52cf9afd..d7b763c4 100644
--- a/alc/backends/wasapi.cpp
+++ b/alc/backends/wasapi.cpp
@@ -1556,28 +1556,54 @@ HRESULT WasapiCapture::resetProxy()
if(wfx != nullptr)
{
TraceFormat("Got capture format", wfx);
- if(!(wfx->nChannels == InputType.Format.nChannels ||
- (wfx->nChannels == 1 && InputType.Format.nChannels == 2) ||
- (wfx->nChannels == 2 && InputType.Format.nChannels == 1)))
+ if(!MakeExtensible(&InputType, wfx))
{
- ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n",
- DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType),
- mDevice->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample,
- wfx->nSamplesPerSec);
CoTaskMemFree(wfx);
return E_FAIL;
}
+ CoTaskMemFree(wfx);
+ wfx = nullptr;
- if(!MakeExtensible(&InputType, wfx))
+ auto validate_fmt = [](ALCdevice *device, uint32_t chancount, DWORD chanmask) noexcept
+ -> bool
{
- CoTaskMemFree(wfx);
+ switch(device->FmtChans)
+ {
+ /* If the device wants mono, we can handle any input. */
+ case DevFmtMono:
+ return true;
+ /* If the device wants stereo, we can handle mono or stereo input. */
+ case DevFmtStereo:
+ return (chancount == 2 && (chanmask == 0 || (chanmask&StereoMask) == STEREO))
+ || (chancount == 1 && (chanmask&MonoMask) == MONO);
+ /* Otherwise, the device must match the input type. */
+ case DevFmtQuad:
+ return (chancount == 4 && (chanmask == 0 || (chanmask&QuadMask) == QUAD));
+ /* 5.1 (Side) and 5.1 (Rear) are interchangeable here. */
+ case DevFmtX51:
+ case DevFmtX51Rear:
+ return (chancount == 6 && (chanmask == 0 || (chanmask&X51Mask) == X5DOT1
+ || (chanmask&X51RearMask) == X5DOT1REAR));
+ case DevFmtX61:
+ return (chancount == 7 && (chanmask == 0 || (chanmask&X61Mask) == X6DOT1));
+ case DevFmtX71:
+ return (chancount == 8 && (chanmask == 0 || (chanmask&X71Mask) == X7DOT1));
+ case DevFmtAmbi3D: return (chanmask == 0 && device->channelsFromFmt());
+ }
+ return false;
+ };
+ if(!validate_fmt(mDevice, InputType.Format.nChannels, InputType.dwChannelMask))
+ {
+ ERR("Failed to match format, wanted: %s %s %uhz, got: 0x%08lx mask %d channel%s %d-bit %luhz\n",
+ DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType),
+ mDevice->Frequency, InputType.dwChannelMask, InputType.Format.nChannels,
+ (InputType.Format.nChannels==1)?"":"s", InputType.Format.wBitsPerSample,
+ InputType.Format.nSamplesPerSec);
return E_FAIL;
}
- CoTaskMemFree(wfx);
- wfx = nullptr;
}
- DevFmtType srcType;
+ DevFmtType srcType{};
if(IsEqualGUID(InputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM))
{
if(InputType.Format.wBitsPerSample == 8)
@@ -1608,10 +1634,20 @@ HRESULT WasapiCapture::resetProxy()
return E_FAIL;
}
- if(mDevice->FmtChans == DevFmtMono && InputType.Format.nChannels == 2)
+ if(mDevice->FmtChans == DevFmtMono && InputType.Format.nChannels != 1)
{
- mChannelConv = ChannelConverter{srcType, DevFmtStereo, mDevice->FmtChans};
- TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType));
+ ALuint chanmask{(1u<<InputType.Format.nChannels) - 1u};
+ /* Exclude LFE from the downmix. */
+ if((InputType.dwChannelMask&SPEAKER_LOW_FREQUENCY))
+ {
+ constexpr auto lfemask = MaskFromTopBits(SPEAKER_LOW_FREQUENCY);
+ const int lfeidx{POPCNT32(InputType.dwChannelMask&lfemask) - 1};
+ chanmask &= ~(1u << lfeidx);
+ }
+
+ mChannelConv = ChannelConverter{srcType, InputType.Format.nChannels, chanmask,
+ mDevice->FmtChans};
+ TRACE("Created %s multichannel-to-mono converter\n", DevFmtTypeString(srcType));
/* The channel converter always outputs float, so change the input type
* for the resampler/type-converter.
*/
@@ -1619,7 +1655,7 @@ HRESULT WasapiCapture::resetProxy()
}
else if(mDevice->FmtChans == DevFmtStereo && InputType.Format.nChannels == 1)
{
- mChannelConv = ChannelConverter{srcType, DevFmtMono, mDevice->FmtChans};
+ mChannelConv = ChannelConverter{srcType, 1, 0x1, mDevice->FmtChans};
TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType));
srcType = DevFmtFloat;
}