mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-26 04:46:53 +01:00
audio: implement AudioOut2 user capability queries
This commit is contained in:
@@ -70,6 +70,9 @@ int KYTY_SYSV_ABI AudioOut2PortGetState(AudioOut2PortHandle port, AudioOut2PortS
|
|||||||
int KYTY_SYSV_ABI AudioOut2GetSystemState(AudioOut2SystemState* state);
|
int KYTY_SYSV_ABI AudioOut2GetSystemState(AudioOut2SystemState* state);
|
||||||
int KYTY_SYSV_ABI AudioOut2UserCreate(uint32_t user_id, AudioOut2UserHandle* handle);
|
int KYTY_SYSV_ABI AudioOut2UserCreate(uint32_t user_id, AudioOut2UserHandle* handle);
|
||||||
int KYTY_SYSV_ABI AudioOut2UserDestroy(AudioOut2UserHandle handle);
|
int KYTY_SYSV_ABI AudioOut2UserDestroy(AudioOut2UserHandle handle);
|
||||||
|
int KYTY_SYSV_ABI AudioOut2UserGetSupportedAttributes(AudioOut2UserHandle handle,
|
||||||
|
uint32_t* context_attributes,
|
||||||
|
uint32_t* port_attributes);
|
||||||
size_t KYTY_SYSV_ABI AudioOut2GetSpeakerArrayMemorySize(uint32_t num_speakers, uint8_t is_3d,
|
size_t KYTY_SYSV_ABI AudioOut2GetSpeakerArrayMemorySize(uint32_t num_speakers, uint8_t is_3d,
|
||||||
uint8_t is_ambisonics);
|
uint8_t is_ambisonics);
|
||||||
int KYTY_SYSV_ABI AudioOut2SpeakerArrayCreate(AudioOut2SpeakerArrayHandle* handle,
|
int KYTY_SYSV_ABI AudioOut2SpeakerArrayCreate(AudioOut2SpeakerArrayHandle* handle,
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ LIB_DEFINE(InitAudio_1_AudioOut2) {
|
|||||||
LIB_FUNC("bkBN+CMLwRc", AudioOut2::AudioOut2GetSystemState);
|
LIB_FUNC("bkBN+CMLwRc", AudioOut2::AudioOut2GetSystemState);
|
||||||
LIB_FUNC("xywYcRB7nbQ", AudioOut2::AudioOut2UserCreate);
|
LIB_FUNC("xywYcRB7nbQ", AudioOut2::AudioOut2UserCreate);
|
||||||
LIB_FUNC("IaZXJ9M79uo", AudioOut2::AudioOut2UserDestroy);
|
LIB_FUNC("IaZXJ9M79uo", AudioOut2::AudioOut2UserDestroy);
|
||||||
|
LIB_FUNC("iE8trxPKnAg", AudioOut2::AudioOut2UserGetSupportedAttributes);
|
||||||
LIB_FUNC("G1YOKDJYX2Y", AudioOut2::AudioOut2GetSpeakerArrayMemorySize);
|
LIB_FUNC("G1YOKDJYX2Y", AudioOut2::AudioOut2GetSpeakerArrayMemorySize);
|
||||||
LIB_FUNC("+k91hoTuoA8", AudioOut2::AudioOut2SpeakerArrayCreate);
|
LIB_FUNC("+k91hoTuoA8", AudioOut2::AudioOut2SpeakerArrayCreate);
|
||||||
LIB_FUNC("erCWQR5eKiQ", AudioOut2::AudioOut2SpeakerArrayDestroy);
|
LIB_FUNC("erCWQR5eKiQ", AudioOut2::AudioOut2SpeakerArrayDestroy);
|
||||||
|
|||||||
+43
-4
@@ -167,7 +167,7 @@ struct AudioOut2MasteringStatesV2 {
|
|||||||
|
|
||||||
static std::atomic_uint64_t g_audioout2_next_context {1};
|
static std::atomic_uint64_t g_audioout2_next_context {1};
|
||||||
static std::atomic_uint64_t g_audioout2_next_port {1};
|
static std::atomic_uint64_t g_audioout2_next_port {1};
|
||||||
static std::atomic_uint64_t g_audioout2_next_user {1};
|
static AudioOut2UserHandle g_audioout2_next_user = 1;
|
||||||
|
|
||||||
struct AudioOut2ContextState {
|
struct AudioOut2ContextState {
|
||||||
bool used = false;
|
bool used = false;
|
||||||
@@ -182,6 +182,7 @@ struct AudioOut2PortStateEntry {
|
|||||||
bool used = false;
|
bool used = false;
|
||||||
AudioOut2PortHandle handle = 0;
|
AudioOut2PortHandle handle = 0;
|
||||||
AudioOut2ContextHandle context = 0;
|
AudioOut2ContextHandle context = 0;
|
||||||
|
AudioOut2UserHandle user = 0;
|
||||||
uint16_t port_type = 0;
|
uint16_t port_type = 0;
|
||||||
uint32_t data_format = 0;
|
uint32_t data_format = 0;
|
||||||
uint32_t sampling_freq = 48000;
|
uint32_t sampling_freq = 48000;
|
||||||
@@ -210,6 +211,7 @@ static Common::Mutex g_audioout2_context_mutex;
|
|||||||
static std::array<AudioOut2ContextState, 16> g_audioout2_contexts;
|
static std::array<AudioOut2ContextState, 16> g_audioout2_contexts;
|
||||||
static Common::Mutex g_audioout2_port_mutex;
|
static Common::Mutex g_audioout2_port_mutex;
|
||||||
static std::array<AudioOut2PortStateEntry, 256> g_audioout2_ports;
|
static std::array<AudioOut2PortStateEntry, 256> g_audioout2_ports;
|
||||||
|
static std::vector<AudioOut2UserHandle> g_audioout2_users;
|
||||||
static Common::Mutex g_audioout2_speaker_array_mutex;
|
static Common::Mutex g_audioout2_speaker_array_mutex;
|
||||||
static std::array<AudioOut2SpeakerArrayState, 32> g_audioout2_speaker_arrays;
|
static std::array<AudioOut2SpeakerArrayState, 32> g_audioout2_speaker_arrays;
|
||||||
static Common::Mutex g_audioout2_latency_mutex;
|
static Common::Mutex g_audioout2_latency_mutex;
|
||||||
@@ -218,6 +220,7 @@ static std::array<AudioOut2LatencyState, 16> g_audioout2_latencies;
|
|||||||
static constexpr int AUDIO_OUT2_ERROR_NOT_READY = -2144960504; /* 0x80268008 */
|
static constexpr int AUDIO_OUT2_ERROR_NOT_READY = -2144960504; /* 0x80268008 */
|
||||||
static constexpr int AUDIO_OUT2_ERROR_PORT_FULL = -2144960494; /* 0x80268012 */
|
static constexpr int AUDIO_OUT2_ERROR_PORT_FULL = -2144960494; /* 0x80268012 */
|
||||||
static constexpr int AUDIO_OUT2_ERROR_INVALID_PARAM = -2144960511; /* 0x80268001 */
|
static constexpr int AUDIO_OUT2_ERROR_INVALID_PARAM = -2144960511; /* 0x80268001 */
|
||||||
|
static constexpr int AUDIO_OUT2_ERROR_BUSY = -2144960505; /* 0x80268007 */
|
||||||
static constexpr int AUDIO_OUT2_ERROR_MASTERING_INVALID_API_PARAM = -2144959999; /* 0x80268201 */
|
static constexpr int AUDIO_OUT2_ERROR_MASTERING_INVALID_API_PARAM = -2144959999; /* 0x80268201 */
|
||||||
static constexpr int AUDIO_OUT2_ERROR_MASTERING_INVALID_STATES_ID = -2144959996; /* 0x80268204 */
|
static constexpr int AUDIO_OUT2_ERROR_MASTERING_INVALID_STATES_ID = -2144959996; /* 0x80268204 */
|
||||||
static constexpr uint32_t AUDIO_OUT2_PORT_ATTRIBUTE_ID_PCM = 0;
|
static constexpr uint32_t AUDIO_OUT2_PORT_ATTRIBUTE_ID_PCM = 0;
|
||||||
@@ -589,6 +592,12 @@ int KYTY_SYSV_ABI AudioOut2PortCreate(AudioOut2ContextHandle ctx, const AudioOut
|
|||||||
const auto samples_num = context_state->num_grains == 0 ? 512u : context_state->num_grains;
|
const auto samples_num = context_state->num_grains == 0 ? 512u : context_state->num_grains;
|
||||||
|
|
||||||
g_audioout2_port_mutex.Lock();
|
g_audioout2_port_mutex.Lock();
|
||||||
|
if (std::find(g_audioout2_users.begin(), g_audioout2_users.end(), params->user_handle) ==
|
||||||
|
g_audioout2_users.end()) {
|
||||||
|
g_audioout2_port_mutex.Unlock();
|
||||||
|
g_audioout2_context_mutex.Unlock();
|
||||||
|
return AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
AudioOut2PortStateEntry* port_state = nullptr;
|
AudioOut2PortStateEntry* port_state = nullptr;
|
||||||
for (auto& candidate: g_audioout2_ports) {
|
for (auto& candidate: g_audioout2_ports) {
|
||||||
if (!candidate.used) {
|
if (!candidate.used) {
|
||||||
@@ -601,6 +610,7 @@ int KYTY_SYSV_ABI AudioOut2PortCreate(AudioOut2ContextHandle ctx, const AudioOut
|
|||||||
port_state->used = true;
|
port_state->used = true;
|
||||||
port_state->handle = next_port;
|
port_state->handle = next_port;
|
||||||
port_state->context = ctx;
|
port_state->context = ctx;
|
||||||
|
port_state->user = params->user_handle;
|
||||||
port_state->port_type = params->port_type;
|
port_state->port_type = params->port_type;
|
||||||
port_state->data_format = params->data_format;
|
port_state->data_format = params->data_format;
|
||||||
port_state->sampling_freq = params->sampling_freq;
|
port_state->sampling_freq = params->sampling_freq;
|
||||||
@@ -730,9 +740,12 @@ int KYTY_SYSV_ABI AudioOut2GetSystemState(AudioOut2SystemState* state) {
|
|||||||
|
|
||||||
int KYTY_SYSV_ABI AudioOut2UserCreate(uint32_t user_id, AudioOut2UserHandle* handle) {
|
int KYTY_SYSV_ABI AudioOut2UserCreate(uint32_t user_id, AudioOut2UserHandle* handle) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
EXIT_NOT_IMPLEMENTED(handle == nullptr);
|
if (handle == nullptr) {
|
||||||
*handle = static_cast<AudioOut2UserHandle>(
|
return AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||||
g_audioout2_next_user.fetch_add(1, std::memory_order_relaxed));
|
}
|
||||||
|
Common::LockGuard lock(g_audioout2_port_mutex);
|
||||||
|
*handle = g_audioout2_next_user++;
|
||||||
|
g_audioout2_users.push_back(*handle);
|
||||||
LOGF("\t user_id = %" PRIu32 ", handle = 0x%016" PRIx64 "\n", user_id,
|
LOGF("\t user_id = %" PRIu32 ", handle = 0x%016" PRIx64 "\n", user_id,
|
||||||
static_cast<uint64_t>(*handle));
|
static_cast<uint64_t>(*handle));
|
||||||
return OK;
|
return OK;
|
||||||
@@ -741,6 +754,32 @@ int KYTY_SYSV_ABI AudioOut2UserCreate(uint32_t user_id, AudioOut2UserHandle* han
|
|||||||
int KYTY_SYSV_ABI AudioOut2UserDestroy(AudioOut2UserHandle handle) {
|
int KYTY_SYSV_ABI AudioOut2UserDestroy(AudioOut2UserHandle handle) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
LOGF("\t handle = 0x%016" PRIx64 "\n", static_cast<uint64_t>(handle));
|
LOGF("\t handle = 0x%016" PRIx64 "\n", static_cast<uint64_t>(handle));
|
||||||
|
Common::LockGuard lock(g_audioout2_port_mutex);
|
||||||
|
const auto it = std::find(g_audioout2_users.begin(), g_audioout2_users.end(), handle);
|
||||||
|
if (it == g_audioout2_users.end()) {
|
||||||
|
return AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
if (std::any_of(g_audioout2_ports.begin(), g_audioout2_ports.end(),
|
||||||
|
[handle](const auto& port) { return port.used && port.user == handle; })) {
|
||||||
|
return AUDIO_OUT2_ERROR_BUSY;
|
||||||
|
}
|
||||||
|
g_audioout2_users.erase(it);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KYTY_SYSV_ABI AudioOut2UserGetSupportedAttributes(AudioOut2UserHandle handle,
|
||||||
|
uint32_t* context_attributes,
|
||||||
|
uint32_t* port_attributes) {
|
||||||
|
if (context_attributes == nullptr || port_attributes == nullptr) {
|
||||||
|
return AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
Common::LockGuard lock(g_audioout2_port_mutex);
|
||||||
|
if (std::find(g_audioout2_users.begin(), g_audioout2_users.end(), handle) ==
|
||||||
|
g_audioout2_users.end()) {
|
||||||
|
return AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
*context_attributes = 0;
|
||||||
|
*port_attributes = 1u << AUDIO_OUT2_PORT_ATTRIBUTE_ID_PCM;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace {
|
|||||||
|
|
||||||
namespace AudioOut2 = Libs::Audio::AudioOut2;
|
namespace AudioOut2 = Libs::Audio::AudioOut2;
|
||||||
|
|
||||||
|
AudioOut2::AudioOut2UserHandle g_user_handle = 0;
|
||||||
std::mutex g_device_mutex;
|
std::mutex g_device_mutex;
|
||||||
std::condition_variable g_device_cv;
|
std::condition_variable g_device_cv;
|
||||||
std::vector<int> g_live_devices;
|
std::vector<int> g_live_devices;
|
||||||
@@ -97,6 +98,7 @@ PortParam MakeParam(uint32_t data_format = 0x200) {
|
|||||||
PortParam param {};
|
PortParam param {};
|
||||||
param.data_format = data_format;
|
param.data_format = data_format;
|
||||||
param.sampling_freq = 48000;
|
param.sampling_freq = 48000;
|
||||||
|
param.user_handle = g_user_handle;
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +112,56 @@ AudioOut2::AudioOut2ContextHandle CreateContext(uint32_t queue_depth = 4) {
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestUserSupportedAttributes() {
|
||||||
|
constexpr int invalid_param = static_cast<int32_t>(0x80268001u);
|
||||||
|
constexpr int busy = static_cast<int32_t>(0x80268007u);
|
||||||
|
AudioOut2::AudioOut2UserHandle user = 0;
|
||||||
|
Check(AudioOut2::AudioOut2UserCreate(1000, nullptr) == invalid_param,
|
||||||
|
"null user handle output was accepted");
|
||||||
|
Check(AudioOut2::AudioOut2UserCreate(1000, &user) == OK, "user create failed");
|
||||||
|
uint32_t context_attributes = UINT32_MAX;
|
||||||
|
uint32_t port_attributes = UINT32_MAX;
|
||||||
|
Check(AudioOut2::AudioOut2UserGetSupportedAttributes(user, &context_attributes,
|
||||||
|
&port_attributes) == OK &&
|
||||||
|
context_attributes == 0 && port_attributes == 1,
|
||||||
|
"user capabilities do not match implemented PCM support");
|
||||||
|
|
||||||
|
context_attributes = port_attributes = UINT32_MAX;
|
||||||
|
Check(AudioOut2::AudioOut2UserGetSupportedAttributes(user, nullptr, &port_attributes) ==
|
||||||
|
invalid_param &&
|
||||||
|
AudioOut2::AudioOut2UserGetSupportedAttributes(user, &context_attributes, nullptr) ==
|
||||||
|
invalid_param &&
|
||||||
|
context_attributes == UINT32_MAX && port_attributes == UINT32_MAX,
|
||||||
|
"null capability outputs were accepted or modified");
|
||||||
|
for (const auto invalid: {AudioOut2::AudioOut2UserHandle {0}, UINTPTR_MAX}) {
|
||||||
|
Check(AudioOut2::AudioOut2UserGetSupportedAttributes(invalid, &context_attributes,
|
||||||
|
&port_attributes) == invalid_param &&
|
||||||
|
context_attributes == UINT32_MAX && port_attributes == UINT32_MAX,
|
||||||
|
"invalid user capabilities succeeded or modified outputs");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto context = CreateContext();
|
||||||
|
auto param = MakeParam();
|
||||||
|
param.user_handle = user;
|
||||||
|
AudioOut2::AudioOut2PortHandle port = 0;
|
||||||
|
Check(AudioOut2::AudioOut2PortCreate(context, AsParam(¶m), &port) == OK,
|
||||||
|
"user port create failed");
|
||||||
|
Check(AudioOut2::AudioOut2UserDestroy(user) == busy,
|
||||||
|
"user was destroyed while owning a port");
|
||||||
|
AudioOut2::AudioOut2ContextDestroy(context);
|
||||||
|
Check(AudioOut2::AudioOut2UserDestroy(user) == OK, "unused user destroy failed");
|
||||||
|
Check(AudioOut2::AudioOut2UserGetSupportedAttributes(user, &context_attributes,
|
||||||
|
&port_attributes) == invalid_param &&
|
||||||
|
context_attributes == UINT32_MAX && port_attributes == UINT32_MAX &&
|
||||||
|
AudioOut2::AudioOut2UserDestroy(user) == invalid_param,
|
||||||
|
"destroyed user remained valid");
|
||||||
|
|
||||||
|
const auto new_context = CreateContext();
|
||||||
|
Check(AudioOut2::AudioOut2PortCreate(new_context, AsParam(¶m), &port) == invalid_param,
|
||||||
|
"destroyed user acquired a port");
|
||||||
|
AudioOut2::AudioOut2ContextDestroy(new_context);
|
||||||
|
}
|
||||||
|
|
||||||
void BlockDeviceOpens() {
|
void BlockDeviceOpens() {
|
||||||
std::lock_guard lock(g_device_mutex);
|
std::lock_guard lock(g_device_mutex);
|
||||||
g_open_waiters = 0;
|
g_open_waiters = 0;
|
||||||
@@ -436,6 +488,8 @@ uint64_t KYTY_SYSV_ABI KernelGetProcessTime() {
|
|||||||
} // namespace Libs::LibKernel
|
} // namespace Libs::LibKernel
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
Check(AudioOut2::AudioOut2UserCreate(1000, &g_user_handle) == OK, "test user create failed");
|
||||||
|
TestUserSupportedAttributes();
|
||||||
TestSlotReuse();
|
TestSlotReuse();
|
||||||
TestFullTableRecovers();
|
TestFullTableRecovers();
|
||||||
TestConcurrentCreates();
|
TestConcurrentCreates();
|
||||||
@@ -445,6 +499,7 @@ int main() {
|
|||||||
TestAsynchronousDevicePushKeepsQueueBounded();
|
TestAsynchronousDevicePushKeepsQueueBounded();
|
||||||
TestHandleWithoutPcmDoesNotBypassQueue();
|
TestHandleWithoutPcmDoesNotBypassQueue();
|
||||||
TestPcmCopiedBeforeScratchBufferReuse();
|
TestPcmCopiedBeforeScratchBufferReuse();
|
||||||
|
Check(AudioOut2::AudioOut2UserDestroy(g_user_handle) == OK, "test user destroy failed");
|
||||||
std::printf("AudioOut2PortTests: all cases passed\n");
|
std::printf("AudioOut2PortTests: all cases passed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user