Files
MinecraftConsoles/Minecraft.Client/PS3/Network/SonyVoiceChat.cpp

765 lines
22 KiB
C++

#include "stdafx.h"
/* SCE CONFIDENTIAL
PlayStation(R)3 Programmer Tool Runtime Library 430.001
* Copyright (C) 2008 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
#include "SonyVoiceChat.h"
#include <arpa/inet.h> /* inet_ntoa() */
/* for displaying extra information */
#ifndef _CONTENT_PACKAGE
#define AVC2_GAME_DEBUG
#endif
#ifdef AVC2_GAME_DEBUG
#define INF(...) printf( "INF:" __VA_ARGS__ )
#define ERR(...) printf( "ERR:" __VA_ARGS__ )
#else
#define INF(...)
#define ERR(...)
#endif
#define UNUSED_VARIABLE(x) (void)(x)
//#define DISABLE_VOICE_CHAT
static CellSysutilAvc2InitParam g_chat_avc2param;
EAVCEvent SonyVoiceChat::sm_event = AVC_EVENT_EPSILON;
EAVCState SonyVoiceChat::sm_state = AVC_STATE_IDLE;
SQRNetworkManager_PS3* SonyVoiceChat::sm_pNetworkManager;
bool SonyVoiceChat::sm_bEnabled = true;
uint8_t SonyVoiceChat::sm_micStatus = CELL_AVC2_MIC_STATUS_UNKNOWN;
bool SonyVoiceChat::sm_bLoaded = false;
bool SonyVoiceChat::sm_bUnloading = false;
unordered_map<SceNpMatching2RoomMemberId, bool> SonyVoiceChat::sm_bTalkingMap;
bool SonyVoiceChat::sm_bCanStart = false;
bool SonyVoiceChat::sm_isChatRestricted = false;
int SonyVoiceChat::sm_currentBitrate = 28000;
void SonyVoiceChat::init( SQRNetworkManager_PS3* pNetMan )
{
if(sm_state != AVC_STATE_IDLE)
return;
sm_pNetworkManager = pNetMan;
setState(AVC_STATE_CHAT_INIT);
ProfileManager.GetChatAndContentRestrictions(0,false,&sm_isChatRestricted,NULL,NULL);
}
void SonyVoiceChat::shutdown()
{
if( sm_state == AVC_STATE_IDLE ||
sm_state == AVC_STATE_CHAT_LEAVE ||
sm_state == AVC_STATE_CHAT_UNLOAD ||
sm_state == AVC_STATE_CHAT_RESET )
{
// we're either shut down already, or in the process
return;
}
setEvent(AVC_EVENT_EXIT_GAME);
}
void SonyVoiceChat::setEnabled( bool bEnabled )
{
if(sm_bEnabled != bEnabled)
{
if(sm_bCanStart)
{
if(bEnabled)
startStream();
else
stopStream();
}
sm_bEnabled = bEnabled;
}
}
int SonyVoiceChat::eventcb_load(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_LOAD_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_LOAD_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_LOAD_SUCCEEDED);
sm_bLoaded = true;
// set the packet contention value here
CellSysutilAvc2Attribute attr;
memset( &attr, 0x00, sizeof(attr) );
attr.attr_id = CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_PACKET_CONTENTION;
attr.attr_param.int_param = 3;
int ret = cellSysutilAvc2SetAttribute(&attr);
if( ret != CELL_OK )
{
app.DebugPrintf("CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_PACKET_CONTENTION failed !!! 0x%08x\n", ret);
}
}
else /* if( event_id == CELL_AVC2_EVENT_LOAD_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_LOAD_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_LOAD_FAILED);
}
return ret;
}
int SonyVoiceChat::eventcb_join(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_JOIN_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_JOIN_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_JOIN_SUCCEEDED);
}
else /* if( event_id == CELL_AVC2_EVENT_JOIN_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_JOIN_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_ERROR);
}
sm_bTalkingMap.clear();
return ret;
}
int SonyVoiceChat::eventcb_leave( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_LEAVE_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_LEAVE_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setState(AVC_STATE_CHAT_LEAVE);
setEvent(AVC_EVENT_CHAT_LEAVE_SUCCEEDED);
}
else /* if( event_id == CELL_AVC2_EVENT_LEAVE_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_LEAVE_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setState(AVC_STATE_CHAT_LEAVE);
setEvent(AVC_EVENT_ERROR);
}
return ret;
}
int SonyVoiceChat::eventcb_unload(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
int ret = CELL_OK;
UNUSED_VARIABLE( event_param );
UNUSED_VARIABLE( userdata );
if( event_id == CELL_AVC2_EVENT_UNLOAD_SUCCEEDED )
{
INF( "<AVC CB>CELL_AVC2_EVENT_UNLOAD_SUCCEEDED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_CHAT_UNLOAD_SUCCEEDED);
sm_bLoaded = false;
sm_bUnloading = false;
}
else /* if( event_id == CELL_AVC2_EVENT_UNLOAD_FAILED ) */
{
INF( "<AVC CB>CELL_AVC2_EVENT_UNLOAD_FAILED(0x%x), param(0x%x)\n", event_id, (int)event_param );
setEvent(AVC_EVENT_ERROR);
}
return ret;
}
int SonyVoiceChat::eventcb_voiceDetected(CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
UNUSED_VARIABLE( userdata );
// To the upper 32 bits, the room member ID of the player is passed.
// In the lower 32 bits, a value of 0 (mute) or a value between 1 (low volume)
// and 10 (high volume) is passed as the audio signal value when the notification
// method is the level method, or a value of 1 (start of speaking) or 0 (end of speaking)
// is stored when the notification method is the trigger method.
SceNpMatching2RoomMemberId roomMemberID = (SceNpMatching2RoomMemberId)(event_param >> 32);
uint32_t volume = (uint32_t)(event_param & 0xffffffff);
// The precision of voice detection is not very high. Since the audio signal values may
// always be relatively high depending on the audio input device and the noise level in the
// room, you should set a large reference value for determining whether or not a player is
// speaking. Relatively good results can be obtained when an audio signal value of at
// least 9 is used to determine if a player is speaking.
bool bTalking = false;
if(volume >= 9)
bTalking = true;
sm_bTalkingMap[roomMemberID] = bTalking;
return CELL_OK;
}
/* Callback function for handling AV Chat2 Utility events */
void SonyVoiceChat::eventcb( CellSysutilAvc2EventId event_id, CellSysutilAvc2EventParam event_param, void *userdata)
{
static struct _cb_func_tbl
{
CellSysutilAvc2EventId event;
int (*func)( CellSysutilAvc2EventId event_id,
CellSysutilAvc2EventParam event_param,
void *userdata );
} event_tbl[] =
{
{ CELL_AVC2_EVENT_LOAD_SUCCEEDED, eventcb_load },
{ CELL_AVC2_EVENT_LOAD_FAILED, eventcb_load },
{ CELL_AVC2_EVENT_JOIN_SUCCEEDED, eventcb_join },
{ CELL_AVC2_EVENT_JOIN_FAILED, eventcb_join },
{ CELL_AVC2_EVENT_LEAVE_SUCCEEDED, eventcb_leave },
{ CELL_AVC2_EVENT_LEAVE_FAILED, eventcb_leave },
{ CELL_AVC2_EVENT_UNLOAD_SUCCEEDED, eventcb_unload },
{ CELL_AVC2_EVENT_UNLOAD_FAILED, eventcb_unload },
{ CELL_AVC2_EVENT_SYSTEM_NEW_MEMBER_JOINED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_MEMBER_LEFT, NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_ESTABLISHED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_CANNOT_ESTABLISHED,NULL },
{ CELL_AVC2_EVENT_SYSTEM_SESSION_DISCONNECTED, NULL },
{ CELL_AVC2_EVENT_SYSTEM_VOICE_DETECTED, eventcb_voiceDetected },
};
int ret = 0;
for( unsigned int i=0; i<sizeof(event_tbl)/sizeof(struct _cb_func_tbl) ; ++i )
{
if( event_tbl[ i ].event == event_id && event_tbl[ i ].func )
{
ret = (*event_tbl[ i ].func)( event_id, event_param, userdata );
if( ret < 0 )
{
ERR("ret=0x%x\n", ret );
}
break;
}
}
}
int SonyVoiceChat::load()
{
int ret = CELL_OK;
INF("----------------------------\n");
INF("| cellSysutilAvc2LoadAsync |\n");
INF("----------------------------\n");
ret = cellSysutilAvc2LoadAsync( sm_pNetworkManager->m_matchingContext,
SYS_MEMORY_CONTAINER_ID_INVALID,
eventcb,
NULL,
&g_chat_avc2param );
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2LoadAsync: ret=0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::join()
{
int ret = CELL_OK;
INF("---------------------------------------------------\n");
INF("| cellSysutilAvc2JoinChatRequest \n");
INF("---------------------------------------------------\n");
ret = cellSysutilAvc2JoinChatRequest( &sm_pNetworkManager->m_room );
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2JoinChatRequest: ret=0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::leave()
{
int ret = CELL_OK;
INF("-----------------------------------\n");
INF("| cellSysutilAvc2LeaveChatRequest |\n");
INF("-----------------------------------\n");
ret = cellSysutilAvc2LeaveChatRequest();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2LeaveChatRequest() = 0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
return ret;
}
int SonyVoiceChat::unload()
{
int ret = CELL_OK;
INF("------------------------------\n");
INF("| cellSysutilAvc2UnloadAsync |\n");
INF("------------------------------\n");
ret = cellSysutilAvc2UnloadAsync();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvcUnloadAsync() = 0x%x\n", ret );
setEvent(AVC_EVENT_ERROR);
return ret;
}
sm_bUnloading = true;
return ret;
}
int SonyVoiceChat::start()
{
sm_bCanStart = (sm_isChatRestricted == false);
int ret = CELL_OK;
if(sm_bEnabled)
ret = startStream();
return ret;
}
int SonyVoiceChat::stop()
{
sm_bCanStart = false;
int ret = CELL_OK;
if(sm_bEnabled)
ret = stopStream();
setEvent(AVC_EVENT_CHAT_SESSION_STOPPED);
return ret;
}
int SonyVoiceChat::startStream()
{
int ret = CELL_OK;
INF("---------------------------------\n");
INF("| cellSysutilAvc2StartStreaming |\n");
INF("---------------------------------\n");
ret = cellSysutilAvc2StartStreaming();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StartStreaming: ret=0x%x\n", ret );
}
ret = cellSysutilAvc2StartVoiceDetection();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StartVoiceDetection: ret=0x%x\n", ret );
}
return ret;
}
int SonyVoiceChat::stopStream()
{
int ret = cellSysutilAvc2StopVoiceDetection();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StopVoiceDetection: ret=0x%x\n", ret );
}
INF("--------------------------------\n");
INF("| cellSysutilAvc2StopStreaming |\n");
INF("--------------------------------\n");
ret = cellSysutilAvc2StopStreaming();
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2StopStreaming: ret=0x%x\n", ret );
}
return ret;
}
int SonyVoiceChat::initialize(void)
{
int ret;
/* Must use cellSysutilAvc2InitParam() for clearing CellSysutilAvc2InitParam struct*/
ret = cellSysutilAvc2InitParam(CELL_SYSUTIL_AVC2_INIT_PARAM_VERSION, &g_chat_avc2param);
if( ret != CELL_OK )
{
ERR( "cellSysutilAvc2InitParam failed (0x%x)\n", ret );
return ret;
}
/* Setting application specific parameters */
g_chat_avc2param.media_type = CELL_SYSUTIL_AVC2_VOICE_CHAT;
g_chat_avc2param.max_players = AVC2_PARAM_DEFAULT_MAX_PLAYERS;
g_chat_avc2param.voice_param.voice_quality = CELL_SYSUTIL_AVC2_VOICE_QUALITY_NORMAL;
g_chat_avc2param.voice_param.max_speakers = AVC2_PARAM_DEFAULT_MAX_SPEAKERS;
g_chat_avc2param.spu_load_average = 50;
g_chat_avc2param.streaming_mode.mode = CELL_SYSUTIL_AVC2_STREAMING_MODE_NORMAL;
setEvent(AVC_EVENT_CHAT_INIT_SUCCEEDED);
setState(AVC_STATE_CHAT_INIT);
return ret;
}
int SonyVoiceChat::finalize(void)
{
setEvent(AVC_EVENT_CHAT_FINALIZE_SUCCEEDED);
return CELL_OK;
}
void SonyVoiceChat::tick()
{
#ifdef DISABLE_VOICE_CHAT
return;
#endif
static state_transition_table tbl[] =
{
/* now state event func after the transition state */
{ AVC_STATE_CHAT_INIT, AVC_EVENT_EPSILON, initialize, AVC_STATE_CHAT_INIT },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_CHAT_INIT_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_LOAD },
{ AVC_STATE_CHAT_INIT, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_EPSILON, load, AVC_STATE_CHAT_LOAD },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_CHAT_LOAD_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_JOIN },
{ AVC_STATE_CHAT_LOAD, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_EPSILON, join, AVC_STATE_CHAT_JOIN },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_EXIT_GAME, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_LAN_DISCONNECT, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_CHAT_JOIN_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_JOIN, AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_EPSILON, start, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_EXIT_GAME, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_ERROR, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_LAN_DISCONNECT, stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_CHAT_SESSION_STOPPED, invoke_epsilon_event, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_SESSION_PROCESSING,AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT,stop, AVC_STATE_CHAT_SESSION_PROCESSING },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_EPSILON, leave, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_LEAVE, AVC_EVENT_CHAT_LEAVE_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_EPSILON, unload, AVC_STATE_CHAT_UNLOAD },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_UNLOAD, AVC_EVENT_CHAT_UNLOAD_SUCCEEDED, invoke_epsilon_event, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_EPSILON, finalize, AVC_STATE_CHAT_RESET },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_ERROR, invoke_epsilon_event, AVC_STATE_CHAT_LEAVE },
{ AVC_STATE_CHAT_RESET, AVC_EVENT_CHAT_FINALIZE_SUCCEEDED, invoke_epsilon_event, AVC_STATE_IDLE },
};
do_state_transition( &tbl[0], sizeof( tbl ) / sizeof( state_transition_table ) );
setBitRate();
}
void SonyVoiceChat::do_state_transition( state_transition_table *tbl, int tbl_size )
{
int ret = CELL_OK;
// if( sm_event == AVC_EVENT_LAN_DISCONNECT ||
// sm_event == AVC_EVENT_EXIT_GAME ||
// sm_event == AVC_EVENT_ERROR ||
// sm_event == AVC_EVENT_FATAL_ERROR )
// {
// g_gamedata.finalize = 1;
// }
// if( sm_event == AVC_EVENT_FATAL_ERROR )
// {
// g_gamedata.exit = true;
// }
bool bCalledFunc = false;
for( int i = 0; i < tbl_size; i++ )
{
if( sm_state == ( tbl + i )->state )
{
if( sm_event == ( tbl + i )->event )
{
sm_event = AVC_EVENT_NON;
ret = (*( tbl + i )->func)();
bCalledFunc = true;
if( ret != CELL_OK )
{
ERR("ret = 0x%x\n", ret );
}
setState(( tbl + i )->new_state);
break;
}
}
}
if(bCalledFunc == false)
{
assert( (sm_event == AVC_EVENT_NON) ||
(sm_state == AVC_STATE_IDLE && sm_event == AVC_EVENT_EPSILON) );
}
}
int SonyVoiceChat::invoke_epsilon_event(void)
{
setEvent(AVC_EVENT_EPSILON);
return CELL_OK;
}
bool SonyVoiceChat::hasMicConnected(const SceNpMatching2RoomMemberId *players_id)
{
CellSysutilAvc2PlayerInfo players_info;
int err = cellSysutilAvc2GetPlayerInfo(players_id, &players_info);
if(err == CELL_OK)
{
if(players_info.connected && players_info.joined)
{
if(players_info.mic_attached == CELL_AVC2_MIC_STATUS_ATTACHED_ON)
return true;
}
}
return false;
}
void SonyVoiceChat::mute( bool bMute )
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetVoiceMuting(bMute);
assert(err == CELL_OK);
}
}
void SonyVoiceChat::mutePlayer( const SceNpMatching2RoomMemberId member_id, bool bMute ) /*Turn chat audio from a specified player on or off */
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetPlayerVoiceMuting(member_id, bMute);
assert(err == CELL_OK);
}
}
void SonyVoiceChat::muteLocalPlayer( bool bMute ) /*Turn microphone input on or off */
{
if(sm_bLoaded && !sm_bUnloading)
{
int err = cellSysutilAvc2SetVoiceMuting(bMute);
assert(err == CELL_OK);
}
}
bool SonyVoiceChat::isMuted()
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetVoiceMuting(&bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
bool SonyVoiceChat::isMutedPlayer( const SceNpMatching2RoomMemberId member_id)
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetPlayerVoiceMuting(member_id, &bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
bool SonyVoiceChat::isMutedLocalPlayer()
{
if(sm_bLoaded && !sm_bUnloading)
{
uint8_t bMute;
int err = cellSysutilAvc2GetVoiceMuting(&bMute);
assert(err == CELL_OK);
return bMute;
}
return false;
}
void SonyVoiceChat::setVolume( float vol )
{
if(sm_bLoaded && !sm_bUnloading)
{
// The volume level can be set to a value in the range 0.0 to 40.0.
// Volume levels are linear values such that if 1.0 is specified, the
// volume level will be 1 times the reference power (0dB), and if 0.5
// is specified, the volume level will be 0.5 times the reference power
// (-6dB). If 0.0 is specified, chat audio will no longer be audible.
int err =cellSysutilAvc2SetSpeakerVolumeLevel(vol * 40.0f);
assert(err==CELL_OK);
}
}
float SonyVoiceChat::getVolume()
{
if(sm_bLoaded && !sm_bUnloading)
{
float vol;
int err = cellSysutilAvc2GetSpeakerVolumeLevel(&vol);
assert(err == CELL_OK);
return (vol / 40.0f);
}
return 0;
}
bool SonyVoiceChat::isTalking( SceNpMatching2RoomMemberId* players_id )
{
auto it = sm_bTalkingMap.find(*players_id);
if (it != sm_bTalkingMap.end() )
return it->second;
return false;
}
void SonyVoiceChat::setBitRate()
{
if(sm_state != AVC_STATE_CHAT_SESSION_PROCESSING)
return;
int numPlayers = sm_pNetworkManager->GetPlayerCount();
// This internal attribute represents the maximum voice bit rate. attr_param
// is an integer value. The units are bps, and the specifiable values are
// 4000, 8000, 16000, 20000, 24000, and 28000. The initial value is 28000.
static int bitRates[8] = { 28000, 28000,
28000, 28000,
24000, 20000,
16000, 16000};
int bitRate = bitRates[numPlayers-1];
if(bitRate == sm_currentBitrate)
return;
CellSysutilAvc2Attribute attr;
memset( &attr, 0x00, sizeof(attr) );
attr.attr_id = CELL_SYSUTIL_AVC2_ATTRIBUTE_VOICE_MAX_BITRATE;
attr.attr_param.int_param = bitRate;
int ret = cellSysutilAvc2SetAttribute(&attr);
if( ret == CELL_OK )
{
sm_currentBitrate = bitRate;
}
else
{
app.DebugPrintf("SonyVoiceChat::setBitRate failed !!! 0x%08x\n", ret);
}
}
#define CASE_STR_VALUE(s) case s: return #s;
const char* getStateString(EAVCState state)
{
switch(state)
{
CASE_STR_VALUE(AVC_STATE_IDLE);
CASE_STR_VALUE(AVC_STATE_CHAT_INIT)
CASE_STR_VALUE(AVC_STATE_CHAT_LOAD);
CASE_STR_VALUE(AVC_STATE_CHAT_JOIN);
CASE_STR_VALUE(AVC_STATE_CHAT_SESSION_PROCESSING);
CASE_STR_VALUE(AVC_STATE_CHAT_LEAVE);
CASE_STR_VALUE(AVC_STATE_CHAT_RESET);
CASE_STR_VALUE(AVC_STATE_CHAT_UNLOAD);
CASE_STR_VALUE(AVC_STATE_EXIT);
default:
return "unknown state";
}
}
const char* getEventString(EAVCEvent state)
{
switch(state)
{
CASE_STR_VALUE(AVC_EVENT_NON);
CASE_STR_VALUE(AVC_EVENT_EPSILON);
CASE_STR_VALUE(AVC_EVENT_LAN_DISCONNECT);
CASE_STR_VALUE(AVC_EVENT_ONLINE);
CASE_STR_VALUE(AVC_EVENT_OFFLINE);
CASE_STR_VALUE(AVC_EVENT_EXIT_GAME);
CASE_STR_VALUE(AVC_EVENT_ROOM_CREATE);
CASE_STR_VALUE(AVC_EVENT_ROOM_SEARCH);
CASE_STR_VALUE(AVC_EVENT_ERROR);
CASE_STR_VALUE(AVC_EVENT_FATAL_ERROR);
CASE_STR_VALUE(AVC_EVENT_NETDIALOG_FINISHED);
CASE_STR_VALUE(AVC_EVENT_NETDIALOG_UNLOADED);
CASE_STR_VALUE(AVC_EVENT_NP2_INIT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_FINALIZE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_START_CONTEXT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_STOP_CONTEXT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_DESTROY_OR_KICKEDOUT);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_MEMBER_LEFT);
CASE_STR_VALUE(AVC_EVENT_NP2_ROOM_MEMBER_JOINED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LOAD_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LOAD_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_JOIN_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_JOIN_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LEAVE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_LEAVE_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_UNLOAD_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_UNLOAD_FAILED);
CASE_STR_VALUE(AVC_EVENT_CHAT_INIT_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_FINALIZE_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_CHAT_SESSION_STOPPED);
CASE_STR_VALUE(AVC_EVENT_CREATE_JOIN_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_SEARCH_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_JOIN_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_LEAVE_ROOM_SUCCEEDED);
CASE_STR_VALUE(AVC_EVENT_SIGNALING_ESTABLISHED);
CASE_STR_VALUE(AVC_EVENT_SIGNALING_DEAD);
CASE_STR_VALUE(AVC_EVENT_UI_CLOSE_SUCCEEDED);
default:
return "unknown event";
}
}
void SonyVoiceChat::printStateAndEvent()
{
app.DebugPrintf("============== State %20s, Event %20s\n", getStateString(sm_state), getEventString(sm_event));
}
void SonyVoiceChat::setEvent( EAVCEvent event )
{
sm_event = event;
printStateAndEvent();
}
void SonyVoiceChat::setState( EAVCState state )
{
sm_state = state;
printStateAndEvent();
}