Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cellSysutilAvc2Load: param checks #15439

Merged
merged 9 commits into from
Apr 12, 2024
212 changes: 189 additions & 23 deletions rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -67,6 +68,10 @@ struct avc2_settings

vm::ptr<CellSysutilAvc2Callback> avc2_cb{};
vm::ptr<void> 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<SceNpMatching2RoomMemberId> player_id, vm::ptr<CellSysutilAvc2PlayerInfo> player_info)
Expand Down Expand Up @@ -250,27 +255,6 @@ error_code cellSysutilAvc2GetAttribute(vm::ptr<CellSysutilAvc2Attribute> attr)
return CELL_OK;
}

error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> 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<avc2_settings>();

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);
Expand Down Expand Up @@ -686,14 +670,196 @@ error_code cellSysutilAvc2SetSpeakerMuting(u8 muting)
return CELL_OK;
}

error_code cellSysutilAvc2Load_shared(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> 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<avc2_settings>();

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<u32>(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<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> 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<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> 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<avc2_settings>();

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;
}
Expand Down