From 06bdf32959b57e16694521754562d914c53acdb7 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 19 Sep 2021 21:50:54 -0700 Subject: [PATCH] * Updated WasapiOut to provide the preferred sample rate for the selected device * Updated FfmpegDecoder to accept the preferred sample rate from the output, and use it when resampling if it is non-negative. Otherwise, use the sample rate defined by the file. Note: this is not wired up in the main app yet. --- src/plugins/ffmpegdecoder/FfmpegDecoder.cpp | 9 ++- src/plugins/ffmpegdecoder/FfmpegDecoder.h | 3 +- src/plugins/wasapiout/WasapiOut.cpp | 84 +++++++++++++-------- src/plugins/wasapiout/WasapiOut.h | 2 + 4 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/plugins/ffmpegdecoder/FfmpegDecoder.cpp b/src/plugins/ffmpegdecoder/FfmpegDecoder.cpp index a90bff162..c8bb74ba6 100644 --- a/src/plugins/ffmpegdecoder/FfmpegDecoder.cpp +++ b/src/plugins/ffmpegdecoder/FfmpegDecoder.cpp @@ -52,6 +52,8 @@ using namespace musik::core::sdk; static const char* TAG = "ffmpegdecoder"; static IDebug* debug = nullptr; +#define RESOLVE_SAMPLE_RATE() this->preferredSampleRate > 0 ? this->preferredSampleRate : this->rate + extern "C" DLLEXPORT void SetDebug(IDebug* debug) { ::debug = debug; } @@ -149,6 +151,7 @@ FfmpegDecoder::FfmpegDecoder() { this->bufferSize = AV_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE; this->buffer = new unsigned char[this->bufferSize]; this->outputFifo = nullptr; + this->preferredSampleRate = -1; } FfmpegDecoder::~FfmpegDecoder() { @@ -192,7 +195,7 @@ double FfmpegDecoder::SetPosition(double seconds) { bool FfmpegDecoder::GetBuffer(IBuffer *buffer) { if (this->ioContext) { - buffer->SetSampleRate((long) this->rate); + buffer->SetSampleRate((long) RESOLVE_SAMPLE_RATE()); buffer->SetChannels((long) this->channels); buffer->SetSamples(0); @@ -256,7 +259,7 @@ bool FfmpegDecoder::InitializeResampler(IBuffer* buffer) { this->resampler, this->codecContext->channel_layout, AV_SAMPLE_FMT_FLT, - (int) this->rate, + (int) RESOLVE_SAMPLE_RATE(), this->codecContext->channel_layout, this->codecContext->sample_fmt, this->codecContext->sample_rate, @@ -404,7 +407,7 @@ bool FfmpegDecoder::ReadSendAndReceivePacket(AVPacket* packet) { this->resampledFrame = this->AllocFrame( this->resampledFrame, AV_SAMPLE_FMT_FLT, - this->rate, + RESOLVE_SAMPLE_RATE(), this->decodedFrame->nb_samples); error = swr_convert_frame( diff --git a/src/plugins/ffmpegdecoder/FfmpegDecoder.h b/src/plugins/ffmpegdecoder/FfmpegDecoder.h index cbcc09129..9e3dc2db2 100644 --- a/src/plugins/ffmpegdecoder/FfmpegDecoder.h +++ b/src/plugins/ffmpegdecoder/FfmpegDecoder.h @@ -64,7 +64,7 @@ class FfmpegDecoder: public musik::core::sdk::IDecoder { double GetDuration() override; bool Open(musik::core::sdk::IDataStream *stream) override; bool Exhausted() override; - void SetPreferredSampleRate(int rate) override { } + void SetPreferredSampleRate(int rate) override { this->preferredSampleRate = rate; } IDataStream* Stream() { return this->stream; } @@ -87,6 +87,7 @@ class FfmpegDecoder: public musik::core::sdk::IDecoder { AVFrame* resampledFrame; SwrContext* resampler; unsigned char* buffer; + int preferredSampleRate { -1 }; int bufferSize; int rate, channels; int streamId; diff --git a/src/plugins/wasapiout/WasapiOut.cpp b/src/plugins/wasapiout/WasapiOut.cpp index cca2b0788..d4c9b7914 100644 --- a/src/plugins/wasapiout/WasapiOut.cpp +++ b/src/plugins/wasapiout/WasapiOut.cpp @@ -514,19 +514,33 @@ found_or_done: return result; } -bool WasapiOut::Configure(IBuffer *buffer) { - HRESULT result; +int WasapiOut::GetDefaultSampleRate() { + int result = -1; + this->InitializeAudioClient(); + if (this->audioClient) { + WAVEFORMATEX* deviceFormat = nullptr; + audioClient->GetMixFormat(&deviceFormat); + if (deviceFormat) { + result = deviceFormat->nSamplesPerSec; + CoTaskMemFree(deviceFormat); + } + } + return result; +} + +bool WasapiOut::InitializeAudioClient() { + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + HRESULT result = S_FALSE; if (!this->audioClient) { if (!this->enumerator) { - CoInitializeEx(nullptr, COINIT_MULTITHREADED); - result = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), - (void**) &this->enumerator); + (void**)&this->enumerator); if (result != S_OK) { return false; @@ -542,37 +556,43 @@ bool WasapiOut::Configure(IBuffer *buffer) { } } - if (waveFormat.Format.nChannels == buffer->Channels() && + if (!this->device) { + bool preferredDeviceOk = false; + + IMMDevice* preferredDevice = this->GetPreferredDevice(); + if (preferredDevice) { + if ((result = preferredDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&this->audioClient)) == S_OK) { + preferredDeviceOk = true; + this->device = preferredDevice; + } + } + + if (!preferredDeviceOk) { + if (preferredDevice) { + preferredDevice->Release(); + } + + if ((result = this->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &this->device)) != S_OK) { + return false; + } + } + + if ((result = this->device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&this->audioClient)) != S_OK) { + return false; + } + } +} + +bool WasapiOut::Configure(IBuffer *buffer) { + if (this->audioClient && + waveFormat.Format.nChannels == buffer->Channels() && waveFormat.Format.nSamplesPerSec == buffer->SampleRate()) { return true; } - CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - bool preferredDeviceOk = false; - - IMMDevice* preferredDevice = this->GetPreferredDevice(); - if (preferredDevice) { - if ((result = preferredDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**) &this->audioClient)) == S_OK) { - preferredDeviceOk = true; - this->device = preferredDevice; - } - } - - if (!preferredDeviceOk) { - if (preferredDevice) { - preferredDevice->Release(); - } - - if ((result = this->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &this->device)) != S_OK) { - return false; - } - } - - if ((result = this->device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**) &this->audioClient)) != S_OK) { - return false; - } + this->Reset(); + this->InitializeAudioClient(); DWORD speakerConfig = 0; switch (buffer->Channels()) { @@ -605,6 +625,8 @@ bool WasapiOut::Configure(IBuffer *buffer) { wf.dwChannelMask = speakerConfig; wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + HRESULT result = S_FALSE; + DWORD streamFlags = 0; if (this->audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *) &wf, 0) != S_OK) { streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; diff --git a/src/plugins/wasapiout/WasapiOut.h b/src/plugins/wasapiout/WasapiOut.h index 71c1daf09..c167f731f 100644 --- a/src/plugins/wasapiout/WasapiOut.h +++ b/src/plugins/wasapiout/WasapiOut.h @@ -70,6 +70,7 @@ class WasapiOut : public IOutput { IDeviceList* GetDeviceList() override; bool SetDefaultDevice(const char* deviceId) override; IDevice* GetDefaultDevice() override; + int GetDefaultSampleRate() override; void OnDeviceChanged() { this->deviceChanged = true; } @@ -81,6 +82,7 @@ class WasapiOut : public IOutput { }; bool Configure(IBuffer *buffer); + bool InitializeAudioClient(); void Reset(); IMMDevice* GetPreferredDevice();