cubeb_sink: Improve logging
This commit is contained in:
parent
675ffc1024
commit
a6cf2e1f9d
2 changed files with 71 additions and 21 deletions
|
@ -2,6 +2,7 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstdarg>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <cubeb/cubeb.h>
|
||||
|
@ -22,6 +23,7 @@ struct CubebSink::Impl {
|
|||
static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||
void* output_buffer, long num_frames);
|
||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
|
||||
static void LogCallback(char const* fmt, ...);
|
||||
};
|
||||
|
||||
CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Impl>()) {
|
||||
|
@ -29,21 +31,23 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp
|
|||
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
cubeb_devid output_device = nullptr;
|
||||
|
||||
cubeb_stream_params params;
|
||||
params.rate = native_sample_rate;
|
||||
params.channels = 2;
|
||||
params.format = CUBEB_SAMPLE_S16NE;
|
||||
params.layout = CUBEB_LAYOUT_STEREO;
|
||||
cubeb_set_log_callback(CUBEB_LOG_NORMAL, &Impl::LogCallback);
|
||||
|
||||
impl->sample_rate = native_sample_rate;
|
||||
|
||||
u32 minimum_latency = 0;
|
||||
if (cubeb_get_min_latency(impl->ctx, ¶ms, &minimum_latency) != CUBEB_OK)
|
||||
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
|
||||
cubeb_stream_params params;
|
||||
params.rate = impl->sample_rate;
|
||||
params.channels = 2;
|
||||
params.layout = CUBEB_LAYOUT_STEREO;
|
||||
params.format = CUBEB_SAMPLE_S16NE;
|
||||
params.prefs = CUBEB_STREAM_PREF_NONE;
|
||||
|
||||
u32 minimum_latency = 100 * impl->sample_rate / 1000; // Firefox default
|
||||
if (cubeb_get_min_latency(impl->ctx, ¶ms, &minimum_latency) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
|
||||
}
|
||||
|
||||
cubeb_devid output_device = nullptr;
|
||||
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||
cubeb_device_collection collection;
|
||||
if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
|
||||
|
@ -61,10 +65,22 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp
|
|||
}
|
||||
}
|
||||
|
||||
if (cubeb_stream_init(impl->ctx, &impl->stream, "Citra Audio Output", nullptr, nullptr,
|
||||
output_device, ¶ms, std::max(512u, minimum_latency),
|
||||
&Impl::DataCallback, &Impl::StateCallback, impl.get()) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
|
||||
int stream_err = cubeb_stream_init(impl->ctx, &impl->stream, "CitraAudio", nullptr, nullptr,
|
||||
output_device, ¶ms, std::max(512u, minimum_latency),
|
||||
&Impl::DataCallback, &Impl::StateCallback, impl.get());
|
||||
if (stream_err != CUBEB_OK) {
|
||||
switch (stream_err) {
|
||||
case CUBEB_ERROR:
|
||||
default:
|
||||
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream ({})", stream_err);
|
||||
break;
|
||||
case CUBEB_ERROR_INVALID_FORMAT:
|
||||
LOG_CRITICAL(Audio_Sink, "Invalid format when initializing cubeb stream");
|
||||
break;
|
||||
case CUBEB_ERROR_DEVICE_UNAVAILABLE:
|
||||
LOG_CRITICAL(Audio_Sink, "Device unavailable when initializing cubeb stream");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -75,8 +91,11 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp
|
|||
}
|
||||
|
||||
CubebSink::~CubebSink() {
|
||||
if (!impl->ctx)
|
||||
if (!impl->ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
impl->cb = nullptr;
|
||||
|
||||
if (cubeb_stream_stop(impl->stream) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
|
||||
|
@ -102,21 +121,53 @@ long CubebSink::Impl::DataCallback(cubeb_stream* stream, void* user_data, const
|
|||
Impl* impl = static_cast<Impl*>(user_data);
|
||||
s16* buffer = reinterpret_cast<s16*>(output_buffer);
|
||||
|
||||
if (!impl || !impl->cb)
|
||||
return 0;
|
||||
if (!impl || !impl->cb) {
|
||||
LOG_DEBUG(Audio_Sink, "Emitting zeros");
|
||||
std::memset(output_buffer, 0, num_frames * 2 * sizeof(s16));
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
impl->cb(buffer, num_frames);
|
||||
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
void CubebSink::Impl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
|
||||
void CubebSink::Impl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
LOG_INFO(Audio_Sink, "Cubeb Audio Stream Started");
|
||||
break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
LOG_INFO(Audio_Sink, "Cubeb Audio Stream Stopped");
|
||||
break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
LOG_INFO(Audio_Sink, "Cubeb Audio Stream Drained");
|
||||
break;
|
||||
case CUBEB_STATE_ERROR:
|
||||
LOG_CRITICAL(Audio_Sink, "Cubeb Audio Stream Errored");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CubebSink::Impl::LogCallback(char const* format, ...) {
|
||||
std::array<char, 512> buffer;
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
#ifdef _MSC_VER
|
||||
vsprintf_s(buffer.data(), buffer.size(), format, args);
|
||||
#else
|
||||
vsnprintf(buffer.data(), buffer.size(), format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
buffer.back() = '\0';
|
||||
LOG_INFO(Audio_Sink, "{}", buffer.data());
|
||||
}
|
||||
|
||||
std::vector<std::string> ListCubebSinkDevices() {
|
||||
std::vector<std::string> device_list;
|
||||
cubeb* ctx;
|
||||
|
||||
if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) {
|
||||
if (cubeb_init(&ctx, "CitraEnumerator", nullptr) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ DspInterface::DspInterface() = default;
|
|||
DspInterface::~DspInterface() = default;
|
||||
|
||||
void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
|
||||
sink.reset();
|
||||
const SinkDetails& sink_details = GetSinkDetails(sink_id);
|
||||
sink = sink_details.factory(audio_device);
|
||||
sink->SetCallback(
|
||||
|
|
Loading…
Reference in a new issue