Revert "audio: refactor SDL2 sink implementation"

This reverts commit 3aa9c0d151.
This commit is contained in:
Zephyron 2025-02-20 16:54:43 +10:00
parent 0576d40bf0
commit 4d50d2ba16
2 changed files with 132 additions and 114 deletions

View file

@ -1,5 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <span>
@ -17,9 +16,138 @@ namespace AudioCore::Sink {
/**
* SDL sink stream, responsible for sinking samples to hardware.
*/
// class SDLSinkStream final : public SinkStream {
// ...
// }
class SDLSinkStream final : public SinkStream {
public:
/**
* Create a new sink stream.
*
* @param device_channels_ - Number of channels supported by the hardware.
* @param system_channels_ - Number of channels the audio systems expect.
* @param output_device - Name of the output device to use for this stream.
* @param input_device - Name of the input device to use for this stream.
* @param type_ - Type of this stream.
* @param system_ - Core system.
* @param event - Event used only for audio renderer, signalled on buffer consume.
*/
SDLSinkStream(u32 device_channels_, u32 system_channels_, const std::string& output_device,
const std::string& input_device, StreamType type_, Core::System& system_)
: SinkStream{system_, type_} {
system_channels = system_channels_;
device_channels = device_channels_;
SDL_AudioSpec spec;
spec.freq = TargetSampleRate;
spec.channels = static_cast<u8>(device_channels);
spec.format = AUDIO_S16SYS;
spec.samples = TargetSampleCount * 2;
spec.callback = &SDLSinkStream::DataCallback;
spec.userdata = this;
std::string device_name{output_device};
bool capture{false};
if (type == StreamType::In) {
device_name = input_device;
capture = true;
}
SDL_AudioSpec obtained;
if (device_name.empty()) {
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
} else {
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
}
if (device == 0) {
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
return;
}
LOG_INFO(Service_Audio,
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
" samples {}",
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
}
/**
* Destroy the sink stream.
*/
~SDLSinkStream() override {
LOG_DEBUG(Service_Audio, "Destructing SDL stream {}", name);
Finalize();
}
/**
* Finalize the sink stream.
*/
void Finalize() override {
if (device == 0) {
return;
}
Stop();
SDL_ClearQueuedAudio(device);
SDL_CloseAudioDevice(device);
}
/**
* Start the sink stream.
*
* @param resume - Set to true if this is resuming the stream a previously-active stream.
* Default false.
*/
void Start(bool resume = false) override {
if (device == 0 || !paused) {
return;
}
paused = false;
SDL_PauseAudioDevice(device, 0);
}
/**
* Stop the sink stream.
*/
void Stop() override {
if (device == 0 || paused) {
return;
}
SignalPause();
SDL_PauseAudioDevice(device, 1);
}
private:
/**
* Main callback from SDL. Either expects samples from us (audio render/audio out), or will
* provide samples to be copied (audio in).
*
* @param userdata - Custom data pointer passed along, points to a SDLSinkStream.
* @param stream - Buffer of samples to be filled or read.
* @param len - Length of the stream in bytes.
*/
static void DataCallback(void* userdata, Uint8* stream, int len) {
auto* impl = static_cast<SDLSinkStream*>(userdata);
if (!impl) {
return;
}
const std::size_t num_channels = impl->GetDeviceChannels();
const std::size_t frame_size = num_channels;
const std::size_t num_frames{len / num_channels / sizeof(s16)};
if (impl->type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
num_frames * frame_size};
impl->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(stream), num_frames * frame_size};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
}
}
/// SDL device id of the opened input/output device
SDL_AudioDeviceID device{};
};
SDLSink::SDLSink(std::string_view target_device_name) {
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
@ -140,96 +268,4 @@ bool IsSDLSuitable() {
#endif
}
SDLSinkStream::SDLSinkStream(u32 device_channels_, u32 system_channels_, const std::string& output_device,
const std::string& input_device, StreamType type_, Core::System& system_)
: SinkStream{system_, type_} {
system_channels = system_channels_;
device_channels = device_channels_;
// Add error checking for SDL audio device
if (SDL_GetNumAudioDevices(0) < 1) {
LOG_ERROR(Service_Audio, "No audio devices available");
return;
}
SDL_AudioSpec want{};
want.freq = TargetSampleRate;
want.format = AUDIO_S16LSB;
want.channels = static_cast<u8>(std::min(device_channels, 2u)); // Limit to stereo
want.samples = TargetSampleCount * 2; // Match the sample count from logs
want.callback = nullptr;
SDL_AudioSpec got;
audio_device_id = SDL_OpenAudioDevice(nullptr, 0, &want, &got,
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (audio_device_id == 0) {
LOG_ERROR(Service_Audio, "SDL_OpenAudioDevice failed: {}", SDL_GetError());
return;
}
// Verify we got the requested format
if (got.format != want.format || got.channels != want.channels) {
LOG_WARNING(Service_Audio,
"SDL audio format mismatch - wanted: {} ch, got: {} ch",
want.channels, got.channels);
}
running = true;
SDL_PauseAudioDevice(audio_device_id, 0);
}
SDLSinkStream::~SDLSinkStream() {
LOG_DEBUG(Service_Audio, "Destructing SDL stream {}", name);
Finalize();
}
void SDLSinkStream::Finalize() {
if (audio_device_id == 0) {
return;
}
Stop();
SDL_ClearQueuedAudio(audio_device_id);
SDL_CloseAudioDevice(audio_device_id);
}
void SDLSinkStream::Start(bool resume) {
if (audio_device_id == 0 || !paused) {
return;
}
paused = false;
SDL_PauseAudioDevice(audio_device_id, 0);
}
void SDLSinkStream::Stop() {
if (audio_device_id == 0 || paused) {
return;
}
SignalPause();
SDL_PauseAudioDevice(audio_device_id, 1);
}
void SDLSinkStream::DataCallback(void* userdata, Uint8* stream, int len) {
auto* impl = static_cast<SDLSinkStream*>(userdata);
if (!impl) {
return;
}
const std::size_t num_channels = impl->GetDeviceChannels();
const std::size_t frame_size = num_channels;
const std::size_t num_frames{len / num_channels / sizeof(s16)};
if (impl->type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
num_frames * frame_size};
impl->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(stream), num_frames * frame_size};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
}
}
} // namespace AudioCore::Sink

View file

@ -5,7 +5,6 @@
#include <string>
#include <vector>
#include <SDL.h>
#include "audio_core/sink/sink.h"
@ -96,21 +95,4 @@ std::vector<std::string> ListSDLSinkDevices(bool capture);
*/
bool IsSDLSuitable();
class SDLSinkStream final : public SinkStream {
public:
SDLSinkStream(u32 sample_rate, u32 num_channels, const std::string& output_device,
const std::string& input_device, StreamType type, Core::System& system);
~SDLSinkStream();
void Start(bool resume) override;
void Stop() override;
void Finalize();
private:
void DataCallback(void* userdata, Uint8* stream, int len);
bool running{false};
SDL_AudioDeviceID audio_device_id{};
};
} // namespace AudioCore::Sink