#include "stdafx.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/lv2/sys_event.h" #include "Emu/Cell/lv2/sys_process.h" #include "cellVoice.h" LOG_CHANNEL(cellVoice); template<> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto error) { switch (error) { STR_CASE(CELL_VOICE_ERROR_ADDRESS_INVALID); STR_CASE(CELL_VOICE_ERROR_ARGUMENT_INVALID); STR_CASE(CELL_VOICE_ERROR_CONTAINER_INVALID); STR_CASE(CELL_VOICE_ERROR_DEVICE_NOT_PRESENT); STR_CASE(CELL_VOICE_ERROR_EVENT_DISPATCH); STR_CASE(CELL_VOICE_ERROR_EVENT_QUEUE); STR_CASE(CELL_VOICE_ERROR_GENERAL); STR_CASE(CELL_VOICE_ERROR_LIBVOICE_INITIALIZED); STR_CASE(CELL_VOICE_ERROR_LIBVOICE_NOT_INIT); STR_CASE(CELL_VOICE_ERROR_NOT_IMPLEMENTED); STR_CASE(CELL_VOICE_ERROR_PORT_INVALID); STR_CASE(CELL_VOICE_ERROR_RESOURCE_INSUFFICIENT); STR_CASE(CELL_VOICE_ERROR_SERVICE_ATTACHED); STR_CASE(CELL_VOICE_ERROR_SERVICE_DETACHED); STR_CASE(CELL_VOICE_ERROR_SERVICE_HANDLE); STR_CASE(CELL_VOICE_ERROR_SERVICE_NOT_FOUND); STR_CASE(CELL_VOICE_ERROR_SHAREDMEMORY); STR_CASE(CELL_VOICE_ERROR_TOPOLOGY); } return unknown; }); } void voice_manager::reset() { id_ctr = 0; port_source = 0; ports.clear(); queue_keys.clear(); } error_code cellVoiceConnectIPortToOPort(u32 ips, u32 ops) { cellVoice.todo("cellVoiceConnectIPortToOPort(ips=%d, ops=%d)", ips, ops); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto iport = manager->access_port(ips); if (!iport || iport->info.portType >= CELLVOICE_PORTTYPE_OUT_PCMAUDIO) return CELL_VOICE_ERROR_TOPOLOGY; auto oport = manager->access_port(ops); if (!oport || oport->info.portType <= CELLVOICE_PORTTYPE_IN_VOICE) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceCreateNotifyEventQueue(vm::ptr id, vm::ptr key) { cellVoice.warning("cellVoiceCreateNotifyEventQueue(id=*0x%x, key=*0x%x)", id, key); auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; vm::var attr; attr->protocol = SYS_SYNC_FIFO; attr->type = SYS_PPU_QUEUE; attr->name_u64 = 0; for (u64 i = 0; i < 10; i++) { // Create an event queue "bruteforcing" an available key const u64 key_value = 0x80004d494f323285ull + i; if (CellError res{sys_event_queue_create(id, attr, key_value, 0x40) + 0u}) { if (res != CELL_EEXIST) { return res; } } else { *key = key_value; return CELL_OK; } } return CELL_VOICE_ERROR_EVENT_QUEUE; } error_code cellVoiceCreatePort(vm::ptr portId, vm::cptr pArg) { cellVoice.warning("cellVoiceCreatePort(portId=*0x%x, pArg=*0x%x)", portId, pArg); auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (!pArg) return CELL_VOICE_ERROR_ARGUMENT_INVALID; switch (pArg->portType) { case CELLVOICE_PORTTYPE_IN_PCMAUDIO: case CELLVOICE_PORTTYPE_OUT_PCMAUDIO: { if (pArg->pcmaudio.format.dataType > CELLVOICE_PCM_INTEGER_LITTLE_ENDIAN) return CELL_VOICE_ERROR_ARGUMENT_INVALID; break; } case CELLVOICE_PORTTYPE_IN_VOICE: case CELLVOICE_PORTTYPE_OUT_VOICE: { // Must be an exact value switch (pArg->voice.bitrate) { case CELLVOICE_BITRATE_3850: case CELLVOICE_BITRATE_4650: case CELLVOICE_BITRATE_5700: case CELLVOICE_BITRATE_7300: case CELLVOICE_BITRATE_14400: case CELLVOICE_BITRATE_16000: case CELLVOICE_BITRATE_22533: break; default: { return CELL_VOICE_ERROR_ARGUMENT_INVALID; } } } case CELLVOICE_PORTTYPE_IN_MIC: case CELLVOICE_PORTTYPE_OUT_SECONDARY: { break; } default: return CELL_VOICE_ERROR_ARGUMENT_INVALID; } if (manager->ports.size() > CELLVOICE_MAX_PORT) return CELL_VOICE_ERROR_RESOURCE_INSUFFICIENT; // Id: bits [8,15] seem to contain a "random" value // bits [0,7] are based on creation counter modulo 0xa0 // The rest are set to zero and ignored. manager->id_ctr++; manager->id_ctr %= 0xa0; // It isn't known whether bits[8,15] are guaranteed to be non-zero constexpr u32 min_value = 1; for (u32 ctr2 = min_value; ctr2 < CELLVOICE_MAX_PORT + min_value; ctr2++) { const auto [port, success] = manager->ports.try_emplace(static_cast((ctr2 << 8) | manager->id_ctr)); if (success) { port->second.info = *pArg; *portId = port->first; return CELL_OK; } } fmt::throw_exception("Unreachable" HERE); } error_code cellVoiceDeletePort(u32 portId) { cellVoice.warning("cellVoiceDeletePort(portId=%d)", portId); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (manager->ports.erase(static_cast(portId)) == 0) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceDisconnectIPortFromOPort(u32 ips, u32 ops) { cellVoice.todo("cellVoiceDisconnectIPortFromOPort(ips=%d, ops=%d)", ips, ops); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto iport = manager->access_port(ips); if (!iport || iport->info.portType >= CELLVOICE_PORTTYPE_OUT_PCMAUDIO) return CELL_VOICE_ERROR_TOPOLOGY; auto oport = manager->access_port(ops); if (!oport || oport->info.portType <= CELLVOICE_PORTTYPE_IN_VOICE) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceEnd() { cellVoice.warning("cellVoiceEnd()"); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (std::exchange(manager->voice_service_started, false)) { for (auto& key_pair : manager->queue_keys) { if (auto queue = lv2_event_queue::find(key_pair.first)) { for (const auto& source : key_pair.second) { queue->send(source, CELLVOICE_EVENT_SERVICE_DETACHED, 0, 0); } } } } manager->reset(); manager->is_init = false; return CELL_OK; } error_code cellVoiceGetBitRate(u32 portId, vm::ptr bitrate) { cellVoice.warning("cellVoiceGetBitRate(portId=%d, bitrate=*0x%x)", portId, bitrate); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; // No nullptr check! // Constant value for errors (meaning unknown) *bitrate = 0x4f323285; auto port = manager->access_port(portId); if (!port || (port->info.portType != CELLVOICE_PORTTYPE_IN_VOICE && port->info.portType != CELLVOICE_PORTTYPE_OUT_VOICE)) return CELL_VOICE_ERROR_TOPOLOGY; *bitrate = port->info.voice.bitrate; return CELL_OK; } error_code cellVoiceGetMuteFlag(u32 portId, vm::ptr bMuted) { cellVoice.warning("cellVoiceGetMuteFlag(portId=%d, bMuted=*0x%x)", portId, bMuted); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; *bMuted = port->info.bMute; return CELL_OK; } error_code cellVoiceGetPortAttr(u32 portId, u32 attr, vm::ptr attrValue) { cellVoice.todo("cellVoiceGetPortAttr(portId=%d, attr=%d, attrValue=*0x%x)", portId, attr, attrValue); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; // Report detached microphone return not_an_error(CELL_VOICE_ERROR_DEVICE_NOT_PRESENT); } error_code cellVoiceGetPortInfo(u32 portId, vm::ptr pInfo) { cellVoice.todo("cellVoiceGetPortInfo(portId=%d, pInfo=*0x%x)", portId, pInfo); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; if (!manager->voice_service_started) return CELL_VOICE_ERROR_SERVICE_DETACHED; // No nullptr check! pInfo->portType = port->info.portType; // TODO return CELL_OK; } error_code cellVoiceGetSignalState(u32 portId, u32 attr, vm::ptr attrValue) { cellVoice.todo("cellVoiceGetSignalState(portId=%d, attr=%d, attrValue=*0x%x)", portId, attr, attrValue); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; // Report detached microphone return not_an_error(CELL_VOICE_ERROR_DEVICE_NOT_PRESENT); } error_code cellVoiceGetVolume(u32 portId, vm::ptr volume) { cellVoice.warning("cellVoiceGetVolume(portId=%d, volume=*0x%x)", portId, volume); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); // No nullptr check! // Constant value for errors (meaning unknown) *volume = std::bit_cast(0x4f323285); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; *volume = port->info.volume; return CELL_OK; } error_code cellVoiceInit(vm::ptr pArg) { cellVoice.todo("cellVoiceInit(pArg=*0x%x)", pArg); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_INITIALIZED; if (!pArg) return CELL_VOICE_ERROR_ARGUMENT_INVALID; manager->is_init = true; return CELL_OK; } error_code cellVoiceInitEx(vm::ptr pArg) { cellVoice.todo("cellVoiceInitEx(pArg=*0x%x)", pArg); const auto manager = g_fxo->get(); if (manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_INITIALIZED; if (!pArg) return CELL_VOICE_ERROR_ARGUMENT_INVALID; manager->is_init = true; return CELL_OK; } error_code cellVoicePausePort(u32 portId) { cellVoice.todo("cellVoicePausePort(portId=%d)", portId); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoicePausePortAll() { cellVoice.todo("cellVoicePausePortAll()"); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; return CELL_OK; } error_code cellVoiceRemoveNotifyEventQueue(u64 key) { cellVoice.warning("cellVoiceRemoveNotifyEventQueue(key=0x%llx)", key); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (manager->queue_keys.erase(key) == 0) return CELL_VOICE_ERROR_EVENT_QUEUE; return CELL_OK; } error_code cellVoiceResetPort(u32 portId) { cellVoice.todo("cellVoiceResetPort(portId=%d)", portId); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceResumePort(u32 portId) { cellVoice.todo("cellVoiceResumePort(portId=%d)", portId); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceResumePortAll() { cellVoice.todo("cellVoiceResumePortAll()"); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; return CELL_OK; } error_code cellVoiceSetBitRate(u32 portId, CellVoiceBitRate bitrate) { cellVoice.warning("cellVoiceSetBitRate(portId=%d, bitrate=%d)", portId, +bitrate); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port || (port->info.portType != CELLVOICE_PORTTYPE_IN_VOICE && port->info.portType != CELLVOICE_PORTTYPE_OUT_VOICE)) return CELL_VOICE_ERROR_TOPOLOGY; // TODO: Check ordering of checks. switch (bitrate) { case CELLVOICE_BITRATE_3850: case CELLVOICE_BITRATE_4650: case CELLVOICE_BITRATE_5700: case CELLVOICE_BITRATE_7300: case CELLVOICE_BITRATE_14400: case CELLVOICE_BITRATE_16000: case CELLVOICE_BITRATE_22533: break; default: { return CELL_VOICE_ERROR_ARGUMENT_INVALID; } } port->info.voice.bitrate = bitrate; return CELL_OK; } error_code cellVoiceSetMuteFlag(u32 portId, u16 bMuted) { cellVoice.warning("cellVoiceSetMuteFlag(portId=%d, bMuted=%d)", portId, bMuted); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; port->info.bMute = bMuted; return CELL_OK; } error_code cellVoiceSetMuteFlagAll(u16 bMuted) { cellVoice.warning("cellVoiceSetMuteFlagAll(bMuted=%d)", bMuted); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; // Doesn't change port->bMute value return CELL_OK; } error_code cellVoiceSetNotifyEventQueue(u64 key, u64 source) { cellVoice.warning("cellVoiceSetNotifyEventQueue(key=0x%llx, source=0x%llx)", key, source); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; // Note: it is allowed to enqueue the key twice (another source is enqueued with FIFO ordering) // It is not allowed to enqueue an invalid key if (!lv2_event_queue::find(key)) return CELL_VOICE_ERROR_EVENT_QUEUE; if (!source) { // same thing as sys_event_port_send with port.name == 0 // Try to give different port id everytime source = ((process_getpid() + 1ull) << 32) | (lv2_event_port::id_base + manager->port_source * lv2_event_port::id_step); manager->port_source = (manager->port_source + 1) % lv2_event_port::id_count; } manager->queue_keys[key].push_back(source); return CELL_OK; } error_code cellVoiceSetPortAttr(u32 portId, u32 attr, vm::ptr attrValue) { cellVoice.todo("cellVoiceSetPortAttr(portId=%d, attr=%d, attrValue=*0x%x)", portId, attr, attrValue); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; // Report detached microphone return not_an_error(CELL_VOICE_ERROR_DEVICE_NOT_PRESENT); } error_code cellVoiceSetVolume(u32 portId, f32 volume) { cellVoice.warning("cellVoiceSetVolume(portId=%d, volume=%f)", portId, volume); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; port->info.volume = volume; return CELL_OK; } error_code VoiceStart(voice_manager* manager) { if (std::exchange(manager->voice_service_started, true)) return CELL_OK; for (auto& key_pair : manager->queue_keys) { if (auto queue = lv2_event_queue::find(key_pair.first)) { for (const auto& source : key_pair.second) { queue->send(source, CELLVOICE_EVENT_SERVICE_ATTACHED, 0, 0); } } } return CELL_OK; } error_code cellVoiceStart() { cellVoice.warning("cellVoiceStart()"); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; return VoiceStart(manager); } error_code cellVoiceStartEx(vm::ptr pArg) { cellVoice.todo("cellVoiceStartEx(pArg=*0x%x)", pArg); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (!pArg) return CELL_VOICE_ERROR_ARGUMENT_INVALID; // TODO: Check provided memory container return VoiceStart(manager); } error_code cellVoiceStop() { cellVoice.warning("cellVoiceStop()"); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (!std::exchange(manager->voice_service_started, false)) return CELL_OK; for (auto& key_pair : manager->queue_keys) { if (auto queue = lv2_event_queue::find(key_pair.first)) { for (const auto& source : key_pair.second) { queue->send(source, CELLVOICE_EVENT_SERVICE_DETACHED, 0, 0); } } } return CELL_OK; } error_code cellVoiceUpdatePort(u32 portId, vm::cptr pArg) { cellVoice.warning("cellVoiceUpdatePort(portId=%d, pArg=*0x%x)", portId, pArg); const auto manager = g_fxo->get(); std::scoped_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; if (!pArg) return CELL_VOICE_ERROR_ARGUMENT_INVALID; auto port = manager->access_port(portId); if (!port) return CELL_VOICE_ERROR_TOPOLOGY; // Not all info is updated port->info.bMute = pArg->bMute; port->info.volume = pArg->volume; port->info.threshold = pArg->threshold; if (port->info.portType == CELLVOICE_PORTTYPE_IN_VOICE || port->info.portType == CELLVOICE_PORTTYPE_OUT_VOICE) { port->info.voice.bitrate = pArg->voice.bitrate; } return CELL_OK; } error_code cellVoiceWriteToIPort(u32 ips, vm::cptr data, vm::ptr size) { cellVoice.todo("cellVoiceWriteToIPort(ips=%d, data=*0x%x, size=*0x%x)", ips, data, size); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto iport = manager->access_port(ips); if (!iport || iport->info.portType >= CELLVOICE_PORTTYPE_OUT_PCMAUDIO) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceWriteToIPortEx(u32 ips, vm::cptr data, vm::ptr size, u32 numFrameLost) { cellVoice.todo("cellVoiceWriteToIPortEx(ips=%d, data=*0x%x, size=*0x%x, numFrameLost=%d)", ips, data, size, numFrameLost); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto iport = manager->access_port(ips); if (!iport || iport->info.portType >= CELLVOICE_PORTTYPE_OUT_PCMAUDIO) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceWriteToIPortEx2(u32 ips, vm::cptr data, vm::ptr size, s16 frameGaps) { cellVoice.todo("cellVoiceWriteToIPortEx2(ips=%d, data=*0x%x, size=*0x%x, frameGaps=%d)", ips, data, size, frameGaps); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto iport = manager->access_port(ips); if (!iport || iport->info.portType >= CELLVOICE_PORTTYPE_OUT_PCMAUDIO) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceReadFromOPort(u32 ops, vm::ptr data, vm::ptr size) { cellVoice.todo("cellVoiceReadFromOPort(ops=%d, data=*0x%x, size=*0x%x)", ops, data, size); const auto manager = g_fxo->get(); std::shared_lock lock(manager->mtx); if (!manager->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; auto oport = manager->access_port(ops); if (!oport || oport->info.portType <= CELLVOICE_PORTTYPE_IN_VOICE) return CELL_VOICE_ERROR_TOPOLOGY; return CELL_OK; } error_code cellVoiceDebugTopology() { UNIMPLEMENTED_FUNC(cellVoice); if (!g_fxo->get()->is_init) return CELL_VOICE_ERROR_LIBVOICE_NOT_INIT; return CELL_VOICE_ERROR_NOT_IMPLEMENTED; } DECLARE(ppu_module_manager::cellVoice)("cellVoice", []() { REG_FUNC(cellVoice, cellVoiceConnectIPortToOPort); REG_FUNC(cellVoice, cellVoiceCreateNotifyEventQueue); REG_FUNC(cellVoice, cellVoiceCreatePort); REG_FUNC(cellVoice, cellVoiceDeletePort); REG_FUNC(cellVoice, cellVoiceDisconnectIPortFromOPort); REG_FUNC(cellVoice, cellVoiceEnd); REG_FUNC(cellVoice, cellVoiceGetBitRate); REG_FUNC(cellVoice, cellVoiceGetMuteFlag); REG_FUNC(cellVoice, cellVoiceGetPortAttr); REG_FUNC(cellVoice, cellVoiceGetPortInfo); REG_FUNC(cellVoice, cellVoiceGetSignalState); REG_FUNC(cellVoice, cellVoiceGetVolume); REG_FUNC(cellVoice, cellVoiceInit); REG_FUNC(cellVoice, cellVoiceInitEx); REG_FUNC(cellVoice, cellVoicePausePort); REG_FUNC(cellVoice, cellVoicePausePortAll); REG_FUNC(cellVoice, cellVoiceRemoveNotifyEventQueue); REG_FUNC(cellVoice, cellVoiceResetPort); REG_FUNC(cellVoice, cellVoiceResumePort); REG_FUNC(cellVoice, cellVoiceResumePortAll); REG_FUNC(cellVoice, cellVoiceSetBitRate); REG_FUNC(cellVoice, cellVoiceSetMuteFlag); REG_FUNC(cellVoice, cellVoiceSetMuteFlagAll); REG_FUNC(cellVoice, cellVoiceSetNotifyEventQueue); REG_FUNC(cellVoice, cellVoiceSetPortAttr); REG_FUNC(cellVoice, cellVoiceSetVolume); REG_FUNC(cellVoice, cellVoiceStart); REG_FUNC(cellVoice, cellVoiceStartEx); REG_FUNC(cellVoice, cellVoiceStop); REG_FUNC(cellVoice, cellVoiceUpdatePort); REG_FUNC(cellVoice, cellVoiceWriteToIPort); REG_FUNC(cellVoice, cellVoiceWriteToIPortEx); REG_FUNC(cellVoice, cellVoiceWriteToIPortEx2); REG_FUNC(cellVoice, cellVoiceReadFromOPort); REG_FUNC(cellVoice, cellVoiceDebugTopology); });