mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 13:02:35 +00:00
* 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.
This commit is contained in:
parent
f2e8fd45f8
commit
06bdf32959
@ -52,6 +52,8 @@ using namespace musik::core::sdk;
|
|||||||
static const char* TAG = "ffmpegdecoder";
|
static const char* TAG = "ffmpegdecoder";
|
||||||
static IDebug* debug = nullptr;
|
static IDebug* debug = nullptr;
|
||||||
|
|
||||||
|
#define RESOLVE_SAMPLE_RATE() this->preferredSampleRate > 0 ? this->preferredSampleRate : this->rate
|
||||||
|
|
||||||
extern "C" DLLEXPORT void SetDebug(IDebug* debug) {
|
extern "C" DLLEXPORT void SetDebug(IDebug* debug) {
|
||||||
::debug = debug;
|
::debug = debug;
|
||||||
}
|
}
|
||||||
@ -149,6 +151,7 @@ FfmpegDecoder::FfmpegDecoder() {
|
|||||||
this->bufferSize = AV_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
|
this->bufferSize = AV_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
|
||||||
this->buffer = new unsigned char[this->bufferSize];
|
this->buffer = new unsigned char[this->bufferSize];
|
||||||
this->outputFifo = nullptr;
|
this->outputFifo = nullptr;
|
||||||
|
this->preferredSampleRate = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FfmpegDecoder::~FfmpegDecoder() {
|
FfmpegDecoder::~FfmpegDecoder() {
|
||||||
@ -192,7 +195,7 @@ double FfmpegDecoder::SetPosition(double seconds) {
|
|||||||
|
|
||||||
bool FfmpegDecoder::GetBuffer(IBuffer *buffer) {
|
bool FfmpegDecoder::GetBuffer(IBuffer *buffer) {
|
||||||
if (this->ioContext) {
|
if (this->ioContext) {
|
||||||
buffer->SetSampleRate((long) this->rate);
|
buffer->SetSampleRate((long) RESOLVE_SAMPLE_RATE());
|
||||||
buffer->SetChannels((long) this->channels);
|
buffer->SetChannels((long) this->channels);
|
||||||
buffer->SetSamples(0);
|
buffer->SetSamples(0);
|
||||||
|
|
||||||
@ -256,7 +259,7 @@ bool FfmpegDecoder::InitializeResampler(IBuffer* buffer) {
|
|||||||
this->resampler,
|
this->resampler,
|
||||||
this->codecContext->channel_layout,
|
this->codecContext->channel_layout,
|
||||||
AV_SAMPLE_FMT_FLT,
|
AV_SAMPLE_FMT_FLT,
|
||||||
(int) this->rate,
|
(int) RESOLVE_SAMPLE_RATE(),
|
||||||
this->codecContext->channel_layout,
|
this->codecContext->channel_layout,
|
||||||
this->codecContext->sample_fmt,
|
this->codecContext->sample_fmt,
|
||||||
this->codecContext->sample_rate,
|
this->codecContext->sample_rate,
|
||||||
@ -404,7 +407,7 @@ bool FfmpegDecoder::ReadSendAndReceivePacket(AVPacket* packet) {
|
|||||||
this->resampledFrame = this->AllocFrame(
|
this->resampledFrame = this->AllocFrame(
|
||||||
this->resampledFrame,
|
this->resampledFrame,
|
||||||
AV_SAMPLE_FMT_FLT,
|
AV_SAMPLE_FMT_FLT,
|
||||||
this->rate,
|
RESOLVE_SAMPLE_RATE(),
|
||||||
this->decodedFrame->nb_samples);
|
this->decodedFrame->nb_samples);
|
||||||
|
|
||||||
error = swr_convert_frame(
|
error = swr_convert_frame(
|
||||||
|
@ -64,7 +64,7 @@ class FfmpegDecoder: public musik::core::sdk::IDecoder {
|
|||||||
double GetDuration() override;
|
double GetDuration() override;
|
||||||
bool Open(musik::core::sdk::IDataStream *stream) override;
|
bool Open(musik::core::sdk::IDataStream *stream) override;
|
||||||
bool Exhausted() override;
|
bool Exhausted() override;
|
||||||
void SetPreferredSampleRate(int rate) override { }
|
void SetPreferredSampleRate(int rate) override { this->preferredSampleRate = rate; }
|
||||||
|
|
||||||
IDataStream* Stream() { return this->stream; }
|
IDataStream* Stream() { return this->stream; }
|
||||||
|
|
||||||
@ -87,6 +87,7 @@ class FfmpegDecoder: public musik::core::sdk::IDecoder {
|
|||||||
AVFrame* resampledFrame;
|
AVFrame* resampledFrame;
|
||||||
SwrContext* resampler;
|
SwrContext* resampler;
|
||||||
unsigned char* buffer;
|
unsigned char* buffer;
|
||||||
|
int preferredSampleRate { -1 };
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
int rate, channels;
|
int rate, channels;
|
||||||
int streamId;
|
int streamId;
|
||||||
|
@ -514,19 +514,33 @@ found_or_done:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WasapiOut::Configure(IBuffer *buffer) {
|
int WasapiOut::GetDefaultSampleRate() {
|
||||||
HRESULT result;
|
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->audioClient) {
|
||||||
if (!this->enumerator) {
|
if (!this->enumerator) {
|
||||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
||||||
|
|
||||||
result = CoCreateInstance(
|
result = CoCreateInstance(
|
||||||
__uuidof(MMDeviceEnumerator),
|
__uuidof(MMDeviceEnumerator),
|
||||||
NULL,
|
NULL,
|
||||||
CLSCTX_ALL,
|
CLSCTX_ALL,
|
||||||
__uuidof(IMMDeviceEnumerator),
|
__uuidof(IMMDeviceEnumerator),
|
||||||
(void**) &this->enumerator);
|
(void**)&this->enumerator);
|
||||||
|
|
||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
return false;
|
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())
|
waveFormat.Format.nSamplesPerSec == buffer->SampleRate())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
this->Reset();
|
||||||
|
this->InitializeAudioClient();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD speakerConfig = 0;
|
DWORD speakerConfig = 0;
|
||||||
switch (buffer->Channels()) {
|
switch (buffer->Channels()) {
|
||||||
@ -605,6 +625,8 @@ bool WasapiOut::Configure(IBuffer *buffer) {
|
|||||||
wf.dwChannelMask = speakerConfig;
|
wf.dwChannelMask = speakerConfig;
|
||||||
wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||||
|
|
||||||
|
HRESULT result = S_FALSE;
|
||||||
|
|
||||||
DWORD streamFlags = 0;
|
DWORD streamFlags = 0;
|
||||||
if (this->audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *) &wf, 0) != S_OK) {
|
if (this->audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *) &wf, 0) != S_OK) {
|
||||||
streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
|
streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
|
||||||
|
@ -70,6 +70,7 @@ class WasapiOut : public IOutput {
|
|||||||
IDeviceList* GetDeviceList() override;
|
IDeviceList* GetDeviceList() override;
|
||||||
bool SetDefaultDevice(const char* deviceId) override;
|
bool SetDefaultDevice(const char* deviceId) override;
|
||||||
IDevice* GetDefaultDevice() override;
|
IDevice* GetDefaultDevice() override;
|
||||||
|
int GetDefaultSampleRate() override;
|
||||||
|
|
||||||
void OnDeviceChanged() { this->deviceChanged = true; }
|
void OnDeviceChanged() { this->deviceChanged = true; }
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ class WasapiOut : public IOutput {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool Configure(IBuffer *buffer);
|
bool Configure(IBuffer *buffer);
|
||||||
|
bool InitializeAudioClient();
|
||||||
void Reset();
|
void Reset();
|
||||||
IMMDevice* GetPreferredDevice();
|
IMMDevice* GetPreferredDevice();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user