mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
164 lines
5.1 KiB
C++
164 lines
5.1 KiB
C++
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/General.hpp"
|
|
|
|
namespace {
|
|
|
|
constexpr std::int32_t VOICE_QOS_APP_TYPE_GAME = 0x20000000;
|
|
constexpr std::int32_t VOICE_QOS_APP_TYPE_10000000 = 0x10000000;
|
|
constexpr std::uint32_t VOICE_QOS_MEMORY_SIZE = 0x40000;
|
|
constexpr int SCE_VOICE_ERROR_LIBVOICEQOS_NOT_INIT = static_cast<int>(0x804E0901);
|
|
constexpr int SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID = static_cast<int>(0x804E0902);
|
|
constexpr int SCE_VOICE_ERROR_LIBVOICEQOS_INITIALIZED = static_cast<int>(0x804E0905);
|
|
|
|
using Endpoint = std::map<std::int32_t, std::vector<std::uint8_t>>;
|
|
|
|
struct Connection {
|
|
std::int32_t local;
|
|
std::int32_t remote;
|
|
};
|
|
|
|
struct QoS {
|
|
std::mutex mutex;
|
|
bool initialized = false;
|
|
std::int32_t nextId = 1;
|
|
std::map<std::int32_t, Endpoint> locals;
|
|
std::map<std::int32_t, Endpoint> remotes;
|
|
std::map<std::int32_t, Connection> connections;
|
|
};
|
|
|
|
QoS& State() {
|
|
static QoS qos;
|
|
return qos;
|
|
}
|
|
|
|
std::int32_t NewId(QoS& qos) {
|
|
const std::int32_t id = qos.nextId;
|
|
qos.nextId = qos.nextId == std::numeric_limits<std::int32_t>::max() ? 1 : qos.nextId + 1;
|
|
return id;
|
|
}
|
|
|
|
int CreateEndpoint(std::int32_t* id, std::map<std::int32_t, Endpoint>& endpoints, QoS& qos) {
|
|
if (!id) return SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID;
|
|
*id = NewId(qos);
|
|
endpoints.emplace(*id, Endpoint{});
|
|
return 0;
|
|
}
|
|
|
|
int DeleteEndpoint(std::int32_t id, std::map<std::int32_t, Endpoint>& endpoints) {
|
|
return endpoints.erase(id) != 0 ? 0 : SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID;
|
|
}
|
|
|
|
int SetAttribute(std::map<std::int32_t, Endpoint>& endpoints, std::int32_t id, std::int32_t attribute, const void* value, std::int32_t size) {
|
|
const auto endpoint = endpoints.find(id);
|
|
if (endpoint == endpoints.end() || !value) return SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID;
|
|
if (size > 0) {
|
|
const auto* bytes = static_cast<const std::uint8_t*>(value);
|
|
endpoint->second[attribute].assign(bytes, bytes + size);
|
|
} else {
|
|
endpoint->second[attribute].clear();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template<typename Body>
|
|
int Locked(Body&& body) {
|
|
auto& qos = State();
|
|
std::lock_guard lock(qos.mutex);
|
|
if (!qos.initialized) return SCE_VOICE_ERROR_LIBVOICEQOS_NOT_INIT;
|
|
return body(qos);
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
int APS5_VABI sceVoiceQoSInit(void* memBlock, uint32_t memSize, int32_t appType) {
|
|
auto& qos = State();
|
|
std::lock_guard lock(qos.mutex);
|
|
if (qos.initialized) return SCE_VOICE_ERROR_LIBVOICEQOS_INITIALIZED;
|
|
if (!memBlock || memSize != VOICE_QOS_MEMORY_SIZE || (appType != VOICE_QOS_APP_TYPE_GAME && appType != VOICE_QOS_APP_TYPE_10000000)) return SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID;
|
|
qos.initialized = true;
|
|
return 0;
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSEnd() {
|
|
return Locked([](QoS& qos) {
|
|
qos.connections.clear();
|
|
qos.locals.clear();
|
|
qos.remotes.clear();
|
|
qos.initialized = false;
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSCreateLocalEndpoint(int32_t* localId, int32_t userId, int32_t deviceInId, int32_t deviceOutId) {
|
|
(void)userId;
|
|
(void)deviceInId;
|
|
(void)deviceOutId;
|
|
return Locked([&](QoS& qos) { return CreateEndpoint(localId, qos.locals, qos); });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSDeleteLocalEndpoint(int32_t localId) {
|
|
return Locked([&](QoS& qos) { return DeleteEndpoint(localId, qos.locals); });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSCreateRemoteEndpoint(int32_t* remoteId) {
|
|
return Locked([&](QoS& qos) { return CreateEndpoint(remoteId, qos.remotes, qos); });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSDeleteRemoteEndpoint(int32_t remoteId) {
|
|
return Locked([&](QoS& qos) { return DeleteEndpoint(remoteId, qos.remotes); });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSConnect(int32_t* connectionId, int32_t localId, int32_t remoteId) {
|
|
return Locked([&](QoS& qos) {
|
|
if (!connectionId || !qos.locals.contains(localId) || !qos.remotes.contains(remoteId)) return SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID;
|
|
*connectionId = NewId(qos);
|
|
qos.connections.emplace(*connectionId, Connection{localId, remoteId});
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSDisconnect(int32_t connectionId) {
|
|
return Locked([&](QoS& qos) { return qos.connections.erase(connectionId) != 0 ? 0 : SCE_VOICE_ERROR_LIBVOICEQOS_ARGUMENT_INVALID; });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSSetConnectionAttribute() {
|
|
NotImplemented_nid_no_patch(__func__);
|
|
return 0;
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSSetLocalEndpointAttribute(int32_t localId, int32_t attributeId, const void* value, int32_t size) {
|
|
return Locked([&](QoS& qos) { return SetAttribute(qos.locals, localId, attributeId, value, size); });
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSSetRemoteEndpointAttribute() {
|
|
NotImplemented_nid_no_patch(__func__);
|
|
return 0;
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSReadPacket() {
|
|
NotImplemented_nid_no_patch(__func__);
|
|
return 0;
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSWritePacket() {
|
|
NotImplemented_nid_no_patch(__func__);
|
|
return 0;
|
|
}
|
|
|
|
int APS5_VABI sceVoiceQoSGetLocalEndpointAttribute() {
|
|
NotImplemented_nid_no_patch(__func__);
|
|
return 0;
|
|
}
|
|
|
|
}
|