From b691c43c44ff180d10e7d4a9afc83b98551ff586 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sun, 1 Mar 2026 12:16:08 +0800 Subject: Initial commit --- .../Orbis/Network/SonyVoiceChat_Orbis.cpp | 1105 ++++++++++++++++++++ 1 file changed, 1105 insertions(+) create mode 100644 Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp (limited to 'Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp') diff --git a/Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp b/Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp new file mode 100644 index 00000000..d869d38b --- /dev/null +++ b/Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp @@ -0,0 +1,1105 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include + +#include "SonyVoiceChat_Orbis.h" + +std::vector SonyVoiceChat_Orbis::m_remoteConnections; +bool SonyVoiceChat_Orbis::m_bVoiceStarted = false; +int SonyVoiceChat_Orbis::m_numLocalDevicesConnected = 0; +SQRLocalVoiceDevice SonyVoiceChat_Orbis::m_localVoiceDevices[MAX_LOCAL_PLAYER_COUNT]; +uint32_t SonyVoiceChat_Orbis::m_voiceOutPort; +bool SonyVoiceChat_Orbis::m_forceSendPacket = false; // force a packet across the network, even if there's no data, so we can update flags +RingBuffer SonyVoiceChat_Orbis::m_recordRingBuffer(sc_ringBufferSize); +VoicePacket::Flags SonyVoiceChat_Orbis::m_localPlayerFlags[MAX_LOCAL_PLAYER_COUNT]; +bool SonyVoiceChat_Orbis::m_bInitialised = false; +CRITICAL_SECTION SonyVoiceChat_Orbis::m_csRemoteConnections; + +// sample related variables +SceVoiceStartParam startParam; +int32_t playSize = 0; + +static const int sc_thresholdValue = 100; + +static const bool sc_verbose = false; + +// #define _USE_PCM_AUDIO_ +//#define USE_PCM_MIC_DATA + + + +int g_loadedPCMVoiceDataSizes[4]; +int g_loadedPCMVoiceDataPos[4]; +char* g_loadedPCMVoiceData[4]; + +static void CreatePort(uint32_t *portId, const SceVoicePortParam *pArg) +{ + C4JThread::PushAffinityAllCores(); // PS4 only + + int err = sceVoiceCreatePort( portId, pArg ); + assert(err == SCE_OK); + assert(*portId != SCE_VOICE_INVALID_PORT_ID); + C4JThread::PopAffinity(); // PS4 only +} + +static void DeletePort(uint32_t& port) +{ + int32_t result; + if (port != SCE_VOICE_INVALID_PORT_ID) + { + result = sceVoiceDeletePort( port ); + if (result != SCE_OK) + { + app.DebugPrintf("sceVoiceDeletePort failed %0x\n", result); + assert(0); + } + port = SCE_VOICE_INVALID_PORT_ID; + } +} + + +void LoadPCMVoiceData() +{ + for(int i=0;i<4;i++) + { + char filename[64]; + sprintf(filename, "voice%d.pcm", i+1); + HANDLE file = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD dwHigh=0; + g_loadedPCMVoiceDataSizes[i] = GetFileSize(file,&dwHigh); + + if(g_loadedPCMVoiceDataSizes[i]!=0) + { + g_loadedPCMVoiceData[i] = new char[g_loadedPCMVoiceDataSizes[i]]; + DWORD bytesRead; + BOOL bSuccess = ReadFile(file, g_loadedPCMVoiceData[i], g_loadedPCMVoiceDataSizes[i], &bytesRead, NULL); + assert(bSuccess); + } + g_loadedPCMVoiceDataPos[i] = 0; + } +} + + +void SonyVoiceChat_Orbis::init() +{ + int returnCode = SCE_OK; + SceUserServiceUserId initialUserId; + + if (returnCode < 0) + { + app.DebugPrintf("Error: sceSysmoduleLoadModule(SCE_SYSMODULE_VOICE), ret 0x%08x\n", returnCode); + assert(0); + } + + + SceVoiceInitParam params; + SceVoicePortParam portArgs; + memset( ¶ms, 0, sizeof(params) ); + params.appType = SCE_VOICE_APPTYPE_GAME; + params.onEvent = 0; + returnCode = sceVoiceInit( ¶ms , SCE_VOICE_VERSION_100); + if (returnCode < 0) + { + app.DebugPrintf("Error: sceVoiceInit(), ret 0x%08x\n", returnCode); + assert(0); + } + +#ifdef _USE_PCM_AUDIO_ + portArgs.portType = SCE_VOICE_PORTTYPE_OUT_PCMAUDIO; + portArgs.bMute = false; + portArgs.threshold = 0; + portArgs.volume = 1.0f; + portArgs.pcmaudio.format.dataType = SCE_VOICE_PCM_SHORT_LITTLE_ENDIAN; + portArgs.pcmaudio.format.sampleRate = SCE_VOICE_SAMPLINGRATE_16000; + portArgs.pcmaudio.bufSize = 4096; +#else + portArgs.portType = SCE_VOICE_PORTTYPE_OUT_VOICE; + portArgs.bMute = false; + portArgs.threshold = 0; + portArgs.volume = 1.0f; + portArgs.voice.bitrate = VOICE_ENCODED_FORMAT; +#endif + CreatePort( &m_voiceOutPort, &portArgs ); + + start(); + m_bInitialised = true; + InitializeCriticalSection(&m_csRemoteConnections); +} + + +void SonyVoiceChat_Orbis::start() +{ + if( m_bVoiceStarted == false) + { + startParam.container = malloc(SCE_VOICE_MEMORY_CONTAINER_SIZE); + startParam.memSize = SCE_VOICE_MEMORY_CONTAINER_SIZE; + + int err; + + C4JThread::PushAffinityAllCores(); // PS4 only + err = sceVoiceStart(&startParam); + assert(err == SCE_OK); + C4JThread::PopAffinity(); // PS4 only + + m_bVoiceStarted = true; + } +} + +void SonyVoiceChat_Orbis::checkFinished() +{ + EnterCriticalSection(&m_csRemoteConnections); + + for(int i=0;im_bFlaggedForShutdown); + } +// assert(m_numLocalDevicesConnected == 0); + + LeaveCriticalSection(&m_csRemoteConnections); +} + + +void SonyVoiceChat_Orbis::shutdown() +{ + m_bInitialised = false; + int32_t result; + result = sceVoiceStop(); + assert(result == SCE_OK); + result = sceVoiceEnd(); + assert(result == SCE_OK); + free(startParam.container); + + int returnCode = sceSysmoduleUnloadModule(SCE_SYSMODULE_VOICE); + if (returnCode < 0) + { + app.DebugPrintf("Error: sceSysmoduleUnloadModule(SCE_SYSMODULE_VOICE), ret 0x%08x\n", returnCode); + assert(0); + } +} + +void SonyVoiceChat_Orbis::setEnabled( bool bEnabled ) +{ +} + + + +// Internal send function. This attempts to send as many elements in the queue as possible until the write function tells us that we can't send any more. This way, +// we are guaranteed that if there *is* anything more in the queue left to send, we'll get a CELL_RUDP_CONTEXT_EVENT_WRITABLE event when whatever we've managed to +// send here is complete, and can continue on. +void SQRVoiceConnection::SendMoreInternal() +{ + EnterCriticalSection(&m_csQueue); + bool keepSending; + do + { + keepSending = false; + if( m_sendQueue.size() > 0) + { + // Attempt to send the full data in the first element in our queue + unsigned char *data= m_sendQueue.front().current; + int dataSize = m_sendQueue.front().end - m_sendQueue.front().current; + int ret = sceRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL ); + int wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK; + + if( ret == dataSize ) + { + // Fully sent, remove from queue - will loop in the while loop to see if there's anything else in the queue we could send + delete [] m_sendQueue.front().start; + m_sendQueue.pop(); + if( m_sendQueue.size() ) + { + keepSending = true; + } + } + else if( ( ret >= 0 ) || ( ret == wouldBlockFlag ) ) + { + + + // Things left to send - adjust this element in the queue + int remainingBytes; + if( ret >= 0 ) + { + // Only ret bytes sent so far + remainingBytes = dataSize - ret; + assert(remainingBytes > 0 ); + } + else + { + // Is CELL_RUDP_ERROR_WOULDBLOCK, nothing has yet been sent + remainingBytes = dataSize; + } + m_sendQueue.front().current = m_sendQueue.front().end - remainingBytes; + } + } + } while (keepSending); + LeaveCriticalSection(&m_csQueue); +} + +void SQRVoiceConnection::SendInternal(const void *data, unsigned int dataSize) +{ + EnterCriticalSection(&m_csQueue); + + QueuedSendBlock sendBlock; + + unsigned char *dataCurrent = (unsigned char *)data; + unsigned int dataRemaining = dataSize; + + while( dataRemaining ) + { + int dataSize = dataRemaining; + if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD; + sendBlock.start = new unsigned char [dataSize]; + sendBlock.end = sendBlock.start + dataSize; + sendBlock.current = sendBlock.start; + memcpy( sendBlock.start, dataCurrent, dataSize); + m_sendQueue.push(sendBlock); + dataRemaining -= dataSize; + dataCurrent += dataSize; + } + +// app.DebugPrintf("voice sent %d bytes\n", dataSize); + + // Now try and send as much as we can + SendMoreInternal(); + + LeaveCriticalSection(&m_csQueue); +} + +void SQRVoiceConnection::readRemoteData() +{ + unsigned int dataSize = sceRudpGetSizeReadable(m_rudpCtx); + if( dataSize > 0 ) + { + VoicePacket packet; + int bytesRead = sceRudpRead( m_rudpCtx, &packet, dataSize, 0, NULL ); + unsigned int writeSize; + if( bytesRead > 0 ) + { +// app.DebugPrintf("voice received %d bytes\n", bytesRead); + writeSize = bytesRead; + packet.verifyData(bytesRead, 19); + addPacket(packet); +// m_playRingBuffer.Write((char*)data, writeSize); + + } + } + +} + + + +SQRVoiceConnection::SQRVoiceConnection( int rudpCtx, SceNpMatching2RoomMemberId remoteRoomMemberId ) + : m_rudpCtx(rudpCtx) + , m_remoteRoomMemberId(remoteRoomMemberId) + , m_bConnected(false) + , m_headsetConnectionMask(0) + , m_playRingBuffer(sc_ringBufferSize) +{ + InitializeCriticalSection(&m_csQueue); + InitializeCriticalSection(&m_csPacketQueue); + + SceVoiceInitParam params; + SceVoicePortParam portArgs; +#ifdef _USE_PCM_AUDIO_ + portArgs.portType = SCE_VOICE_PORTTYPE_IN_PCMAUDIO; + portArgs.bMute = false; + portArgs.threshold = 100; + portArgs.volume = 1.0f; + portArgs.pcmaudio.format.sampleRate= SCE_VOICE_SAMPLINGRATE_16000; + portArgs.pcmaudio.format.dataType = SCE_VOICE_PCM_SHORT_LITTLE_ENDIAN; + portArgs.pcmaudio.bufSize = 4096; +#else + portArgs.portType = SCE_VOICE_PORTTYPE_IN_VOICE; + portArgs.bMute = false; + portArgs.threshold = sc_thresholdValue; // compensate network jitter + portArgs.volume = 1.0f; + portArgs.voice.bitrate = VOICE_ENCODED_FORMAT; +#endif + CreatePort( &m_voiceInPort, &portArgs ); + m_nextExpectedFrameIndex = 0; + m_bFlaggedForShutdown = false; +} + +SQRVoiceConnection::~SQRVoiceConnection() +{ + DeleteCriticalSection(&m_csQueue); + DeleteCriticalSection(&m_csPacketQueue); + extern int g_numRUDPContextsBound; + int err = sceRudpTerminate( m_rudpCtx ); + app.DebugPrintf(sc_verbose, "-----------------::::::::::::: sceRudpTerminate\n" ); + + app.DebugPrintf("-----------------------------\n"); + if(err<0) + app.DebugPrintf("Voice rudp context failed to delete!!! %d\n", m_rudpCtx); + else + { + g_numRUDPContextsBound--; + app.DebugPrintf("Voice rudp context deleted %d\n", m_rudpCtx); + } + app.DebugPrintf("-----------------------------\n"); + + DeletePort(m_voiceInPort); + +} + +bool SQRVoiceConnection::getNextPacket( VoicePacket& packet ) +{ + EnterCriticalSection(&m_csPacketQueue); + bool retVal = false; + if(m_receivedVoicePackets.size() > 0) + { + retVal = true; + packet = m_receivedVoicePackets.front(); + m_receivedVoicePackets.pop(); + } + LeaveCriticalSection(&m_csPacketQueue); + return retVal; +} + +void SQRVoiceConnection::addPacket( VoicePacket& packet ) +{ + EnterCriticalSection(&m_csPacketQueue); + m_receivedVoicePackets.push(packet); + LeaveCriticalSection(&m_csPacketQueue); +} + +int g_frameNum = 0; +bool g_bRecording = false; + + +uint32_t frameSendIndex = 0; +uint32_t lastReadFrameCnt = 0; + + +void PrintAllOutputVoiceStates( std::vector& connections) +{ + for(int rIdx=0;rIdxm_voiceInPort, &portInfo ); + static SceVoicePortState lastPortState = SCE_VOICE_PORTSTATE_IDLE; + if(portInfo.state != lastPortState) + { + lastPortState = portInfo.state; + switch(portInfo.state) + { + case SCE_VOICE_PORTSTATE_IDLE: + app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_IDLE\n"); + break; + case SCE_VOICE_PORTSTATE_BUFFERING: + app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_BUFFERING\n"); + break; + case SCE_VOICE_PORTSTATE_RUNNING: + app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_RUNNING\n"); + break; + case SCE_VOICE_PORTSTATE_READY: + app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_READY\n"); + break; + case SCE_VOICE_PORTSTATE_NULL: + default: + app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_NULL\n"); + break; + } + } + } + +} + + +void SonyVoiceChat_Orbis::sendPCMMicData() +{ + int32_t result; + uint32_t outputPortBytes; + VoicePacket packetToSend; + uint32_t readSize; + SceVoiceBasePortInfo portInfo; + memset( &portInfo, 0, sizeof(portInfo) ); + uint16_t frameGap = 0; + + DWORD tick = GetTickCount(); + static DWORD lastTick = 0; + int numFrames = ceilf((tick - lastTick)/16.0f); + lastTick = tick; + readSize = 512 * numFrames; + + if(g_loadedPCMVoiceDataPos[0] + readSize < g_loadedPCMVoiceDataSizes[0]) + { + for(int i=0;i (g_loadedPCMVoiceDataSizes[0] + 8192)) + g_loadedPCMVoiceDataPos[0] = 0; + + +} + +void SonyVoiceChat_Orbis::sendAllVoiceData() +{ + int32_t result; + uint32_t outputPortBytes; + VoicePacket packetToSend; + uint32_t readSize; + SceVoiceBasePortInfo portInfo; + memset( &portInfo, 0, sizeof(portInfo) ); + uint16_t frameGap = 0; + + VoicePacket::Flags lastPlayerFlags[MAX_LOCAL_PLAYER_COUNT]; + + for(int i=0; isizeof(packetToSend.m_data))?sizeof(packetToSend.m_data):outputPortBytes; + if( outputPortBytes || flagsChanged || m_forceSendPacket) + { + frameSendIndex += lastReadFrameCnt; + if(outputPortBytes) + { + readSize = outputPortBytes; + result = sceVoiceReadFromOPort(m_voiceOutPort, packetToSend.m_data, &readSize ); + if (result != SCE_OK) + { + app.DebugPrintf("sceVoiceReadFromOPort failed %0x\n", result); + assert(0); + return; + } + lastReadFrameCnt = readSize/portInfo.frameSize; + assert(readSize%portInfo.frameSize == 0); + + packetToSend.m_numFrames = lastReadFrameCnt; + packetToSend.m_frameSendIndex = frameSendIndex; + packetToSend.setChecksum(readSize); + } + else + { + readSize = 0; + packetToSend.m_numFrames = 0; + packetToSend.m_frameSendIndex = frameSendIndex; + packetToSend.setChecksum(readSize); + + } + + + int packetSize = packetToSend.getPacketSize(readSize); + + EnterCriticalSection(&m_csRemoteConnections); + + // send this packet out to all our remote connections + for(int rIdx=0;rIdxm_bConnected) + m_remoteConnections[rIdx]->SendInternal(&packetToSend, packetSize); + } + + LeaveCriticalSection(&m_csRemoteConnections); + } + m_forceSendPacket = false; +} + +bool g_bPlaying = false; + +void SonyVoiceChat_Orbis::playAllReceivedData() +{ + EnterCriticalSection(&m_csRemoteConnections); + // write all the incoming data from the network to each of the input voices + for(int rIdx=0;rIdxgetNextPacket(packet)) // MGH - changed to a while loop, so all the packets are sent to the voice port, and it can handle delayed packets due to the size of it's internal buffer + { + int frameGap; + if (pVoice->m_nextExpectedFrameIndex == packet.m_frameSendIndex) + { + // no voice frame drop, continuous frames + frameGap = 0; + app.DebugPrintf(sc_verbose, "index@%d gets expected frame\n",pVoice->m_nextExpectedFrameIndex); + pVoice->m_nextExpectedFrameIndex = packet.m_frameSendIndex + packet.m_numFrames; + } + else if (pVoice->m_nextExpectedFrameIndex < packet.m_frameSendIndex) + { + // has voice frame drop, dropped forwarding frames + frameGap = packet.m_frameSendIndex - pVoice->m_nextExpectedFrameIndex; + app.DebugPrintf(sc_verbose, "index@%d gets dropped forwarding frames %d\n",pVoice->m_nextExpectedFrameIndex, frameGap); + pVoice->m_nextExpectedFrameIndex = packet.m_frameSendIndex + packet.m_numFrames; + } + else if (pVoice->m_nextExpectedFrameIndex > packet.m_frameSendIndex) + { + // has voice frame drop, dropped preceding frames, no reset on pVoice->m_nextExpectedFrameIndex + frameGap = packet.m_frameSendIndex - pVoice->m_nextExpectedFrameIndex; + app.DebugPrintf(sc_verbose, "index@%d gets dropped forwarding frames %d\n", pVoice->m_nextExpectedFrameIndex, frameGap); + } + + SceVoiceBasePortInfo portInfo; + int result = sceVoiceGetPortInfo(pVoice->m_voiceInPort, &portInfo ); + if (result != SCE_OK) + { + app.DebugPrintf(sc_verbose, "sceVoiceGetPortInfo LoopbackVoiceInPort failed %x\n", result); + assert(0); + LeaveCriticalSection(&m_csRemoteConnections); + return; + } + uint32_t writeSize = packet.m_numFrames * portInfo.frameSize; + int inputPortBytes = portInfo.numByte; + inputPortBytes = (inputPortBytes>writeSize)?writeSize:inputPortBytes; + writeSize = inputPortBytes; + result = sceVoiceWriteToIPort(pVoice->m_voiceInPort, packet.m_data, &writeSize, frameGap); + if (result != SCE_OK) + { + app.DebugPrintf(sc_verbose, "sceVoiceWriteToIPort failed %0x\n", result); + assert(0); + LeaveCriticalSection(&m_csRemoteConnections); + return; + } + if (writeSize != inputPortBytes) + { + // libvoice internal voice in port buffer fulls + app.DebugPrintf(sc_verbose, "internal voice in port buffer fulls. \n"); + } + packet.m_numFrames = 0; + + // copy the flags + for(int flagIndex=0;flagIndexm_remotePlayerFlags[flagIndex] = packet.m_localPlayerFlags[flagIndex]; + } + } + LeaveCriticalSection(&m_csRemoteConnections); + +} + +void SonyVoiceChat_Orbis::tick() +{ + if(m_bInitialised) + { +// DWORD tick = GetTickCount(); +// static DWORD lastTick = 0; +// app.DebugPrintf("Time since last voice tick : %d ms\n", tick - lastTick); +// lastTick = tick; + g_frameNum++; +#ifdef USE_PCM_MIC_DATA + sendPCMMicData(); +#endif + sendAllVoiceData(); + playAllReceivedData(); + + EnterCriticalSection(&m_csRemoteConnections); + + for(int i=m_remoteConnections.size()-1;i>=0;i--) + { + if(m_remoteConnections[i]->m_bFlaggedForShutdown) + { + delete m_remoteConnections[i]; + m_remoteConnections.erase(m_remoteConnections.begin() + i); + } + } + + LeaveCriticalSection(&m_csRemoteConnections); + + // MGH - added to hopefully fix a lockup with shutdowns happening on different threads, when more than 1 player leaves the game + for(int i=0;iIsLocal()) + { + return m_localPlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bHasMicConnected; + } + else + { + EnterCriticalSection(&m_csRemoteConnections); + for(int i=0;im_remoteRoomMemberId == pNetPlayer->m_roomMemberId) + { + bool bMicConnected = pVoice->m_remotePlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bHasMicConnected; + LeaveCriticalSection(&m_csRemoteConnections); + return bMicConnected; + } + } + LeaveCriticalSection(&m_csRemoteConnections); + } + // if we get here we've not found the player, panic!! + assert(0); + return false; +} + +void SonyVoiceChat_Orbis::mute( bool bMute ) +{ +} + +void SonyVoiceChat_Orbis::mutePlayer( const SceNpMatching2RoomMemberId member_id, bool bMute ) /*Turn chat audio from a specified player on or off */ +{ +} + +void SonyVoiceChat_Orbis::muteLocalPlayer( bool bMute ) /*Turn microphone input on or off */ +{ +} + +bool SonyVoiceChat_Orbis::isMuted() +{ +} + +bool SonyVoiceChat_Orbis::isMutedPlayer( const PlayerUID& memberUID) +{ + return false; +} + +bool SonyVoiceChat_Orbis::isMutedLocalPlayer() +{ + return false; +} + + +bool SonyVoiceChat_Orbis::isTalking(SQRNetworkPlayer* pNetPlayer) +{ + if(pNetPlayer->IsLocal()) + { + return m_localPlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bTalking; + } + else + { + EnterCriticalSection(&m_csRemoteConnections); + for(int i=0;im_remoteRoomMemberId == pNetPlayer->m_roomMemberId) + { + bool bTalking = pVoice->m_remotePlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bTalking; + LeaveCriticalSection(&m_csRemoteConnections); + return bTalking; + } + } + LeaveCriticalSection(&m_csRemoteConnections); + } + // if we get here we've not found the player, panic!! + assert(0); + return false; +} + + +void SQRLocalVoiceDevice::init(SceUserServiceUserId localUserID, bool bChatRestricted) +{ + SceVoiceInitParam params; + SceVoicePortParam portArgs; + + int returnCode = 0; + m_bChatRestricted = bChatRestricted; + +#ifdef USE_PCM_MIC_DATA + portArgs.portType = SCE_VOICE_PORTTYPE_IN_PCMAUDIO; + portArgs.bMute = false; + portArgs.threshold = 100; + portArgs.volume = 1.0f; + portArgs.pcmaudio.format.sampleRate= SCE_VOICE_SAMPLINGRATE_16000; + portArgs.pcmaudio.format.dataType = SCE_VOICE_PCM_SHORT_LITTLE_ENDIAN; + portArgs.pcmaudio.bufSize = 4096; + CreatePort( &m_microphonePort, &portArgs ); +#else + portArgs.portType = SCE_VOICE_PORTTYPE_IN_DEVICE; + portArgs.bMute = false; + portArgs.threshold = 0; + portArgs.volume = 1.0f; + portArgs.device.userId = localUserID; + portArgs.device.type = SCE_AUDIO_IN_TYPE_VOICE; + portArgs.device.index = 0; + CreatePort( &m_microphonePort, &portArgs ); + +#endif + portArgs.portType = SCE_VOICE_PORTTYPE_OUT_DEVICE; + portArgs.bMute = false; + portArgs.threshold = 0; + portArgs.volume = 1.0f; + portArgs.device.userId = localUserID; + portArgs.device.type = SCE_AUDIO_OUT_PORT_TYPE_VOICE; + portArgs.device.index = 0; + CreatePort( &m_headsetPort, &portArgs ); + + m_localUserID = localUserID; + +} + + + +void SQRLocalVoiceDevice::shutdownWhenFlagged() +{ + + assert(isValid()); + m_localUserID = SCE_USER_SERVICE_USER_ID_INVALID; + DeletePort(m_microphonePort); + DeletePort(m_headsetPort); + m_bFlaggedForShutdown = false; +} + + + +SQRVoiceConnection* SonyVoiceChat_Orbis::addRemoteConnection( int RudpCxt, SceNpMatching2RoomMemberId peerMemberId) +{ + EnterCriticalSection(&m_csRemoteConnections); + SQRVoiceConnection* pConn = new SQRVoiceConnection(RudpCxt, peerMemberId); + m_remoteConnections.push_back(pConn); + m_forceSendPacket = true; // new connection, so we'll force a packet through for the flags + LeaveCriticalSection(&m_csRemoteConnections); + + return pConn; +} + +void SonyVoiceChat_Orbis::connectPorts(uint32_t inPort, uint32_t outPort) +{ + int returnCode = sceVoiceConnectIPortToOPort(inPort, outPort); + if (returnCode != SCE_OK ) + { + app.DebugPrintf("sceVoiceConnectIPortToOPort failed (0x%08x), inPort 0x%08x, outPort 0x%08x\n", returnCode, inPort, outPort); + assert(0); + } +} +void SonyVoiceChat_Orbis::disconnectPorts(uint32_t inPort, uint32_t outPort) +{ + int returnCode = sceVoiceDisconnectIPortFromOPort(inPort, outPort); + if (returnCode != SCE_OK ) + { + app.DebugPrintf("sceVoiceDisconnectIPortFromOPort failed (0x%08x), inPort 0x%08x, outPort 0x%08x\n", returnCode, inPort, outPort); + assert(0); + } +} + + +void SonyVoiceChat_Orbis::makeLocalConnections() +{ + // connect all mics to other devices headsets, for local chat + for(int i=0;iisValid()) + { + for(int j=0;jisValid()) + { + if(pConnectFrom->m_localConnections[j] == false) + { + if(pConnectTo->m_bChatRestricted == false && pConnectFrom->m_bChatRestricted == false) + { + connectPorts(pConnectFrom->m_microphonePort, pConnectTo->m_headsetPort); + pConnectFrom->m_localConnections[j] = true; + } + } + } + } + } + } +} + +void SonyVoiceChat_Orbis::breakLocalConnections(int playerIdx) +{ + // break any connections with devices that are no longer valid + for(int i=0;im_localConnections[j] == true) + { + SQRLocalVoiceDevice* pConnectedTo = &m_localVoiceDevices[j]; + if(i==playerIdx || j==playerIdx) + { + if(pConnectedTo->m_bChatRestricted == false && pConnectedFrom->m_bChatRestricted == false) + { + disconnectPorts(pConnectedFrom->m_microphonePort, pConnectedTo->m_headsetPort); + pConnectedFrom->m_localConnections[j] = false; + } + } + } + } + } +} + + +void SonyVoiceChat_Orbis::initLocalPlayer(int playerIndex) +{ + if(m_localVoiceDevices[playerIndex].isValid() == false) + { + bool chatRestricted = false; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&chatRestricted,NULL,NULL); + + // create all device ports required + m_localVoiceDevices[playerIndex].init(ProfileManager.getUserID(playerIndex), chatRestricted); + m_numLocalDevicesConnected++; + if(m_localVoiceDevices[playerIndex].m_bChatRestricted == false) + { + connectPorts(m_localVoiceDevices[playerIndex].m_microphonePort, m_voiceOutPort); + } + m_forceSendPacket = true; // new local device, so we'll force a packet through for the flags + + } + makeLocalConnections(); +} + +void SonyVoiceChat_Orbis::connectPlayer(SQRVoiceConnection* pConnection, int playerIndex) +{ + if((pConnection->m_headsetConnectionMask & (1 << playerIndex)) == 0) + { + initLocalPlayer(playerIndex); // added this as we can get a client->client connection coming in first, and the network player hasn't been created yet (so this hasn't been initialised) + if(m_localVoiceDevices[playerIndex].m_bChatRestricted == false) + { + connectPorts(pConnection->m_voiceInPort, m_localVoiceDevices[playerIndex].m_headsetPort); + } + pConnection->m_headsetConnectionMask |= (1 << playerIndex); + app.DebugPrintf("Connecting player %d to rudp context %d\n", playerIndex, pConnection->m_rudpCtx); + m_forceSendPacket = true; // new connection, so we'll force a packet through for the flags + } +} + +SQRVoiceConnection* SonyVoiceChat_Orbis::GetVoiceConnectionFromRudpCtx( int RudpCtx ) +{ + for(int i=0;im_rudpCtx == RudpCtx) + return m_remoteConnections[i]; + } + return NULL; +} + +void SonyVoiceChat_Orbis::connectPlayerToAll( int playerIndex ) +{ + EnterCriticalSection(&m_csRemoteConnections); + + for(int i=0;im_remoteRoomMemberId == roomMemberID) + { + return m_remoteConnections[i]; + } + } + + return NULL; +} + +void SonyVoiceChat_Orbis::disconnectLocalPlayer( int localIdx ) +{ + EnterCriticalSection(&m_csRemoteConnections); + + if(m_localVoiceDevices[localIdx].m_bChatRestricted == false) + { + disconnectPorts(m_localVoiceDevices[localIdx].m_microphonePort, m_voiceOutPort); + + for(int i=0;im_voiceInPort, m_localVoiceDevices[localIdx].m_headsetPort); + m_remoteConnections[i]->m_headsetConnectionMask &= (~(1 << localIdx)); + app.DebugPrintf("disconnecting player %d from rudp context %d\n", localIdx, m_remoteConnections[i]->m_rudpCtx); + } + } + LeaveCriticalSection(&m_csRemoteConnections); + + breakLocalConnections(localIdx); + m_localVoiceDevices[localIdx].flagForShutdown(); + m_numLocalDevicesConnected--; + + if(m_numLocalDevicesConnected == 0) // no more local players, kill all the remote connections + { + for(int i=0;i=0); + if(voiceIdx>=0) + { + m_remoteConnections[voiceIdx]->m_bFlaggedForShutdown = true; + } + + LeaveCriticalSection(&m_csRemoteConnections); + +} + +void SonyVoiceChat_Orbis::setConnected( int RudpCtx ) +{ + SQRVoiceConnection* pVoice = GetVoiceConnectionFromRudpCtx(RudpCtx); + if(pVoice) + { + pVoice->m_bConnected = true; + m_forceSendPacket = true; + } + else + { + assert(false); + } +} + + + + +RingBuffer::RingBuffer( int sizeBytes ) +{ + buffer = new char[sizeBytes]; + buf_size = sizeBytes; + buf_full = buf_free = 0; +} + + +int RingBuffer::Write( char* data, int len_ ) +{ + if (len_ <= 0) return len_; + unsigned int len = (unsigned int)len_; + unsigned int data_size = buf_size - (buf_free - buf_full); + if (len > data_size) + len = data_size; + data_size = buf_size - (buf_free % buf_size); + if (data_size > len) + data_size = len; + memcpy(buffer + (buf_free % buf_size), data, data_size); + if (data_size != len) + memcpy(buffer, data + data_size, len - data_size); + buf_free += len; + return len; +} + +int RingBuffer::Read( char* data, int max_bytes_ ) +{ + if (max_bytes_ <= 0) return max_bytes_; + unsigned int max_bytes = (unsigned int)max_bytes_; + unsigned int result = buf_free - buf_full; + if (result > max_bytes) + result = max_bytes; + unsigned int chunk = buf_size - (buf_full % buf_size); + if (chunk > result) + chunk = result; + memcpy(data, buffer + (buf_full % buf_size), chunk); + if (chunk != result) + memcpy(data + chunk, buffer, result - chunk); + buf_full += result; + return result; +} -- cgit v1.2.3