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) {
|
switch (format) {
|
||||||
case OrbisAudioOutParamFormat::S16Mono:
|
case OrbisAudioOutParamFormat::S16Mono:
|
||||||
case OrbisAudioOutParamFormat::FloatMono:
|
case OrbisAudioOutParamFormat::FloatMono:
|
||||||
@ -403,12 +403,14 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
port->type = port_type;
|
port->type = port_type;
|
||||||
port->samples_num = length;
|
|
||||||
port->freq = sample_rate;
|
|
||||||
port->format = format;
|
port->format = format;
|
||||||
port->is_float = IsFormatFloat(format);
|
port->is_float = IsFormatFloat(format);
|
||||||
port->channels_num = GetFormatNumChannels(format);
|
|
||||||
port->sample_size = GetFormatSampleSize(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->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
|
||||||
port->impl = audio->Open(*port);
|
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;
|
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, port.buffer_size);
|
||||||
port.impl->Output(ptr, data_size);
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +62,16 @@ struct OrbisAudioOutPortState {
|
|||||||
struct PortOut {
|
struct PortOut {
|
||||||
std::unique_ptr<PortBackend> impl{};
|
std::unique_ptr<PortBackend> impl{};
|
||||||
|
|
||||||
u32 samples_num;
|
|
||||||
u32 freq;
|
|
||||||
OrbisAudioOutParamFormat format;
|
|
||||||
OrbisAudioOutPort type;
|
OrbisAudioOutPort type;
|
||||||
int channels_num;
|
OrbisAudioOutParamFormat format;
|
||||||
bool is_float;
|
bool is_float;
|
||||||
std::array<int, 8> volume;
|
|
||||||
u8 sample_size;
|
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();
|
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
#include <cubeb/cubeb.h>
|
#include <cubeb/cubeb.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
@ -16,8 +17,7 @@ constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buff
|
|||||||
class CubebPortBackend : public PortBackend {
|
class CubebPortBackend : public PortBackend {
|
||||||
public:
|
public:
|
||||||
CubebPortBackend(cubeb* ctx, const PortOut& port)
|
CubebPortBackend(cubeb* ctx, const PortOut& port)
|
||||||
: frame_size(port.channels_num * port.sample_size),
|
: frame_size(port.frame_size), buffer(static_cast<int>(port.buffer_size) * 4) {
|
||||||
buffer(static_cast<int>(port.samples_num * frame_size) * 4) {
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ public:
|
|||||||
cubeb_stream_params stream_params = {
|
cubeb_stream_params stream_params = {
|
||||||
.format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE,
|
.format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE,
|
||||||
.rate = port.freq,
|
.rate = port.freq,
|
||||||
.channels = static_cast<u32>(port.channels_num),
|
.channels = port.channels_num,
|
||||||
.layout = get_channel_layout(),
|
.layout = get_channel_layout(),
|
||||||
.prefs = CUBEB_STREAM_PREF_NONE,
|
.prefs = CUBEB_STREAM_PREF_NONE,
|
||||||
};
|
};
|
||||||
@ -75,16 +75,10 @@ public:
|
|||||||
|
|
||||||
void Output(void* ptr, size_t size) override {
|
void Output(void* ptr, size_t size) override {
|
||||||
auto* data = static_cast<u8*>(ptr);
|
auto* data = static_cast<u8*>(ptr);
|
||||||
while (size > 0) {
|
|
||||||
const auto queued = buffer.enqueue(data, static_cast<int>(size));
|
std::unique_lock lock{buffer_mutex};
|
||||||
size -= queued;
|
buffer_cv.wait(lock, [&] { return buffer.available_write() >= size; });
|
||||||
data += queued;
|
buffer.enqueue(data, static_cast<int>(size));
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVolume(const std::array<int, 8>& ch_volumes) override {
|
void SetVolume(const std::array<int, 8>& ch_volumes) override {
|
||||||
@ -106,7 +100,12 @@ private:
|
|||||||
auto* stream_data = static_cast<CubebPortBackend*>(user_data);
|
auto* stream_data = static_cast<CubebPortBackend*>(user_data);
|
||||||
const auto out_data = static_cast<u8*>(out);
|
const auto out_data = static_cast<u8*>(out);
|
||||||
const auto requested_size = static_cast<int>(num_frames * stream_data->frame_size);
|
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);
|
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) {
|
if (dequeued_size < requested_size) {
|
||||||
// Need to fill remaining space with silence.
|
// Need to fill remaining space with silence.
|
||||||
std::memset(out_data + dequeued_size, 0, requested_size - dequeued_size);
|
std::memset(out_data + dequeued_size, 0, requested_size - dequeued_size);
|
||||||
@ -133,6 +132,8 @@ private:
|
|||||||
|
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
ring_buffer_base<u8> buffer;
|
ring_buffer_base<u8> buffer;
|
||||||
|
std::mutex buffer_mutex;
|
||||||
|
std::condition_variable buffer_cv;
|
||||||
cubeb_stream* stream{};
|
cubeb_stream* stream{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user