Files
yuzu/src/audio_core/sink/sink_details.cpp

114 lines
3.5 KiB
C++
Raw Normal View History

2022-07-07 09:40:51 +02:00
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
2022-09-02 21:29:33 +02:00
2022-07-07 09:40:51 +02:00
#include "audio_core/sink/sink_details.h"
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
#ifdef HAVE_SDL2
#include "audio_core/sink/sdl2_sink.h"
#endif
2022-09-02 21:29:33 +02:00
#include "audio_core/sink/null_sink.h"
2022-07-07 09:40:51 +02:00
#include "common/logging/log.h"
namespace AudioCore::Sink {
namespace {
struct SinkDetails {
using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view);
using ListDevicesFn = std::vector<std::string> (*)(bool);
2022-10-09 22:48:39 +02:00
using LatencyFn = u32 (*)();
2022-07-07 09:40:51 +02:00
/// Name for this sink.
2022-10-09 22:48:39 +02:00
std::string_view id;
2022-07-07 09:40:51 +02:00
/// A method to call to construct an instance of this type of sink.
FactoryFn factory;
/// A method to call to list available devices.
ListDevicesFn list_devices;
2022-10-09 22:48:39 +02:00
/// Method to get the latency of this backend.
LatencyFn latency;
2022-07-07 09:40:51 +02:00
};
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef HAVE_CUBEB
2022-10-09 22:48:39 +02:00
SinkDetails{
"cubeb",
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<CubebSink>(device_id);
},
&ListCubebSinkDevices,
&GetCubebLatency,
},
2022-07-07 09:40:51 +02:00
#endif
#ifdef HAVE_SDL2
2022-10-09 22:48:39 +02:00
SinkDetails{
2022-10-14 21:58:05 +02:00
"sdl2",
2022-10-09 22:48:39 +02:00
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<SDLSink>(device_id);
},
&ListSDLSinkDevices,
&GetSDLLatency,
},
2022-07-07 09:40:51 +02:00
#endif
SinkDetails{"null",
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<NullSink>(device_id);
},
2022-10-09 22:48:39 +02:00
[](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }},
2022-07-07 09:40:51 +02:00
};
const SinkDetails& GetOutputSinkDetails(std::string_view sink_id) {
2022-10-09 22:48:39 +02:00
const auto find_backend{[](std::string_view id) {
return std::find_if(std::begin(sink_details), std::end(sink_details),
[&id](const auto& sink_detail) { return sink_detail.id == id; });
}};
2022-07-07 09:40:51 +02:00
2022-10-09 22:48:39 +02:00
auto iter = find_backend(sink_id);
if (sink_id == "auto") {
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
// causes audio issues, in that case go with SDL.
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
iter = find_backend("cubeb");
if (iter->latency() > TargetSampleCount * 3) {
2022-10-14 21:58:05 +02:00
iter = find_backend("sdl2");
2022-07-07 09:40:51 +02:00
}
2022-10-09 22:48:39 +02:00
#else
2022-07-07 09:40:51 +02:00
iter = std::begin(sink_details);
2022-10-09 22:48:39 +02:00
#endif
LOG_INFO(Service_Audio, "Auto-selecting the {} backend", iter->id);
}
if (iter == std::end(sink_details)) {
LOG_ERROR(Audio, "Invalid sink_id {}", sink_id);
iter = find_backend("null");
2022-07-07 09:40:51 +02:00
}
return *iter;
}
} // Anonymous namespace
2022-10-09 22:48:39 +02:00
std::vector<std::string_view> GetSinkIDs() {
std::vector<std::string_view> sink_ids(std::size(sink_details));
2022-07-07 09:40:51 +02:00
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
[](const auto& sink) { return sink.id; });
return sink_ids;
}
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture) {
return GetOutputSinkDetails(sink_id).list_devices(capture);
}
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
return GetOutputSinkDetails(sink_id).factory(device_id);
}
} // namespace AudioCore::Sink