diff --git a/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp index e62ce9d5dbc2..0607f6f77b3c 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" +#include "util/asm.hpp" #include "sceNp.h" #include "sceNp2.h" @@ -67,6 +68,10 @@ struct avc2_settings vm::ptr avc2_cb{}; vm::ptr avc2_cb_arg{}; + u32 streaming_mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL; + u8 mic_out_stream_sharing = 0; + u8 video_stream_sharing = 0; + u32 total_video_bitrate = 0; }; error_code cellSysutilAvc2GetPlayerInfo(vm::cptr player_id, vm::ptr player_info) @@ -250,27 +255,6 @@ error_code cellSysutilAvc2GetAttribute(vm::ptr attr) return CELL_OK; } -error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr callback_func, vm::ptr user_data, vm::cptr init_param) -{ - cellSysutilAvc2.warning("cellSysutilAvc2LoadAsync(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param); - - auto& settings = g_fxo->get(); - - settings.avc2_cb = callback_func; - settings.avc2_cb_arg = user_data; - - if (settings.avc2_cb) - { - sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32 - { - avc2_cb(cb_ppu, CELL_AVC2_EVENT_LOAD_SUCCEEDED, 0, avc2_cb_arg); - return 0; - }); - } - - return CELL_OK; -} - error_code cellSysutilAvc2SetSpeakerVolumeLevel(f32 level) { cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerVolumeLevel(level=0x%x)", level); @@ -686,14 +670,196 @@ error_code cellSysutilAvc2SetSpeakerMuting(u8 muting) return CELL_OK; } +error_code cellSysutilAvc2Load_shared(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr callback_func, vm::ptr user_data, vm::cptr init_param) +{ + if (!init_param || !init_param->avc_init_param_version || + !(init_param->avc_init_param_version == 100 || + init_param->avc_init_param_version == 110 || + init_param->avc_init_param_version == 120 || + init_param->avc_init_param_version == 130 || + init_param->avc_init_param_version == 140) + ) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + auto& settings = g_fxo->get(); + + switch (init_param->media_type) + { + case CELL_SYSUTIL_AVC2_VOICE_CHAT: + { + if (init_param->max_players < 2 || + init_param->max_players > 64 || + init_param->spu_load_average > 100 || + init_param->voice_param.voice_quality != CELL_SYSUTIL_AVC2_VOICE_QUALITY_NORMAL || + init_param->voice_param.max_speakers == 0 || + init_param->voice_param.max_speakers > 16 + ) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + u32 streaming_mode = init_param->direct_streaming_mode; + + if (init_param->avc_init_param_version >= 120) + { + switch (init_param->direct_streaming_mode) + { + case CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL: + streaming_mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL; + break; + case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_WAN: + break; + case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_LAN: + if (init_param->streaming_mode.mode == CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL) + { + settings.streaming_mode = streaming_mode; + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + break; + default: + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + } + else if (init_param->avc_init_param_version >= 110) + { + switch (init_param->direct_streaming_mode) + { + case CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL: + case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_WAN: + break; + case CELL_SYSUTIL_AVC2_STREAMING_MODE_DIRECT_LAN: + default: + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + } + else + { + streaming_mode = settings.streaming_mode; + } + + settings.streaming_mode = streaming_mode; + settings.mic_out_stream_sharing = init_param->voice_param.mic_out_stream_sharing; + + if (!callback_func) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + if (settings.avc2_cb) + { + return CELL_AVC2_ERROR_ALREADY_INITIALIZED; + } + + settings.avc2_cb = callback_func; + settings.avc2_cb_arg = user_data; + break; + } + case CELL_SYSUTIL_AVC2_VIDEO_CHAT: + { + if (false) // TODO: syscall to check container + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + if (init_param->avc_init_param_version <= 140) + { + if (false) // TODO + { + return CELL_AVC2_ERROR_OUT_OF_MEMORY; + } + } + + if (callback_func) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + if (init_param->video_param.max_video_windows == 0 || + init_param->video_param.max_video_windows > (init_param->video_param.frame_mode == CELL_SYSUTIL_AVC2_FRAME_MODE_NORMAL ? 6 : 16)) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + if (init_param->video_param.max_video_bitrate < 1000 || init_param->video_param.max_video_bitrate > 512000) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + if (init_param->video_param.max_video_framerate == 0 || init_param->video_param.max_video_framerate > 30) + { + return CELL_AVC2_ERROR_INVALID_ARGUMENT; + } + + s32 bitrate = 0; + + switch (init_param->video_param.max_video_resolution) + { + case CELL_SYSUTIL_AVC2_VIDEO_RESOLUTION_QQVGA: + bitrate = 76800; + break; + case CELL_SYSUTIL_AVC2_VIDEO_RESOLUTION_QVGA: + bitrate = 307200; + break; + default: + break; + } + + u32 total_bitrate = 0; + + if (bitrate != 0) + { + u32 window_count = init_param->video_param.max_video_windows; + + if (init_param->video_param.video_stream_sharing == CELL_SYSUTIL_AVC2_VIDEO_SHARING_MODE_2) + { + window_count++; + } + + total_bitrate = utils::align(window_count * bitrate, 0x100000) + 0x100000; + } + + settings.video_stream_sharing = init_param->video_param.video_stream_sharing; + settings.total_video_bitrate = total_bitrate; + break; + } + default: + return CELL_AVC2_ERROR_NOT_SUPPORTED; + } + + return CELL_OK; +} + error_code cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr callback_func, vm::ptr user_data, vm::cptr init_param) { cellSysutilAvc2.warning("cellSysutilAvc2Load(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param); + error_code error = cellSysutilAvc2Load_shared(ctx_id, container, callback_func, user_data, init_param); + if (error != CELL_OK) + return error; + + return CELL_OK; +} + +error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr callback_func, vm::ptr user_data, vm::cptr init_param) +{ + cellSysutilAvc2.warning("cellSysutilAvc2LoadAsync(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param); + + error_code error = cellSysutilAvc2Load_shared(ctx_id, container, callback_func, user_data, init_param); + if (error != CELL_OK) + return error; + auto& settings = g_fxo->get(); - settings.avc2_cb = callback_func; - settings.avc2_cb_arg = user_data; + if (settings.avc2_cb && init_param && init_param->media_type == CELL_SYSUTIL_AVC2_VOICE_CHAT) + { + sysutil_register_cb([=, avc2_cb = settings.avc2_cb, avc2_cb_arg = settings.avc2_cb_arg](ppu_thread& cb_ppu) -> s32 + { + avc2_cb(cb_ppu, CELL_AVC2_EVENT_LOAD_SUCCEEDED, 0, avc2_cb_arg); + return 0; + }); + } return CELL_OK; }