diff options
author | Chris Robinson <[email protected]> | 2019-12-21 20:43:46 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-12-21 20:43:46 -0800 |
commit | 2e6a55a87ce24a9303c3039609b41fb0eb302483 (patch) | |
tree | f3bb706cac1689ac9233da4bdd78a9530b5c078a /alc/backends | |
parent | c2ca617ed60e26878a6ac10aaf0dc644b6a24d29 (diff) |
Handle padding between device sample frames
The padding must be constant and sample type aligned (e.g. some fixed multiple
of two bytes between the start of two consecutive frames for 16-bit output).
The intent is to always have the ability for stereo output with WASAPI even if
the device has some other unsupported configuration, as long as front-left and
front-right exist.
Diffstat (limited to 'alc/backends')
-rw-r--r-- | alc/backends/alsa.cpp | 6 | ||||
-rw-r--r-- | alc/backends/coreaudio.cpp | 3 | ||||
-rw-r--r-- | alc/backends/dsound.cpp | 5 | ||||
-rw-r--r-- | alc/backends/jack.cpp | 6 | ||||
-rw-r--r-- | alc/backends/null.cpp | 2 | ||||
-rw-r--r-- | alc/backends/opensl.cpp | 6 | ||||
-rw-r--r-- | alc/backends/oss.cpp | 3 | ||||
-rw-r--r-- | alc/backends/portaudio.cpp | 3 | ||||
-rw-r--r-- | alc/backends/pulseaudio.cpp | 2 | ||||
-rw-r--r-- | alc/backends/sdl2.cpp | 2 | ||||
-rw-r--r-- | alc/backends/sndio.cpp | 3 | ||||
-rw-r--r-- | alc/backends/solaris.cpp | 3 | ||||
-rw-r--r-- | alc/backends/wasapi.cpp | 43 | ||||
-rw-r--r-- | alc/backends/wave.cpp | 3 | ||||
-rw-r--r-- | alc/backends/winmm.cpp | 4 |
15 files changed, 58 insertions, 36 deletions
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 7dc3c3c4..236e7a2f 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -446,6 +446,7 @@ int AlsaPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t samplebits{mDevice->bytesFromFmt() * 8}; const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; const snd_pcm_uframes_t buffer_size{mDevice->BufferSize}; while(!mKillNow.load(std::memory_order_acquire)) @@ -507,7 +508,7 @@ int AlsaPlayback::mixerProc() } char *WritePtr{static_cast<char*>(areas->addr) + (offset * areas->step / 8)}; - aluMixData(mDevice, WritePtr, static_cast<ALuint>(frames)); + aluMixData(mDevice, WritePtr, static_cast<ALuint>(frames), areas->step / samplebits); snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)}; if(commitres < 0 || (static_cast<snd_pcm_uframes_t>(commitres)-frames) != 0) @@ -529,6 +530,7 @@ int AlsaPlayback::mixerNoMMapProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frame_step{mDevice->channelsFromFmt()}; const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; const snd_pcm_uframes_t buffer_size{mDevice->BufferSize}; while(!mKillNow.load(std::memory_order_acquire)) @@ -574,7 +576,7 @@ int AlsaPlayback::mixerNoMMapProc() std::lock_guard<AlsaPlayback> _{*this}; al::byte *WritePtr{mBuffer.data()}; avail = snd_pcm_bytes_to_frames(mPcmHandle, static_cast<ssize_t>(mBuffer.size())); - aluMixData(mDevice, WritePtr, static_cast<ALuint>(avail)); + aluMixData(mDevice, WritePtr, static_cast<ALuint>(avail), frame_step); while(avail > 0) { snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 7c18287b..a8527bed 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -82,7 +82,8 @@ OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTi UInt32, AudioBufferList *ioData) noexcept { std::lock_guard<CoreAudioPlayback> _{*this}; - aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); + aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize, + ioData->mBuffers[0].mNumberChannels); return noErr; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index c04ba9e4..69fb5fb0 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -219,6 +219,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() return 1; } + const size_t FrameStep{mDevice->channelsFromFmt()}; ALuint FrameSize{mDevice->frameSizeFromFmt()}; DWORD FragSize{mDevice->UpdateSize * FrameSize}; @@ -276,9 +277,9 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() if(SUCCEEDED(err)) { std::unique_lock<DSoundPlayback> dlock{*this}; - aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); + aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize, FrameStep); if(WriteCnt2 > 0) - aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); + aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize, FrameStep); dlock.unlock(); mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index c7bf8469..2be52e35 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -292,6 +292,8 @@ int JackPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frame_step{mDevice->channelsFromFmt()}; + std::unique_lock<JackPlayback> dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) @@ -311,9 +313,9 @@ int JackPlayback::mixerProc() ALuint len1{minu(static_cast<ALuint>(data.first.len), todo)}; ALuint len2{minu(static_cast<ALuint>(data.second.len), todo-len1)}; - aluMixData(mDevice, data.first.buf, len1); + aluMixData(mDevice, data.first.buf, len1, frame_step); if(len2 > 0) - aluMixData(mDevice, data.second.buf, len2); + aluMixData(mDevice, data.second.buf, len2, frame_step); mRing->writeAdvance(todo); } diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index bc2a0c9c..9f069be8 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -87,7 +87,7 @@ int NullBackend::mixerProc() while(avail-done >= mDevice->UpdateSize) { std::lock_guard<NullBackend> _{*this}; - aluMixData(mDevice, nullptr, mDevice->UpdateSize); + aluMixData(mDevice, nullptr, mDevice->UpdateSize, 0u); done += mDevice->UpdateSize; } diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index a1fdccc7..ab2b8c2c 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -228,6 +228,8 @@ int OpenSLPlayback::mixerProc() PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } + const size_t frame_step{mDevice->channelsFromFmt()}; + std::unique_lock<OpenSLPlayback> dlock{*this}; if(SL_RESULT_SUCCESS != result) aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); @@ -263,10 +265,10 @@ int OpenSLPlayback::mixerProc() auto data = mRing->getWriteVector(); aluMixData(mDevice, data.first.buf, - static_cast<ALuint>(data.first.len*mDevice->UpdateSize)); + static_cast<ALuint>(data.first.len*mDevice->UpdateSize), frame_step); if(data.second.len > 0) aluMixData(mDevice, data.second.buf, - static_cast<ALuint>(data.second.len*mDevice->UpdateSize)); + static_cast<ALuint>(data.second.len*mDevice->UpdateSize), frame_step); size_t todo{data.first.len + data.second.len}; mRing->writeAdvance(todo); diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 59cc44e4..b3f8936a 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -277,6 +277,7 @@ int OSSPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frame_step{mDevice->channelsFromFmt()}; const ALuint frame_size{mDevice->frameSizeFromFmt()}; std::unique_lock<OSSPlayback> dlock{*this}; @@ -306,7 +307,7 @@ int OSSPlayback::mixerProc() ALubyte *write_ptr{mMixData.data()}; size_t to_write{mMixData.size()}; - aluMixData(mDevice, write_ptr, static_cast<ALuint>(to_write/frame_size)); + aluMixData(mDevice, write_ptr, static_cast<ALuint>(to_write/frame_size), frame_step); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { ssize_t wrote{write(mFd, write_ptr, to_write)}; diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 1e3d0ce8..5de9ab58 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -110,7 +110,8 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long f const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) noexcept { std::lock_guard<PortPlayback> _{*this}; - aluMixData(mDevice, outputBuffer, static_cast<ALuint>(framesPerBuffer)); + aluMixData(mDevice, outputBuffer, static_cast<ALuint>(framesPerBuffer), + mDevice->channelsFromFmt()); return 0; } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 4e46460b..be4e742c 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -763,7 +763,7 @@ void PulsePlayback::streamStateCallback(pa_stream *stream) noexcept void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) noexcept { void *buf{pa_xmalloc(nbytes)}; - aluMixData(mDevice, buf, static_cast<ALuint>(nbytes/mFrameSize)); + aluMixData(mDevice, buf, static_cast<ALuint>(nbytes/mFrameSize), mDevice->channelsFromFmt()); int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; if UNLIKELY(ret != PA_OK) diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 25b5d4d9..abb240e4 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -85,7 +85,7 @@ void Sdl2Backend::audioCallback(Uint8 *stream, int len) noexcept { const auto ulen = static_cast<unsigned int>(len); assert((ulen % mFrameSize) == 0); - aluMixData(mDevice, stream, ulen / mFrameSize); + aluMixData(mDevice, stream, ulen / mFrameSize, mDevice->channelsFromFmt()); } void Sdl2Backend::open(const ALCchar *name) diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 7799316f..4d851391 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -77,6 +77,7 @@ int SndioPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frameStep{mDevice->channelsFromFmt()}; const ALuint frameSize{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire) && @@ -87,7 +88,7 @@ int SndioPlayback::mixerProc() { std::lock_guard<SndioPlayback> _{*this}; - aluMixData(mDevice, WritePtr, static_cast<ALuint>(len/frameSize)); + aluMixData(mDevice, WritePtr, static_cast<ALuint>(len/frameSize), frameStep); } while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 7cc2606e..6823777c 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -89,6 +89,7 @@ int SolarisBackend::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frame_step{mDevice->channelsFromFmt()}; const ALuint frame_size{mDevice->frameSizeFromFmt()}; std::unique_lock<SolarisBackend> dlock{*this}; @@ -119,7 +120,7 @@ int SolarisBackend::mixerProc() ALubyte *write_ptr{mBuffer.data()}; size_t to_write{mBuffer.size()}; - aluMixData(mDevice, write_ptr, to_write/frame_size); + aluMixData(mDevice, write_ptr, to_write/frame_size, frame_step); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { ssize_t wrote{write(mFd, write_ptr, to_write)}; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 37a547af..900e204f 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -106,6 +106,19 @@ inline int64_t ScaleCeil(int64_t val, int64_t new_scale, int64_t old_scale) } +class GuidPrinter { + char mMsg[64]; + +public: + GuidPrinter(const GUID &guid) + { + std::snprintf(mMsg, al::size(mMsg), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + DWORD{guid.Data1}, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], + guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + } + const char *c_str() const { return mMsg; } +}; + struct PropVariant { PROPVARIANT mProp; @@ -356,21 +369,6 @@ void TraceFormat(const char *msg, const WAVEFORMATEX *format) constexpr size_t fmtex_extra_size{sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)}; if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= fmtex_extra_size) { - class GuidPrinter { - char mMsg[64]; - - public: - GuidPrinter(const GUID &guid) - { - std::snprintf(mMsg, al::size(mMsg), - "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - DWORD{guid.Data1}, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - } - const char *c_str() const { return mMsg; } - }; - const WAVEFORMATEXTENSIBLE *fmtex{ CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format)}; TRACE("%s:\n" @@ -452,7 +450,8 @@ struct WasapiProxy { { std::promise<HRESULT> promise; std::future<HRESULT> future{promise.get_future()}; - { std::lock_guard<std::mutex> _{mMsgQueueLock}; + { + std::lock_guard<std::mutex> _{mMsgQueueLock}; mMsgQueue.emplace_back(Msg{type, this, std::move(promise)}); } mMsgQueueCond.notify_one(); @@ -463,7 +462,8 @@ struct WasapiProxy { { std::promise<HRESULT> promise; std::future<HRESULT> future{promise.get_future()}; - { std::lock_guard<std::mutex> _{mMsgQueueLock}; + { + std::lock_guard<std::mutex> _{mMsgQueueLock}; mMsgQueue.emplace_back(Msg{type, nullptr, std::move(promise)}); } mMsgQueueCond.notify_one(); @@ -631,6 +631,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { IAudioRenderClient *mRender{nullptr}; HANDLE mNotifyEvent{nullptr}; + UINT32 mFrameStep{0u}; std::atomic<UINT32> mPadding{0u}; std::atomic<bool> mKillNow{true}; @@ -690,7 +691,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(SUCCEEDED(hr)) { std::unique_lock<WasapiPlayback> dlock{*this}; - aluMixData(mDevice, buffer, len); + aluMixData(mDevice, buffer, len, mFrameStep); mPadding.store(written + len, std::memory_order_relaxed); dlock.unlock(); hr = mRender->ReleaseBuffer(len, 0); @@ -988,6 +989,11 @@ HRESULT WasapiPlayback::resetProxy() mDevice->FmtChans = DevFmtX61; else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) mDevice->FmtChans = DevFmtX71; + else if(OutputType.Format.nChannels >= 2 && (OutputType.dwChannelMask&STEREO) == STEREO) + { + TRACE("Mixing stereo over channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + mDevice->FmtChans = DevFmtStereo; + } else { ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); @@ -1026,6 +1032,7 @@ HRESULT WasapiPlayback::resetProxy() } OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; } + mFrameStep = OutputType.Format.nChannels; EndpointFormFactor formfactor = UnknownFormFactor; get_device_formfactor(mMMDev, &formfactor); diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 7bcc3436..4f357970 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -126,6 +126,7 @@ int WaveBackend::mixerProc() althrd_setname(MIXER_THREAD_NAME); + const size_t frameStep{mDevice->channelsFromFmt()}; const ALuint frameSize{mDevice->frameSizeFromFmt()}; int64_t done{0}; @@ -147,7 +148,7 @@ int WaveBackend::mixerProc() { { std::lock_guard<WaveBackend> _{*this}; - aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); + aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize, frameStep); } done += mDevice->UpdateSize; diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 649bb345..82625e1f 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -180,6 +180,8 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); + const size_t frame_step{mDevice->channelsFromFmt()}; + std::unique_lock<WinMMPlayback> dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) @@ -198,7 +200,7 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() WAVEHDR &waveHdr = mWaveBuffer[widx]; widx = (widx+1) % mWaveBuffer.size(); - aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize); + aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize, frame_step); mWritable.fetch_sub(1, std::memory_order_acq_rel); waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); |