mirror of
https://github.com/citra-emu/citra-canary.git
synced 2024-12-23 20:25:37 +00:00
cubeb_sink: Improve logging
This commit is contained in:
parent
675ffc1024
commit
a6cf2e1f9d
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cubeb/cubeb.h>
|
#include <cubeb/cubeb.h>
|
||||||
|
@ -22,6 +23,7 @@ struct CubebSink::Impl {
|
||||||
static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||||
void* output_buffer, long num_frames);
|
void* output_buffer, long num_frames);
|
||||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
|
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>()) {
|
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");
|
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cubeb_set_log_callback(CUBEB_LOG_NORMAL, &Impl::LogCallback);
|
||||||
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;
|
|
||||||
|
|
||||||
impl->sample_rate = native_sample_rate;
|
impl->sample_rate = native_sample_rate;
|
||||||
|
|
||||||
u32 minimum_latency = 0;
|
cubeb_stream_params params;
|
||||||
if (cubeb_get_min_latency(impl->ctx, ¶ms, &minimum_latency) != CUBEB_OK)
|
params.rate = impl->sample_rate;
|
||||||
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
|
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()) {
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
cubeb_device_collection collection;
|
cubeb_device_collection collection;
|
||||||
if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
|
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,
|
int stream_err = cubeb_stream_init(impl->ctx, &impl->stream, "CitraAudio", nullptr, nullptr,
|
||||||
output_device, ¶ms, std::max(512u, minimum_latency),
|
output_device, ¶ms, std::max(512u, minimum_latency),
|
||||||
&Impl::DataCallback, &Impl::StateCallback, impl.get()) != CUBEB_OK) {
|
&Impl::DataCallback, &Impl::StateCallback, impl.get());
|
||||||
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +91,11 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp
|
||||||
}
|
}
|
||||||
|
|
||||||
CubebSink::~CubebSink() {
|
CubebSink::~CubebSink() {
|
||||||
if (!impl->ctx)
|
if (!impl->ctx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl->cb = nullptr;
|
||||||
|
|
||||||
if (cubeb_stream_stop(impl->stream) != CUBEB_OK) {
|
if (cubeb_stream_stop(impl->stream) != CUBEB_OK) {
|
||||||
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
|
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);
|
Impl* impl = static_cast<Impl*>(user_data);
|
||||||
s16* buffer = reinterpret_cast<s16*>(output_buffer);
|
s16* buffer = reinterpret_cast<s16*>(output_buffer);
|
||||||
|
|
||||||
if (!impl || !impl->cb)
|
if (!impl || !impl->cb) {
|
||||||
return 0;
|
LOG_DEBUG(Audio_Sink, "Emitting zeros");
|
||||||
|
std::memset(output_buffer, 0, num_frames * 2 * sizeof(s16));
|
||||||
|
return num_frames;
|
||||||
|
}
|
||||||
|
|
||||||
impl->cb(buffer, num_frames);
|
impl->cb(buffer, num_frames);
|
||||||
|
|
||||||
return 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> ListCubebSinkDevices() {
|
||||||
std::vector<std::string> device_list;
|
std::vector<std::string> device_list;
|
||||||
cubeb* ctx;
|
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");
|
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ DspInterface::DspInterface() = default;
|
||||||
DspInterface::~DspInterface() = default;
|
DspInterface::~DspInterface() = default;
|
||||||
|
|
||||||
void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
|
void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
|
||||||
sink.reset();
|
|
||||||
const SinkDetails& sink_details = GetSinkDetails(sink_id);
|
const SinkDetails& sink_details = GetSinkDetails(sink_id);
|
||||||
sink = sink_details.factory(audio_device);
|
sink = sink_details.factory(audio_device);
|
||||||
sink->SetCallback(
|
sink->SetCallback(
|
||||||
|
|
Loading…
Reference in a new issue