Lib.Audio3d: implement sceAudio3dPortCreate and update sceAudio3dPortOpen (#4457)

* implement sceAudio3dPortCreate and closer implementation to sceAudio3dPortOpen

* clang format and forgot to remove some lines

* refactor port creation, small cleanups and openal

* rename parameter arguments

* idk might be correct

* floor size_this to closest multiple of 8
This commit is contained in:
Xupie
2026-05-24 20:07:04 +03:00
committed by GitHub
parent e5c406d809
commit c0d35332af
4 changed files with 298 additions and 38 deletions
+139 -13
View File
@@ -617,9 +617,23 @@ s32 PS4_SYSV_ABI sceAudio3dPortClose(const OrbisAudio3dPortId port_id) {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortCreate() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceAudio3dPortCreate(u32 granularity, u32 rate, s64 reserved,
OrbisAudio3dPortId* port_id) {
LOG_INFO(Lib_Audio3d, "called, granularity = {}, rate = {}, reserved = {}, port_id = {}",
granularity, rate, reserved, static_cast<void*>(port_id));
if (!port_id || reserved) {
LOG_INFO(Lib_Audio3d, "!port_id || reserved");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
OrbisAudio3dOpenParameters local_params{};
local_params.size_this = 0x10;
local_params.granularity = granularity;
local_params.rate = static_cast<OrbisAudio3dRate>(rate);
return sceAudio3dPortOpen(static_cast<Libraries::UserService::OrbisUserServiceUserId>(0xFF),
&local_params, port_id);
}
s32 PS4_SYSV_ABI sceAudio3dPortDestroy() {
@@ -782,31 +796,143 @@ s32 PS4_SYSV_ABI sceAudio3dPortGetStatus() {
s32 PS4_SYSV_ABI sceAudio3dPortOpen(const Libraries::UserService::OrbisUserServiceUserId user_id,
const OrbisAudio3dOpenParameters* parameters,
OrbisAudio3dPortId* port_id) {
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, id = {}", user_id,
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, port_id = {}", user_id,
static_cast<const void*>(parameters), static_cast<void*>(port_id));
if (user_id != 0xFF || !parameters || !port_id) {
LOG_ERROR(Lib_Audio3d, "user_id != 0xFF || !parameters || !port_id");
if (port_id)
*port_id = ORBIS_AUDIO3D_PORT_INVALID;
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
*port_id = ORBIS_AUDIO3D_PORT_INVALID;
if (!state) {
LOG_ERROR(Lib_Audio3d, "!initialized");
return ORBIS_AUDIO3D_ERROR_NOT_READY;
}
if (!parameters || !port_id) {
LOG_ERROR(Lib_Audio3d, "!parameters || !id");
OrbisAudio3dOpenParameters effective{
.size_this = 0x28,
.granularity = parameters->granularity,
.rate = parameters->rate,
.max_objects = 512,
.queue_depth = 2,
.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_NO_ADVANCE,
._pad = 0,
.num_beds = 2,
};
switch (parameters->size_this & ~0x7ull) {
case 0x10:
break;
case 0x18:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH;
break;
case 0x20:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = parameters->buffer_mode;
break;
case 0x28:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = parameters->buffer_mode;
effective.num_beds = parameters->num_beds;
break;
default:
LOG_ERROR(Lib_Audio3d, "invalid size_this");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
const int id = static_cast<int>(state->ports.size()) + 1;
if (effective.rate != OrbisAudio3dRate::ORBIS_AUDIO3D_RATE_48000) {
LOG_ERROR(Lib_Audio3d, "unsupported rate");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (id > 3) {
LOG_ERROR(Lib_Audio3d, "id > 3");
if (effective.granularity < 0x100) {
LOG_ERROR(Lib_Audio3d, "granularity < 0x100");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if ((effective.granularity & 0xFF) != 0) {
LOG_ERROR(Lib_Audio3d, "granularity not aligned to 0x100");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.max_objects == 0) {
LOG_ERROR(Lib_Audio3d, "max_objects == 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.queue_depth == 0) {
LOG_ERROR(Lib_Audio3d, "queue_depth == 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x100 && effective.queue_depth > 0x40) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x100 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x200 && effective.queue_depth > 0x1F) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x200 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x300 && effective.queue_depth > 0x14) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x300 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.queue_depth > 0xF && effective.granularity > 0x3FF) {
LOG_ERROR(Lib_Audio3d, "queue_depth invalid for large granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (static_cast<u32>(effective.buffer_mode) > 2) {
LOG_ERROR(Lib_Audio3d, "invalid buffer_mode");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if ((effective.num_beds & 0xfffffffe) != 2) {
LOG_ERROR(Lib_Audio3d, "invalid num_beds");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.max_objects > 0x200) {
LOG_WARNING(Lib_Audio3d, "max_objects {} exceeds limit, clamping to 512",
effective.max_objects);
effective.max_objects = 0x200;
}
std::scoped_lock lock{state->ports_mutex};
OrbisAudio3dPortId id = ORBIS_AUDIO3D_PORT_INVALID;
for (OrbisAudio3dPortId i = 0; i < MaxPorts; i++) {
if (!state->ports.contains(i)) {
id = i;
break;
}
}
if (id == ORBIS_AUDIO3D_PORT_INVALID) {
LOG_ERROR(Lib_Audio3d, "no free ports");
return ORBIS_AUDIO3D_ERROR_OUT_OF_RESOURCES;
}
auto& port = state->ports.try_emplace(id).first->second;
port.parameters = effective;
*port_id = id;
auto& port = state->ports[id];
std::memcpy(
&port.parameters, parameters,
std::min(parameters->size_this, static_cast<u64>(sizeof(OrbisAudio3dOpenParameters))));
return ORBIS_OK;
}
+10 -6
View File
@@ -18,7 +18,13 @@ class SymbolsResolver;
namespace Libraries::Audio3d {
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
using OrbisAudio3dAmbisonics = u32;
constexpr int ORBIS_AUDIO3D_OBJECT_INVALID = 0xFFFFFFFF;
constexpr OrbisAudio3dPortId ORBIS_AUDIO3D_PORT_INVALID = 0xFFFFFFFFu;
constexpr OrbisAudio3dPortId MaxPorts = 4;
enum class OrbisAudio3dRate : u32 {
ORBIS_AUDIO3D_RATE_48000 = 0,
@@ -37,7 +43,7 @@ struct OrbisAudio3dOpenParameters {
u32 max_objects;
u32 queue_depth;
OrbisAudio3dBufferMode buffer_mode;
int : 32;
u32 _pad;
u32 num_beds;
};
@@ -77,10 +83,6 @@ enum class OrbisAudio3dAttributeId : u32 {
ORBIS_AUDIO3D_ATTRIBUTE_OUTPUT_ROUTE = 11,
};
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
using OrbisAudio3dAmbisonics = u32;
struct OrbisAudio3dAttribute {
OrbisAudio3dAttributeId attribute_id;
int : 32;
@@ -119,6 +121,7 @@ struct Port {
};
struct Audio3dState {
std::mutex ports_mutex;
std::unordered_map<OrbisAudio3dPortId, Port> ports;
};
@@ -154,7 +157,8 @@ s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve(OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId object_id);
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortClose(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortCreate();
s32 PS4_SYSV_ABI sceAudio3dPortCreate(u32 granularity, u32 rate, s64 reserved,
OrbisAudio3dPortId* port_id);
s32 PS4_SYSV_ABI sceAudio3dPortDestroy();
s32 PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortFreeState();
+139 -13
View File
@@ -617,9 +617,23 @@ s32 PS4_SYSV_ABI sceAudio3dPortClose(const OrbisAudio3dPortId port_id) {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortCreate() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceAudio3dPortCreate(u32 granularity, u32 rate, s64 reserved,
OrbisAudio3dPortId* port_id) {
LOG_INFO(Lib_Audio3d, "called, granularity = {}, rate = {}, reserved = {}, port_id = {}",
granularity, rate, reserved, static_cast<void*>(port_id));
if (!port_id || reserved) {
LOG_INFO(Lib_Audio3d, "!port_id || reserved");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
OrbisAudio3dOpenParameters local_params{};
local_params.size_this = 0x10;
local_params.granularity = granularity;
local_params.rate = static_cast<OrbisAudio3dRate>(rate);
return sceAudio3dPortOpen(static_cast<Libraries::UserService::OrbisUserServiceUserId>(0xFF),
&local_params, port_id);
}
s32 PS4_SYSV_ABI sceAudio3dPortDestroy() {
@@ -782,31 +796,143 @@ s32 PS4_SYSV_ABI sceAudio3dPortGetStatus() {
s32 PS4_SYSV_ABI sceAudio3dPortOpen(const Libraries::UserService::OrbisUserServiceUserId user_id,
const OrbisAudio3dOpenParameters* parameters,
OrbisAudio3dPortId* port_id) {
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, id = {}", user_id,
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, port_id = {}", user_id,
static_cast<const void*>(parameters), static_cast<void*>(port_id));
if (user_id != 0xFF || !parameters || !port_id) {
LOG_ERROR(Lib_Audio3d, "user_id != 0xFF || !parameters || !port_id");
if (port_id)
*port_id = ORBIS_AUDIO3D_PORT_INVALID;
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
*port_id = ORBIS_AUDIO3D_PORT_INVALID;
if (!state) {
LOG_ERROR(Lib_Audio3d, "!initialized");
return ORBIS_AUDIO3D_ERROR_NOT_READY;
}
if (!parameters || !port_id) {
LOG_ERROR(Lib_Audio3d, "!parameters || !id");
OrbisAudio3dOpenParameters effective{
.size_this = 0x28,
.granularity = parameters->granularity,
.rate = parameters->rate,
.max_objects = 512,
.queue_depth = 2,
.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_NO_ADVANCE,
._pad = 0,
.num_beds = 2,
};
switch (parameters->size_this & ~0x7ull) {
case 0x10:
break;
case 0x18:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH;
break;
case 0x20:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = parameters->buffer_mode;
break;
case 0x28:
effective.max_objects = parameters->max_objects;
effective.queue_depth = parameters->queue_depth;
effective.buffer_mode = parameters->buffer_mode;
effective.num_beds = parameters->num_beds;
break;
default:
LOG_ERROR(Lib_Audio3d, "invalid size_this");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
const int id = static_cast<int>(state->ports.size()) + 1;
if (effective.rate != OrbisAudio3dRate::ORBIS_AUDIO3D_RATE_48000) {
LOG_ERROR(Lib_Audio3d, "unsupported rate");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (id > 3) {
LOG_ERROR(Lib_Audio3d, "id > 3");
if (effective.granularity < 0x100) {
LOG_ERROR(Lib_Audio3d, "granularity < 0x100");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if ((effective.granularity & 0xFF) != 0) {
LOG_ERROR(Lib_Audio3d, "granularity not aligned to 0x100");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.max_objects == 0) {
LOG_ERROR(Lib_Audio3d, "max_objects == 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.queue_depth == 0) {
LOG_ERROR(Lib_Audio3d, "queue_depth == 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x100 && effective.queue_depth > 0x40) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x100 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x200 && effective.queue_depth > 0x1F) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x200 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.granularity == 0x300 && effective.queue_depth > 0x14) {
LOG_ERROR(Lib_Audio3d, "queue_depth too large for 0x300 granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.queue_depth > 0xF && effective.granularity > 0x3FF) {
LOG_ERROR(Lib_Audio3d, "queue_depth invalid for large granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (static_cast<u32>(effective.buffer_mode) > 2) {
LOG_ERROR(Lib_Audio3d, "invalid buffer_mode");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if ((effective.num_beds & 0xfffffffe) != 2) {
LOG_ERROR(Lib_Audio3d, "invalid num_beds");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (effective.max_objects > 0x200) {
LOG_WARNING(Lib_Audio3d, "max_objects {} exceeds limit, clamping to 512",
effective.max_objects);
effective.max_objects = 0x200;
}
std::scoped_lock lock{state->ports_mutex};
OrbisAudio3dPortId id = ORBIS_AUDIO3D_PORT_INVALID;
for (OrbisAudio3dPortId i = 0; i < MaxPorts; i++) {
if (!state->ports.contains(i)) {
id = i;
break;
}
}
if (id == ORBIS_AUDIO3D_PORT_INVALID) {
LOG_ERROR(Lib_Audio3d, "no free ports");
return ORBIS_AUDIO3D_ERROR_OUT_OF_RESOURCES;
}
auto& port = state->ports.try_emplace(id).first->second;
port.parameters = effective;
*port_id = id;
auto& port = state->ports[id];
std::memcpy(
&port.parameters, parameters,
std::min(parameters->size_this, static_cast<u64>(sizeof(OrbisAudio3dOpenParameters))));
return ORBIS_OK;
}
+10 -6
View File
@@ -17,7 +17,13 @@ class SymbolsResolver;
namespace Libraries::Audio3dOpenAL {
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
using OrbisAudio3dAmbisonics = u32;
constexpr int ORBIS_AUDIO3D_OBJECT_INVALID = 0xFFFFFFFF;
constexpr OrbisAudio3dPortId ORBIS_AUDIO3D_PORT_INVALID = 0xFFFFFFFFu;
constexpr OrbisAudio3dPortId MaxPorts = 4;
enum class OrbisAudio3dRate : u32 {
ORBIS_AUDIO3D_RATE_48000 = 0,
@@ -36,7 +42,7 @@ struct OrbisAudio3dOpenParameters {
u32 max_objects;
u32 queue_depth;
OrbisAudio3dBufferMode buffer_mode;
int : 32;
u32 _pad;
u32 num_beds;
};
@@ -76,10 +82,6 @@ enum class OrbisAudio3dAttributeId : u32 {
ORBIS_AUDIO3D_ATTRIBUTE_OUTPUT_ROUTE = 11,
};
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
using OrbisAudio3dAmbisonics = u32;
struct OrbisAudio3dAttribute {
OrbisAudio3dAttributeId attribute_id;
int : 32;
@@ -117,6 +119,7 @@ struct Port {
};
struct Audio3dState {
std::mutex ports_mutex;
std::unordered_map<OrbisAudio3dPortId, Port> ports;
};
@@ -152,7 +155,8 @@ s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve(OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId object_id);
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortClose(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortCreate();
s32 PS4_SYSV_ABI sceAudio3dPortCreate(u32 granularity, u32 rate, s64 reserved,
OrbisAudio3dPortId* port_id);
s32 PS4_SYSV_ABI sceAudio3dPortDestroy();
s32 PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortFreeState();