mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-05 18:23:16 +00:00
audio: Implement cubeb audio out backend. (#1895)
* audio: Implement cubeb audio out backend. * cubeb_audio: Add some additional safety checks. * cubeb_audio: Add debug logging callback. * audioout: Refactor backend ports into class. * pthread: Bump minimum stack size to fix cubeb crash. * cubeb_audio: Replace output yield loop with condvar. * common: Rename ring_buffer_base to RingBuffer.
This commit is contained in:
parent
f95803664b
commit
333f35ef25
18 changed files with 733 additions and 90 deletions
|
@ -7,26 +7,15 @@
|
|||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio/sdl_audio.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
struct PortOut {
|
||||
void* impl;
|
||||
u32 samples_num;
|
||||
u32 freq;
|
||||
OrbisAudioOutParamFormat format;
|
||||
OrbisAudioOutPort type;
|
||||
int channels_num;
|
||||
bool is_float;
|
||||
std::array<int, 8> volume;
|
||||
u8 sample_size;
|
||||
bool is_open;
|
||||
};
|
||||
std::shared_mutex ports_mutex;
|
||||
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
|
||||
|
||||
|
@ -104,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:
|
||||
|
@ -187,13 +176,11 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
|||
|
||||
std::scoped_lock lock(ports_mutex);
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
if (!port.impl) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
audio->Close(port.impl);
|
||||
port.impl = nullptr;
|
||||
port.is_open = false;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -264,7 +251,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
|||
|
||||
std::scoped_lock lock(ports_mutex);
|
||||
const auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
if (!port.impl) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
|
@ -324,7 +311,16 @@ int PS4_SYSV_ABI sceAudioOutInit() {
|
|||
if (audio != nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT;
|
||||
}
|
||||
audio = std::make_unique<SDLAudioOut>();
|
||||
const auto backend = Config::getAudioBackend();
|
||||
if (backend == "cubeb") {
|
||||
audio = std::make_unique<CubebAudioOut>();
|
||||
} else if (backend == "sdl") {
|
||||
audio = std::make_unique<SDLAudioOut>();
|
||||
} else {
|
||||
// Cubeb as a default fallback.
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid audio backend '{}', defaulting to cubeb.", backend);
|
||||
audio = std::make_unique<CubebAudioOut>();
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -399,23 +395,25 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||
}
|
||||
|
||||
std::scoped_lock lock{ports_mutex};
|
||||
const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
|
||||
const auto port =
|
||||
std::ranges::find_if(ports_out, [&](const PortOut& p) { return p.impl == nullptr; });
|
||||
if (port == ports_out.end()) {
|
||||
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
|
||||
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
|
||||
}
|
||||
|
||||
port->is_open = true;
|
||||
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);
|
||||
|
||||
port->impl = audio->Open(port->is_float, port->channels_num, port->freq);
|
||||
return std::distance(ports_out.begin(), port) + 1;
|
||||
}
|
||||
|
||||
|
@ -424,7 +422,7 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -434,12 +432,11 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
|
|||
}
|
||||
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
if (!port.impl) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
||||
audio->Output(port.impl, ptr, data_size);
|
||||
port.impl->Output(ptr, port.buffer_size);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -548,7 +545,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
|||
|
||||
std::scoped_lock lock(ports_mutex);
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
if (!port.impl) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
|
@ -579,7 +576,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
|||
}
|
||||
}
|
||||
|
||||
audio->SetVolume(port.impl, port.volume);
|
||||
port.impl->SetVolume(port.volume);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include <memory>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "core/libraries/system/userservice.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
class PortBackend;
|
||||
|
||||
// Main up to 8 ports, BGM 1 port, voice up to 4 ports,
|
||||
// personal up to 4 ports, padspk up to 5 ports, aux 1 port
|
||||
constexpr int SCE_AUDIO_OUT_NUM_PORTS = 22;
|
||||
|
@ -43,7 +46,7 @@ union OrbisAudioOutParamExtendedInformation {
|
|||
|
||||
struct OrbisAudioOutOutputParam {
|
||||
s32 handle;
|
||||
const void* ptr;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
struct OrbisAudioOutPortState {
|
||||
|
@ -56,6 +59,21 @@ struct OrbisAudioOutPortState {
|
|||
u64 reserved64[2];
|
||||
};
|
||||
|
||||
struct PortOut {
|
||||
std::unique_ptr<PortBackend> impl{};
|
||||
|
||||
OrbisAudioOutPort type;
|
||||
OrbisAudioOutParamFormat format;
|
||||
bool is_float;
|
||||
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 sceAudioDeviceControlGet();
|
||||
int PS4_SYSV_ABI sceAudioDeviceControlSet();
|
||||
|
@ -94,7 +112,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||
OrbisAudioOutPort port_type, s32 index, u32 length,
|
||||
u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type);
|
||||
int PS4_SYSV_ABI sceAudioOutOpenEx();
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr);
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr);
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num);
|
||||
int PS4_SYSV_ABI sceAudioOutPtClose();
|
||||
int PS4_SYSV_ABI sceAudioOutPtGetLastOutputTime();
|
||||
|
|
|
@ -3,17 +3,42 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef struct cubeb cubeb;
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
struct PortOut;
|
||||
|
||||
class PortBackend {
|
||||
public:
|
||||
virtual ~PortBackend() = default;
|
||||
|
||||
virtual void Output(void* ptr, size_t size) = 0;
|
||||
virtual void SetVolume(const std::array<int, 8>& ch_volumes) = 0;
|
||||
};
|
||||
|
||||
class AudioOutBackend {
|
||||
public:
|
||||
AudioOutBackend() = default;
|
||||
virtual ~AudioOutBackend() = default;
|
||||
|
||||
virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0;
|
||||
virtual void Close(void* impl) = 0;
|
||||
virtual void Output(void* impl, const void* ptr, size_t size) = 0;
|
||||
virtual void SetVolume(void* impl, std::array<int, 8> ch_volumes) = 0;
|
||||
virtual std::unique_ptr<PortBackend> Open(PortOut& port) = 0;
|
||||
};
|
||||
|
||||
class CubebAudioOut final : public AudioOutBackend {
|
||||
public:
|
||||
CubebAudioOut();
|
||||
~CubebAudioOut() override;
|
||||
|
||||
std::unique_ptr<PortBackend> Open(PortOut& port) override;
|
||||
|
||||
private:
|
||||
cubeb* ctx = nullptr;
|
||||
};
|
||||
|
||||
class SDLAudioOut final : public AudioOutBackend {
|
||||
public:
|
||||
std::unique_ptr<PortBackend> Open(PortOut& port) override;
|
||||
};
|
||||
|
||||
} // namespace Libraries::AudioOut
|
||||
|
|
158
src/core/libraries/audio/cubeb_audio.cpp
Normal file
158
src/core/libraries/audio/cubeb_audio.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <cubeb/cubeb.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/ringbuffer.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
||||
|
||||
class CubebPortBackend : public PortBackend {
|
||||
public:
|
||||
CubebPortBackend(cubeb* ctx, const PortOut& port)
|
||||
: frame_size(port.frame_size), buffer(static_cast<int>(port.buffer_size) * 4) {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
const auto get_channel_layout = [&port] -> cubeb_channel_layout {
|
||||
switch (port.channels_num) {
|
||||
case 1:
|
||||
return CUBEB_LAYOUT_MONO;
|
||||
case 2:
|
||||
return CUBEB_LAYOUT_STEREO;
|
||||
case 8:
|
||||
return CUBEB_LAYOUT_3F4_LFE;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
};
|
||||
cubeb_stream_params stream_params = {
|
||||
.format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE,
|
||||
.rate = port.freq,
|
||||
.channels = port.channels_num,
|
||||
.layout = get_channel_layout(),
|
||||
.prefs = CUBEB_STREAM_PREF_NONE,
|
||||
};
|
||||
u32 latency_frames = 512;
|
||||
if (const auto ret = cubeb_get_min_latency(ctx, &stream_params, &latency_frames);
|
||||
ret != CUBEB_OK) {
|
||||
LOG_WARNING(Lib_AudioOut,
|
||||
"Could not get minimum cubeb audio latency, falling back to default: {}",
|
||||
ret);
|
||||
}
|
||||
char stream_name[64];
|
||||
snprintf(stream_name, sizeof(stream_name), "shadPS4 stream %p", this);
|
||||
if (const auto ret = cubeb_stream_init(ctx, &stream, stream_name, nullptr, nullptr, nullptr,
|
||||
&stream_params, latency_frames, &DataCallback,
|
||||
&StateCallback, this);
|
||||
ret != CUBEB_OK) {
|
||||
LOG_ERROR(Lib_AudioOut, "Failed to create cubeb stream: {}", ret);
|
||||
return;
|
||||
}
|
||||
if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) {
|
||||
LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~CubebPortBackend() override {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
if (const auto ret = cubeb_stream_stop(stream); ret != CUBEB_OK) {
|
||||
LOG_WARNING(Lib_AudioOut, "Failed to stop cubeb stream: {}", ret);
|
||||
}
|
||||
cubeb_stream_destroy(stream);
|
||||
stream = nullptr;
|
||||
}
|
||||
|
||||
void Output(void* ptr, size_t size) override {
|
||||
auto* data = static_cast<u8*>(ptr);
|
||||
|
||||
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 {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
// Cubeb does not have per-channel volumes, for now just take the maximum of the channels.
|
||||
const auto vol = *std::ranges::max_element(ch_volumes);
|
||||
if (const auto ret =
|
||||
cubeb_stream_set_volume(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB);
|
||||
ret != CUBEB_OK) {
|
||||
LOG_WARNING(Lib_AudioOut, "Failed to change cubeb stream volume: {}", ret);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static long DataCallback(cubeb_stream* stream, void* user_data, const void* in, void* out,
|
||||
long num_frames) {
|
||||
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);
|
||||
}
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
LOG_INFO(Lib_AudioOut, "Cubeb stream started");
|
||||
break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
LOG_INFO(Lib_AudioOut, "Cubeb stream stopped");
|
||||
break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
LOG_INFO(Lib_AudioOut, "Cubeb stream drained");
|
||||
break;
|
||||
case CUBEB_STATE_ERROR:
|
||||
LOG_ERROR(Lib_AudioOut, "Cubeb stream encountered an error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t frame_size;
|
||||
RingBuffer<u8> buffer;
|
||||
std::mutex buffer_mutex;
|
||||
std::condition_variable buffer_cv;
|
||||
cubeb_stream* stream{};
|
||||
};
|
||||
|
||||
CubebAudioOut::CubebAudioOut() {
|
||||
if (const auto ret = cubeb_init(&ctx, "shadPS4", nullptr); ret != CUBEB_OK) {
|
||||
LOG_CRITICAL(Lib_AudioOut, "Failed to create cubeb context: {}", ret);
|
||||
}
|
||||
}
|
||||
|
||||
CubebAudioOut::~CubebAudioOut() {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
cubeb_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PortBackend> CubebAudioOut::Open(PortOut& port) {
|
||||
return std::make_unique<CubebPortBackend>(ctx, port);
|
||||
}
|
||||
|
||||
} // namespace Libraries::AudioOut
|
|
@ -1,44 +1,60 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/libraries/audio/sdl_audio.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
||||
|
||||
void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) {
|
||||
SDL_AudioSpec fmt;
|
||||
SDL_zero(fmt);
|
||||
fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16;
|
||||
fmt.channels = num_channels;
|
||||
fmt.freq = sample_rate;
|
||||
|
||||
auto* stream =
|
||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
|
||||
SDL_ResumeAudioStreamDevice(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
void SDLAudioOut::Close(void* impl) {
|
||||
SDL_DestroyAudioStream(static_cast<SDL_AudioStream*>(impl));
|
||||
}
|
||||
|
||||
void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) {
|
||||
auto* stream = static_cast<SDL_AudioStream*>(impl);
|
||||
SDL_PutAudioStreamData(stream, ptr, size);
|
||||
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||
SDL_Delay(0);
|
||||
class SDLPortBackend : public PortBackend {
|
||||
public:
|
||||
explicit SDLPortBackend(const PortOut& port) {
|
||||
const SDL_AudioSpec fmt = {
|
||||
.format = port.is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16,
|
||||
.channels = port.channels_num,
|
||||
.freq = static_cast<int>(port.freq),
|
||||
};
|
||||
stream =
|
||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
|
||||
if (stream == nullptr) {
|
||||
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
|
||||
}
|
||||
SDL_ResumeAudioStreamDevice(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLAudioOut::SetVolume(void* impl, std::array<int, 8> ch_volumes) {
|
||||
// Not yet implemented
|
||||
~SDLPortBackend() override {
|
||||
if (stream) {
|
||||
SDL_DestroyAudioStream(stream);
|
||||
stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Output(void* ptr, size_t size) override {
|
||||
SDL_PutAudioStreamData(stream, ptr, static_cast<int>(size));
|
||||
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||
// Yield to allow the stream to drain.
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
void SetVolume(const std::array<int, 8>& ch_volumes) override {
|
||||
// TODO: Not yet implemented
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_AudioStream* stream;
|
||||
};
|
||||
|
||||
std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) {
|
||||
return std::make_unique<SDLPortBackend>(port);
|
||||
}
|
||||
|
||||
} // namespace Libraries::AudioOut
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
class SDLAudioOut final : public AudioOutBackend {
|
||||
public:
|
||||
void* Open(bool is_float, int num_channels, u32 sample_rate) override;
|
||||
void Close(void* impl) override;
|
||||
void Output(void* impl, const void* ptr, size_t size) override;
|
||||
void SetVolume(void* impl, std::array<int, 8> ch_volumes) override;
|
||||
};
|
||||
|
||||
} // namespace Libraries::AudioOut
|
|
@ -244,8 +244,8 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
new_thread->tid = ++TidCounter;
|
||||
|
||||
if (new_thread->attr.stackaddr_attr == 0) {
|
||||
/* Enforce minimum stack size of 64 KB */
|
||||
static constexpr size_t MinimumStack = 64_KB;
|
||||
/* Enforce minimum stack size of 128 KB */
|
||||
static constexpr size_t MinimumStack = 128_KB;
|
||||
auto& stacksize = new_thread->attr.stacksize_attr;
|
||||
stacksize = std::max(stacksize, MinimumStack);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue