mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 08:52:36 +00:00
cubeb_audio: Replace output yield loop with condvar.
This commit is contained in:
parent
a4ef7771df
commit
42fb06d0f1
@ -93,7 +93,7 @@ static bool IsFormatFloat(const OrbisAudioOutParamFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
|
||||
static u8 GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
|
||||
switch (format) {
|
||||
case OrbisAudioOutParamFormat::S16Mono:
|
||||
case OrbisAudioOutParamFormat::FloatMono:
|
||||
@ -403,12 +403,14 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||
}
|
||||
|
||||
port->type = port_type;
|
||||
port->samples_num = length;
|
||||
port->freq = sample_rate;
|
||||
port->format = format;
|
||||
port->is_float = IsFormatFloat(format);
|
||||
port->channels_num = GetFormatNumChannels(format);
|
||||
port->sample_size = GetFormatSampleSize(format);
|
||||
port->channels_num = GetFormatNumChannels(format);
|
||||
port->samples_num = length;
|
||||
port->frame_size = port->sample_size * port->channels_num;
|
||||
port->buffer_size = port->frame_size * port->samples_num;
|
||||
port->freq = sample_rate;
|
||||
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
|
||||
port->impl = audio->Open(*port);
|
||||
|
||||
@ -434,8 +436,7 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
||||
port.impl->Output(ptr, data_size);
|
||||
port.impl->Output(ptr, port.buffer_size);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -62,14 +62,16 @@ struct OrbisAudioOutPortState {
|
||||
struct PortOut {
|
||||
std::unique_ptr<PortBackend> impl{};
|
||||
|
||||
u32 samples_num;
|
||||
u32 freq;
|
||||
OrbisAudioOutParamFormat format;
|
||||
OrbisAudioOutPort type;
|
||||
int channels_num;
|
||||
OrbisAudioOutParamFormat format;
|
||||
bool is_float;
|
||||
std::array<int, 8> volume;
|
||||
u8 sample_size;
|
||||
u8 channels_num;
|
||||
u32 samples_num;
|
||||
u32 frame_size;
|
||||
u32 buffer_size;
|
||||
u32 freq;
|
||||
std::array<int, 8> volume;
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdarg>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <cubeb/cubeb.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
@ -16,8 +17,7 @@ constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buff
|
||||
class CubebPortBackend : public PortBackend {
|
||||
public:
|
||||
CubebPortBackend(cubeb* ctx, const PortOut& port)
|
||||
: frame_size(port.channels_num * port.sample_size),
|
||||
buffer(static_cast<int>(port.samples_num * frame_size) * 4) {
|
||||
: frame_size(port.frame_size), buffer(static_cast<int>(port.buffer_size) * 4) {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
@ -36,7 +36,7 @@ public:
|
||||
cubeb_stream_params stream_params = {
|
||||
.format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE,
|
||||
.rate = port.freq,
|
||||
.channels = static_cast<u32>(port.channels_num),
|
||||
.channels = port.channels_num,
|
||||
.layout = get_channel_layout(),
|
||||
.prefs = CUBEB_STREAM_PREF_NONE,
|
||||
};
|
||||
@ -75,16 +75,10 @@ public:
|
||||
|
||||
void Output(void* ptr, size_t size) override {
|
||||
auto* data = static_cast<u8*>(ptr);
|
||||
while (size > 0) {
|
||||
const auto queued = buffer.enqueue(data, static_cast<int>(size));
|
||||
size -= queued;
|
||||
data += queued;
|
||||
if (size > 0) {
|
||||
// If the data is too large for the ring buffer, yield execution and give it a
|
||||
// chance to drain.
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock lock{buffer_mutex};
|
||||
buffer_cv.wait(lock, [&] { return buffer.available_write() >= size; });
|
||||
buffer.enqueue(data, static_cast<int>(size));
|
||||
}
|
||||
|
||||
void SetVolume(const std::array<int, 8>& ch_volumes) override {
|
||||
@ -106,7 +100,12 @@ private:
|
||||
auto* stream_data = static_cast<CubebPortBackend*>(user_data);
|
||||
const auto out_data = static_cast<u8*>(out);
|
||||
const auto requested_size = static_cast<int>(num_frames * stream_data->frame_size);
|
||||
|
||||
std::unique_lock lock{stream_data->buffer_mutex};
|
||||
const auto dequeued_size = stream_data->buffer.dequeue(out_data, requested_size);
|
||||
lock.unlock();
|
||||
stream_data->buffer_cv.notify_one();
|
||||
|
||||
if (dequeued_size < requested_size) {
|
||||
// Need to fill remaining space with silence.
|
||||
std::memset(out_data + dequeued_size, 0, requested_size - dequeued_size);
|
||||
@ -133,6 +132,8 @@ private:
|
||||
|
||||
size_t frame_size;
|
||||
ring_buffer_base<u8> buffer;
|
||||
std::mutex buffer_mutex;
|
||||
std::condition_variable buffer_cv;
|
||||
cubeb_stream* stream{};
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user