Files
MinecraftConsoles/Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.h
2026-03-01 12:16:08 +08:00

215 lines
6.7 KiB
C++

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <voice_qos.h>
#include "Common/Network/Sony/SQRNetworkPlayer.h"
static const int sc_maxVoiceDataSize = 2048;
class VoicePacket
{
static const int MAX_LOCAL_PLAYER_COUNT = 4;
public:
struct Flags
{
bool m_bTalking : 1;
bool m_bHasMicConnected : 1;
};
Flags m_localPlayerFlags[MAX_LOCAL_PLAYER_COUNT];
uint32_t m_frameSendIndex;
uint32_t m_numFrames;
uint32_t m_checkSum;
uint32_t m_playerIndexFlags;
char m_data[sc_maxVoiceDataSize];
static int getPacketSize(int dataSize) { return (uint64_t)&((VoicePacket*)0)->m_data[dataSize];}
void setChecksum(int dataSize)
{
m_checkSum = 0;
for(int i=0;i<dataSize;i++)
m_checkSum += m_data[i];
}
void verifyData(int packetSize, int frameSize)
{
if(m_numFrames == 0)
return;
int dataSize = m_numFrames*frameSize;
assert(packetSize == getPacketSize(dataSize));
int checkSum = 0;
for(int i=0;i<dataSize;i++)
checkSum += m_data[i];
assert(checkSum == m_checkSum);
}
};
//--------------------------------------------------------------------------
// read-write-safe ring buffer implementation: does not use mutex protection
// the writer thread changes pointer <buf_free>,
// the reader thread changes pointer <buf_full>
class RingBuffer
{
public:
RingBuffer(int sizeBytes);
~RingBuffer() { delete buffer; }
void Reset(void) { buf_full = buf_free = 0; }
unsigned int DataSize(void) { return (buf_free - buf_full); }
int Write(char* data, int len_);
int Read(char* data, int max_bytes_);
int getDataSize() { return buf_free - buf_full; }
void ResetByWriter(void) { buf_free = buf_full; }
void ResetByReader(void) { buf_full = buf_free; }
private:
char* buffer;
unsigned int buf_size;
unsigned int buf_full;
unsigned int buf_free;
};
static const int sc_ringBufferSize = 16384;
class SQRLocalVoiceDevice
{
public:
uint32_t m_headsetPort;
uint32_t m_microphonePort;
uint8_t m_localConnections[4]; // connection between this devices mic and other local player's headsets
bool m_bChatRestricted;
bool m_bFlaggedForShutdown;
SceUserServiceUserId m_localUserID;
public:
SQRLocalVoiceDevice()
: m_headsetPort(SCE_VOICE_INVALID_PORT_ID)
, m_microphonePort(SCE_VOICE_INVALID_PORT_ID)
, m_localUserID(SCE_USER_SERVICE_USER_ID_INVALID)
{
for(int i=0;i<4;i++)
m_localConnections[i] = 0;
}
void init(SceUserServiceUserId localUserID, bool bChatRestricted);
void flagForShutdown() { m_bFlaggedForShutdown = true;}
void shutdownWhenFlagged();
bool isValid() { return m_localUserID != SCE_USER_SERVICE_USER_ID_INVALID; }
// void setBitRate()
// {
// int err = sceVoiceSetBitRate(uint32_t portId,
// SceVoiceBitRate bitrate
// );
// }
};
#define VOICE_ENCODED_FORMAT SCE_VOICE_BITRATE_7300
class SQRVoiceConnection
{
static const int MAX_LOCAL_PLAYER_COUNT = 4;
static const int SNP_MAX_PAYLOAD = 1346; // This is the default RUDP payload size - if we want to change this we'll need to use cellRudpSetOption to set something else & adjust segment size
class QueuedSendBlock
{
public:
unsigned char *start;
unsigned char *end;
unsigned char *current;
};
std::queue<QueuedSendBlock> m_sendQueue;
CRITICAL_SECTION m_csQueue;
public:
int m_rudpCtx;
bool m_bConnected;
uint32_t m_voiceInPort; // 1 input port per connection, incoming UDP packets are written to each of these, and then they're connected out to all headsets
int m_headsetConnectionMask; // 1 bit per player, if the headset connection has been made
RingBuffer m_playRingBuffer;
SceNpMatching2RoomMemberId m_remoteRoomMemberId; // Assigned by Matching2 lib, we can use to indicate which machine this player belongs to (note - 16 bits)
std::queue<VoicePacket> m_receivedVoicePackets;
CRITICAL_SECTION m_csPacketQueue;
VoicePacket::Flags m_remotePlayerFlags[MAX_LOCAL_PLAYER_COUNT];
uint32_t m_nextExpectedFrameIndex;
bool m_bFlaggedForShutdown;
SQRVoiceConnection(int rudpCtx, SceNpMatching2RoomMemberId remoteRoomMemberId);
~SQRVoiceConnection();
void SendInternal(const void *data, unsigned int dataSize);
void SendMoreInternal();
void readRemoteData();
bool getNextPacket(VoicePacket& packet);
void addPacket(VoicePacket& packet);
};
class SonyVoiceChat_Orbis
{
public:
static void init();
static void start();
static void shutdown();
static void tick();
static void checkFinished();
static void setEnabled(bool bEnabled);
static bool hasMicConnected(SQRNetworkPlayer* pNetPlayer);
static bool isTalking(SQRNetworkPlayer* pNetPlayer);
static void mute(bool bMute); //Turn chat audio on or off
static void mutePlayer(const SceNpMatching2RoomMemberId member_id, bool bMute); //Turn chat audio from a specified player on or off;
static void muteLocalPlayer(bool bMute); //Turn microphone input on or off;
static bool isMuted();
static bool isMutedPlayer(const PlayerUID& memberUID);
static bool isMutedLocalPlayer(); //Turn microphone input on or off;
static void initLocalPlayer(int playerIndex);
static SQRVoiceConnection* addRemoteConnection(int RudpCxt, SceNpMatching2RoomMemberId peerMemberId);
static void connectPlayer(SQRVoiceConnection* pConnection, int playerIndex);
static void connectPlayerToAll(int playerIndex);
static void disconnectLocalPlayer(int localIdx);
static void disconnectRemoteConnection( SQRVoiceConnection* pVoice );
static void VoiceEventCallback( SceVoiceEventData* pEvent );
static std::vector<SQRVoiceConnection*> m_remoteConnections;
static void connectPorts(uint32_t inPort, uint32_t outPort);
static void disconnectPorts(uint32_t inPort, uint32_t outPort);
static void makeLocalConnections();
static void breakLocalConnections(int playerIdx);
static void sendAllVoiceData();
static void playAllReceivedData();
static void sendPCMMicData();
static SQRVoiceConnection* getVoiceConnectionFromRoomMemberID(SceNpMatching2RoomMemberId roomMemberID);
static SQRVoiceConnection* GetVoiceConnectionFromRudpCtx(int RudpCtx);
static void setConnected(int RudpCtx);
private:
static const int MAX_LOCAL_PLAYER_COUNT = 4;
static bool m_bVoiceStarted;
static int m_numLocalDevicesConnected;
static SQRLocalVoiceDevice m_localVoiceDevices[MAX_LOCAL_PLAYER_COUNT];
static uint32_t m_voiceOutPort; // single output port that all local devices are mixed to, and then sent out to all other remote machines
static RingBuffer m_recordRingBuffer;
static RingBuffer m_playRingBuffer;
static VoicePacket::Flags m_localPlayerFlags[MAX_LOCAL_PLAYER_COUNT];
static bool m_forceSendPacket; // force a packet across the network, even if there's no data, so we can update flags
static bool m_bInitialised;
static CRITICAL_SECTION m_csRemoteConnections;
};