mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-02-23 17:18:47 +01:00
Revert "audio: refactor SDL2 sink implementation"
This reverts commit 3aa9c0d151
.
This commit is contained in:
parent
0576d40bf0
commit
4d50d2ba16
2 changed files with 132 additions and 114 deletions
|
@ -1,5 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
@ -17,9 +16,138 @@ namespace AudioCore::Sink {
|
||||||
/**
|
/**
|
||||||
* SDL sink stream, responsible for sinking samples to hardware.
|
* 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) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
@ -140,96 +268,4 @@ bool IsSDLSuitable() {
|
||||||
#endif
|
#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
|
} // namespace AudioCore::Sink
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL.h>
|
|
||||||
|
|
||||||
#include "audio_core/sink/sink.h"
|
#include "audio_core/sink/sink.h"
|
||||||
|
|
||||||
|
@ -96,21 +95,4 @@ std::vector<std::string> ListSDLSinkDevices(bool capture);
|
||||||
*/
|
*/
|
||||||
bool IsSDLSuitable();
|
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
|
} // namespace AudioCore::Sink
|
||||||
|
|
Loading…
Reference in a new issue