mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 00:13:08 +00:00
Refactor audio handling with range checks, buffer threshold, and lock fixes
- Added range checks for handle to avoid invalid index access in AudioOutOutput, AudioOutSetVolume, and AudioOutGetStatus. - Added a constant AUDIO_STREAM_BUFFER_THRESHOLD for the buffer threshold (was previously a magic number). - Set the freq parameter correctly in the SDL_AudioSpec structure in AudioOutOpen. - Fixed locking issues in AudioOutOutput to avoid unlocking before it's locked.
This commit is contained in:
parent
394b7fa671
commit
d63b7fcc1d
@ -14,150 +14,168 @@
|
|||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
|
||||||
|
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
||||||
|
|
||||||
int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
|
int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
|
||||||
Libraries::AudioOut::OrbisAudioOutParamFormat format) {
|
Libraries::AudioOut::OrbisAudioOutParamFormat format) {
|
||||||
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
for (int id = 0; id < portsOut.size(); id++) {
|
for (int id = 0; id < portsOut.size(); id++) {
|
||||||
auto& port = portsOut[id];
|
auto& port = portsOut[id];
|
||||||
if (!port.isOpen) {
|
if (!port.isOpen) {
|
||||||
port.isOpen = true;
|
port.isOpen = true;
|
||||||
port.type = type;
|
port.type = type;
|
||||||
port.samples_num = samples_num;
|
port.samples_num = samples_num;
|
||||||
port.freq = freq;
|
port.freq = freq;
|
||||||
port.format = format;
|
port.format = format;
|
||||||
SDL_AudioFormat sampleFormat;
|
SDL_AudioFormat sampleFormat;
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
|
||||||
sampleFormat = SDL_AUDIO_S16;
|
sampleFormat = SDL_AUDIO_S16;
|
||||||
port.channels_num = 1;
|
port.channels_num = 1;
|
||||||
port.sample_size = 2;
|
port.sample_size = 2;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
|
||||||
sampleFormat = SDL_AUDIO_F32;
|
sampleFormat = SDL_AUDIO_F32;
|
||||||
port.channels_num = 1;
|
port.channels_num = 1;
|
||||||
port.sample_size = 4;
|
port.sample_size = 4;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
|
||||||
sampleFormat = SDL_AUDIO_S16;
|
sampleFormat = SDL_AUDIO_S16;
|
||||||
port.channels_num = 2;
|
port.channels_num = 2;
|
||||||
port.sample_size = 2;
|
port.sample_size = 2;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
|
||||||
sampleFormat = SDL_AUDIO_F32;
|
sampleFormat = SDL_AUDIO_F32;
|
||||||
port.channels_num = 2;
|
port.channels_num = 2;
|
||||||
port.sample_size = 4;
|
port.sample_size = 4;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
|
||||||
sampleFormat = SDL_AUDIO_S16;
|
sampleFormat = SDL_AUDIO_S16;
|
||||||
port.channels_num = 8;
|
port.channels_num = 8;
|
||||||
port.sample_size = 2;
|
port.sample_size = 2;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
|
||||||
sampleFormat = SDL_AUDIO_F32;
|
sampleFormat = SDL_AUDIO_F32;
|
||||||
port.channels_num = 8;
|
port.channels_num = 8;
|
||||||
port.sample_size = 4;
|
port.sample_size = 4;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
|
||||||
sampleFormat = SDL_AUDIO_S16;
|
sampleFormat = SDL_AUDIO_S16;
|
||||||
port.channels_num = 8;
|
port.channels_num = 8;
|
||||||
port.sample_size = 2;
|
port.sample_size = 2;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
|
case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
|
||||||
sampleFormat = SDL_AUDIO_F32;
|
sampleFormat = SDL_AUDIO_F32;
|
||||||
port.channels_num = 8;
|
port.channels_num = 8;
|
||||||
port.sample_size = 4;
|
port.sample_size = 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Unknown format");
|
UNREACHABLE_MSG("Unknown format");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < port.channels_num; i++) {
|
for (int i = 0; i < port.channels_num; i++) {
|
||||||
port.volume[i] = Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB;
|
port.volume[i] = Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AudioSpec fmt;
|
SDL_AudioSpec fmt;
|
||||||
SDL_zero(fmt);
|
SDL_zero(fmt);
|
||||||
fmt.format = sampleFormat;
|
fmt.format = sampleFormat;
|
||||||
fmt.channels = port.channels_num;
|
fmt.channels = port.channels_num;
|
||||||
fmt.freq = 48000;
|
fmt.freq = freq; // Set frequency from the argument
|
||||||
port.stream =
|
port.stream =
|
||||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
|
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
|
||||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port.stream));
|
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port.stream));
|
||||||
return id + 1;
|
return id + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1; // all ports are used
|
return -1; // all ports are used
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
|
s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
|
||||||
std::shared_lock lock{m_mutex};
|
if (handle < 1 || handle > portsOut.size()) { // Add handle range check
|
||||||
auto& port = portsOut[handle - 1];
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
if (!port.isOpen) {
|
}
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
|
||||||
}
|
|
||||||
if (ptr == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lock.unlock();
|
|
||||||
// TODO mixing channels
|
|
||||||
SDL_bool result = SDL_PutAudioStreamData(
|
|
||||||
port.stream, ptr, port.samples_num * port.sample_size * port.channels_num);
|
|
||||||
// TODO find a correct value 8192 is estimated
|
|
||||||
while (SDL_GetAudioStreamAvailable(port.stream) > 65536) {
|
|
||||||
SDL_Delay(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result ? ORBIS_OK : -1;
|
std::shared_lock lock{m_mutex};
|
||||||
|
auto& port = portsOut[handle - 1];
|
||||||
|
if (!port.isOpen) {
|
||||||
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
|
}
|
||||||
|
if (ptr == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO mixing channels
|
||||||
|
SDL_bool result = SDL_PutAudioStreamData(
|
||||||
|
port.stream, ptr, port.samples_num * port.sample_size * port.channels_num);
|
||||||
|
|
||||||
|
lock.unlock(); // Unlock after the critical section
|
||||||
|
|
||||||
|
// TODO find a correct value 8192 is estimated
|
||||||
|
while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||||
|
SDL_Delay(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result ? ORBIS_OK : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
|
bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
|
||||||
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
if (handle < 1 || handle > portsOut.size()) { // Add handle range check
|
||||||
std::shared_lock lock{m_mutex};
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
auto& port = portsOut[handle - 1];
|
}
|
||||||
if (!port.isOpen) {
|
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) {
|
|
||||||
auto bit = bitflag & 0x1u;
|
|
||||||
|
|
||||||
if (bit == 1) {
|
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
||||||
int src_index = i;
|
std::shared_lock lock{m_mutex};
|
||||||
if (port.format ==
|
auto& port = portsOut[handle - 1];
|
||||||
OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD ||
|
if (!port.isOpen) {
|
||||||
port.format == OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD) {
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
switch (i) {
|
}
|
||||||
case 4:
|
|
||||||
src_index = 6;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
src_index = 7;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
src_index = 4;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
src_index = 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
port.volume[i] = volume[src_index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) {
|
||||||
|
auto bit = bitflag & 0x1u;
|
||||||
|
|
||||||
|
if (bit == 1) {
|
||||||
|
int src_index = i;
|
||||||
|
if (port.format ==
|
||||||
|
OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD ||
|
||||||
|
port.format == OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD) {
|
||||||
|
switch (i) {
|
||||||
|
case 4:
|
||||||
|
src_index = 6;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
src_index = 7;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
src_index = 4;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
src_index = 5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.volume[i] = volume[src_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
|
bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
|
||||||
std::shared_lock lock{m_mutex};
|
if (handle < 1 || handle > portsOut.size()) { // Add handle range check
|
||||||
auto& port = portsOut[handle - 1];
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
*type = port.type;
|
}
|
||||||
*channels_num = port.channels_num;
|
|
||||||
|
|
||||||
return true;
|
std::shared_lock lock{m_mutex};
|
||||||
|
auto& port = portsOut[handle - 1];
|
||||||
|
*type = port.type;
|
||||||
|
*channels_num = port.channels_num;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Audio
|
} // namespace Audio
|
||||||
|
Loading…
Reference in New Issue
Block a user