From a6cf2e1f9d706f3f5c9d66d7209a9a925e6d89f5 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 9 Sep 2018 08:37:34 +0100 Subject: [PATCH] cubeb_sink: Improve logging --- src/audio_core/cubeb_sink.cpp | 91 +++++++++++++++++++++++++------- src/audio_core/dsp_interface.cpp | 1 - 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp index 0dda3e826..c39afe349 100644 --- a/src/audio_core/cubeb_sink.cpp +++ b/src/audio_core/cubeb_sink.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -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()) { @@ -29,21 +31,23 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_uniquesample_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_uniquectx, &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_uniquectx) + 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(user_data); s16* buffer = reinterpret_cast(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 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 ListCubebSinkDevices() { std::vector 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 {}; } diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp index aa4bb1fd1..d6343d332 100644 --- a/src/audio_core/dsp_interface.cpp +++ b/src/audio_core/dsp_interface.cpp @@ -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(