the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include <libsysmodule.h>
3#include <rudp.h>
4#include <audioin.h>
5#include <audioout.h>
6#include <fios2.h>
7
8#include "SonyVoiceChat_Vita.h"
9
10std::vector<SQRVoiceConnection*> SonyVoiceChat_Vita::m_remoteConnections;
11bool SonyVoiceChat_Vita::m_bVoiceStarted = false;
12int SonyVoiceChat_Vita::m_numLocalDevicesConnected = 0;
13SQRLocalVoiceDevice SonyVoiceChat_Vita::m_localVoiceDevices[MAX_LOCAL_PLAYER_COUNT];
14uint32_t SonyVoiceChat_Vita::m_voiceOutPort;
15bool SonyVoiceChat_Vita::m_forceSendPacket = false; // force a packet across the network, even if there's no data, so we can update flags
16RingBuffer SonyVoiceChat_Vita::m_recordRingBuffer(sc_ringBufferSize);
17VoicePacket::Flags SonyVoiceChat_Vita::m_localPlayerFlags[MAX_LOCAL_PLAYER_COUNT];
18bool SonyVoiceChat_Vita::m_bInitialised = false;
19CRITICAL_SECTION SonyVoiceChat_Vita::m_csRemoteConnections;
20
21// sample related variables
22SceVoiceStartParam startParam;
23int32_t playSize = 0;
24
25static const int sc_thresholdValue = 100;
26
27static const bool sc_verbose = false;
28
29// #define _USE_PCM_AUDIO_
30//#define LOOPBACK_TEST
31
32
33
34int g_loadedPCMVoiceDataSizes[4];
35int g_loadedPCMVoiceDataPos[4];
36char* g_loadedPCMVoiceData[4];
37
38static void CreatePort(uint32_t *portId, const SceVoicePortParam *pArg)
39{
40// C4JThread::PushAffinityAllCores(); // PS4 only
41
42 int err = sceVoiceCreatePort( portId, pArg );
43 assert(err == SCE_OK);
44 assert(*portId != SCE_VOICE_INVALID_PORT_ID);
45// C4JThread::PopAffinity(); // PS4 only
46}
47
48static void DeletePort(uint32_t& port)
49{
50 int32_t result;
51 if (port != SCE_VOICE_INVALID_PORT_ID)
52 {
53 result = sceVoiceDeletePort( port );
54 if (result != SCE_OK)
55 {
56 app.DebugPrintf("sceVoiceDeletePort failed %0x\n", result);
57 assert(0);
58 }
59 port = SCE_VOICE_INVALID_PORT_ID;
60 }
61}
62
63
64void LoadPCMVoiceData()
65{
66 for(int i=0;i<4;i++)
67 {
68 char filename[64];
69 sprintf(filename, "voice%d.pcm", i+1);
70 HANDLE file = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
71 DWORD dwHigh=0;
72 g_loadedPCMVoiceDataSizes[i] = GetFileSize(file,&dwHigh);
73
74 if(g_loadedPCMVoiceDataSizes[i]!=0)
75 {
76 g_loadedPCMVoiceData[i] = new char[g_loadedPCMVoiceDataSizes[i]];
77 DWORD bytesRead;
78 BOOL bSuccess = ReadFile(file, g_loadedPCMVoiceData[i], g_loadedPCMVoiceDataSizes[i], &bytesRead, NULL);
79 assert(bSuccess);
80 }
81 g_loadedPCMVoiceDataPos[i] = 0;
82 }
83}
84
85
86void SonyVoiceChat_Vita::init()
87{
88 int returnCode = SCE_OK;
89
90 returnCode = sceSysmoduleLoadModule(SCE_SYSMODULE_VOICE);
91 if (returnCode < 0)
92 {
93 app.DebugPrintf("Error: sceSysmoduleLoadModule(SCE_SYSMODULE_VOICE), ret 0x%08x\n", returnCode);
94 assert(0);
95 }
96
97
98 SceVoiceInitParam params;
99 SceVoicePortParam portArgs;
100 memset( ¶ms, 0, sizeof(params) );
101 params.appType = SCEVOICE_APPTYPE_GAME;
102 params.onEvent = 0;
103 returnCode = sceVoiceInit( ¶ms , SCEVOICE_VERSION_100);
104 if (returnCode < 0)
105 {
106 app.DebugPrintf("Error: sceVoiceInit(), ret 0x%08x\n", returnCode);
107 assert(0);
108 }
109
110#ifdef _USE_PCM_AUDIO_
111 portArgs.portType = SCEVOICE_PORTTYPE_OUT_PCMAUDIO;
112 portArgs.bMute = false;
113 portArgs.threshold = 0;
114 portArgs.volume = 1.0f;
115 portArgs.pcmaudio.format.dataType = SCEVOICE_PCM_SHORT_LITTLE_ENDIAN;
116 portArgs.pcmaudio.format.sampleRate = SCE_VOICE_SAMPLINGRATE_16000;
117 portArgs.pcmaudio.bufSize = 4096;
118#else
119 portArgs.portType = SCEVOICE_PORTTYPE_OUT_VOICE;
120 portArgs.bMute = false;
121 portArgs.threshold = 0;
122 portArgs.volume = 1.0f;
123 portArgs.voice.bitrate = VOICE_ENCODED_FORMAT;
124#endif
125 CreatePort( &m_voiceOutPort, &portArgs );
126
127 start();
128 m_bInitialised = true;
129#ifdef LOOPBACK_TEST
130 // LoadPCMVoiceData();
131 initLocalPlayer(0);
132 connectPorts(m_localVoiceDevices[0].m_microphonePort, m_localVoiceDevices[0].m_headsetPort);
133 // SQRVoiceConnection* pConnection = addRemoteConnection(0, 0);
134 // connectPlayer(pConnection, 0);
135#endif
136 InitializeCriticalSection(&m_csRemoteConnections);
137}
138
139void SonyVoiceChat_Vita::shutdown()
140{
141 m_bInitialised = false;
142 int32_t result;
143
144 DeletePort( m_voiceOutPort);
145 result = sceVoiceStop();
146 assert(result == SCE_OK);
147 result = sceVoiceEnd();
148 assert(result == SCE_OK);
149
150 m_bVoiceStarted=false;
151 sceKernelFreeMemBlock(startParam.container);
152
153 int returnCode = sceSysmoduleUnloadModule(SCE_SYSMODULE_VOICE);
154 if (returnCode < 0)
155 {
156 app.DebugPrintf("Error: sceSysmoduleUnloadModule(SCE_SYSMODULE_VOICE), ret 0x%08x\n", returnCode);
157 assert(0);
158 }
159
160 DeleteCriticalSection(&m_csRemoteConnections);
161}
162
163
164void SonyVoiceChat_Vita::start()
165{
166 if( m_bVoiceStarted == false)
167 {
168 startParam.container = sceKernelAllocMemBlock("SceUserVoiceEvent", SCE_KERNEL_MEMBLOCK_TYPE_USER_RWDATA, SCE_VOICE_MEMORY_CONTAINER_SIZE, SCE_NULL);
169 int err;
170
171// C4JThread::PushAffinityAllCores(); // PS4 only
172 err = sceVoiceStart(&startParam);
173 assert(err == SCE_OK);
174// C4JThread::PopAffinity(); // PS4 only
175
176 m_bVoiceStarted = true;
177 }
178}
179
180void SonyVoiceChat_Vita::checkFinished()
181{
182 EnterCriticalSection(&m_csRemoteConnections);
183
184 for(int i=0;i<m_remoteConnections.size();i++)
185 {
186 if(!m_remoteConnections[i]->m_bFlaggedForShutdown)
187 m_remoteConnections[i]->m_bFlaggedForShutdown = true;
188 }
189// assert(m_numLocalDevicesConnected == 0);
190
191 LeaveCriticalSection(&m_csRemoteConnections);
192}
193
194void SonyVoiceChat_Vita::setEnabled( bool bEnabled )
195{
196}
197
198
199
200// 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,
201// 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
202// send here is complete, and can continue on.
203void SQRVoiceConnection::SendMoreInternal()
204{
205 bool keepSending;
206 do
207 {
208 EnterCriticalSection(&m_csQueue);
209 keepSending = false;
210 if( m_sendQueue.size() > 0)
211 {
212 // Attempt to send the full data in the first element in our queue
213 unsigned char *data= m_sendQueue.front().current;
214 int dataSize = m_sendQueue.front().end - m_sendQueue.front().current;
215 int ret = sceRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );
216 int wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK;
217
218 if( ret == dataSize )
219 {
220 // Fully sent, remove from queue - will loop in the while loop to see if there's anything else in the queue we could send
221 delete [] m_sendQueue.front().start;
222 m_sendQueue.pop();
223 if( m_sendQueue.size() )
224 {
225 keepSending = true;
226 }
227 }
228 else if( ( ret >= 0 ) || ( ret == wouldBlockFlag ) )
229 {
230
231
232 // Things left to send - adjust this element in the queue
233 int remainingBytes;
234 if( ret >= 0 )
235 {
236 // Only ret bytes sent so far
237 remainingBytes = dataSize - ret;
238 assert(remainingBytes > 0 );
239 }
240 else
241 {
242 // Is CELL_RUDP_ERROR_WOULDBLOCK, nothing has yet been sent
243 remainingBytes = dataSize;
244 }
245 m_sendQueue.front().current = m_sendQueue.front().end - remainingBytes;
246 }
247 }
248 LeaveCriticalSection(&m_csQueue);
249 } while (keepSending);
250}
251
252void SQRVoiceConnection::SendInternal(const void *data, unsigned int dataSize)
253{
254 EnterCriticalSection(&m_csQueue);
255
256 QueuedSendBlock sendBlock;
257
258 unsigned char *dataCurrent = (unsigned char *)data;
259 unsigned int dataRemaining = dataSize;
260
261 while( dataRemaining )
262 {
263 int dataSize = dataRemaining;
264 if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD;
265 sendBlock.start = new unsigned char [dataSize];
266 sendBlock.end = sendBlock.start + dataSize;
267 sendBlock.current = sendBlock.start;
268 memcpy( sendBlock.start, dataCurrent, dataSize);
269 m_sendQueue.push(sendBlock);
270 dataRemaining -= dataSize;
271 dataCurrent += dataSize;
272 }
273
274// app.DebugPrintf("voice sent %d bytes\n", dataSize);
275
276 // Now try and send as much as we can
277 SendMoreInternal();
278
279 LeaveCriticalSection(&m_csQueue);
280}
281
282void SQRVoiceConnection::readRemoteData()
283{
284 unsigned int dataSize = sceRudpGetSizeReadable(m_rudpCtx);
285 if( dataSize > 0 )
286 {
287 VoicePacket packet;
288 unsigned int bytesRead = sceRudpRead( m_rudpCtx, &packet, dataSize, 0, NULL );
289 unsigned int writeSize;
290 if( bytesRead > 0 )
291 {
292// app.DebugPrintf("voice received %d bytes\n", bytesRead);
293 writeSize = bytesRead;
294 if(packet.verifyData(bytesRead, 19))
295 addPacket(packet);
296// m_playRingBuffer.Write((char*)data, writeSize);
297
298 }
299 }
300
301}
302
303
304
305SQRVoiceConnection::SQRVoiceConnection( int rudpCtx, SceNpMatching2RoomMemberId remoteRoomMemberId )
306 : m_rudpCtx(rudpCtx)
307 , m_remoteRoomMemberId(remoteRoomMemberId)
308 , m_bConnected(false)
309 , m_headsetConnectionMask(0)
310 , m_playRingBuffer(sc_ringBufferSize)
311{
312 InitializeCriticalSection(&m_csQueue);
313 InitializeCriticalSection(&m_csPacketQueue);
314
315 SceVoiceInitParam params;
316 SceVoicePortParam portArgs;
317#ifdef _USE_PCM_AUDIO_
318 portArgs.portType = SCEVOICE_PORTTYPE_IN_PCMAUDIO;
319 portArgs.bMute = false;
320 portArgs.threshold = 100;
321 portArgs.volume = 1.0f;
322 portArgs.pcmaudio.format.sampleRate= SCEVOICE_SAMPLINGRATE_16000;
323 portArgs.pcmaudio.format.dataType = SCEVOICE_PCM_SHORT_LITTLE_ENDIAN;
324 portArgs.pcmaudio.bufSize = 4096;
325#else
326 portArgs.portType = SCEVOICE_PORTTYPE_IN_VOICE;
327 portArgs.bMute = false;
328 portArgs.threshold = sc_thresholdValue; // compensate network jitter
329 portArgs.volume = 1.0f;
330 portArgs.voice.bitrate = VOICE_ENCODED_FORMAT;
331#endif
332 CreatePort( &m_voiceInPort, &portArgs );
333 m_nextExpectedFrameIndex = 0;
334 m_bFlaggedForShutdown = false;
335}
336
337SQRVoiceConnection::~SQRVoiceConnection()
338{
339 DeleteCriticalSection(&m_csQueue);
340 DeleteCriticalSection(&m_csPacketQueue);
341 sceRudpTerminate( m_rudpCtx );
342 app.DebugPrintf("-----------------------------\n");
343 app.DebugPrintf("Voice rudp context deleted %d\n", m_rudpCtx);
344 app.DebugPrintf("-----------------------------\n");
345
346 DeletePort(m_voiceInPort);
347
348}
349
350bool SQRVoiceConnection::getNextPacket( VoicePacket& packet )
351{
352 EnterCriticalSection(&m_csPacketQueue);
353 bool retVal = false;
354 if(m_receivedVoicePackets.size() > 0)
355 {
356 retVal = true;
357 packet = m_receivedVoicePackets.front();
358 m_receivedVoicePackets.pop();
359 }
360 LeaveCriticalSection(&m_csPacketQueue);
361 return retVal;
362}
363
364void SQRVoiceConnection::addPacket( VoicePacket& packet )
365{
366 EnterCriticalSection(&m_csPacketQueue);
367 m_receivedVoicePackets.push(packet);
368 LeaveCriticalSection(&m_csPacketQueue);
369}
370
371int g_frameNum = 0;
372bool g_bRecording = false;
373
374
375uint32_t frameSendIndex = 0;
376uint32_t lastReadFrameCnt = 0;
377
378
379void PrintAllOutputVoiceStates( std::vector<SQRVoiceConnection*>& connections)
380{
381 for(int rIdx=0;rIdx<connections.size(); rIdx++)
382 {
383 SQRVoiceConnection* pVoice = connections[rIdx];
384 SceVoiceBasePortInfo portInfo;
385 int result = sceVoiceGetPortInfo(pVoice->m_voiceInPort, &portInfo );
386 static SceVoicePortState lastPortState = SCEVOICE_PORTSTATE_IDLE;
387 if(portInfo.state != lastPortState)
388 {
389 lastPortState = portInfo.state;
390 switch(portInfo.state)
391 {
392 case SCEVOICE_PORTSTATE_IDLE:
393 app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_IDLE\n");
394 break;
395 case SCEVOICE_PORTSTATE_BUFFERING:
396 app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_BUFFERING\n");
397 break;
398 case SCEVOICE_PORTSTATE_RUNNING:
399 app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_RUNNING\n");
400 break;
401 case SCEVOICE_PORTSTATE_READY:
402 app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_READY\n");
403 break;
404 case SCEVOICE_PORTSTATE_NULL:
405 default:
406 app.DebugPrintf(" ----- SCE_VOICE_PORTSTATE_NULL\n");
407 break;
408 }
409 }
410 }
411
412}
413
414
415void SonyVoiceChat_Vita::sendPCMMicData()
416{
417 int32_t result;
418 uint32_t outputPortBytes;
419 VoicePacket packetToSend;
420 uint32_t readSize;
421 SceVoiceBasePortInfo portInfo;
422 memset( &portInfo, 0, sizeof(portInfo) );
423 uint16_t frameGap = 0;
424
425 DWORD tick = GetTickCount();
426 static DWORD lastTick = 0;
427 int numFrames = ceilf((tick - lastTick)/16.0f);
428 lastTick = tick;
429 readSize = 512 * numFrames;
430
431 if(g_loadedPCMVoiceDataPos[0] + readSize < g_loadedPCMVoiceDataSizes[0])
432 {
433 for(int i=0;i<MAX_LOCAL_PLAYER_COUNT;i++)
434 {
435 if(m_localVoiceDevices[i].isValid())
436 {
437 result = sceVoiceWriteToIPort(m_localVoiceDevices[i].m_microphonePort, &g_loadedPCMVoiceData[0][g_loadedPCMVoiceDataPos[0]], &readSize, 0);
438 }
439 }
440 }
441 g_loadedPCMVoiceDataPos[0] += readSize;
442 if(g_loadedPCMVoiceDataPos[0] > (g_loadedPCMVoiceDataSizes[0] + 8192))
443 g_loadedPCMVoiceDataPos[0] = 0;
444
445
446}
447
448void SonyVoiceChat_Vita::sendAllVoiceData()
449{
450 int32_t result;
451 uint32_t outputPortBytes;
452 VoicePacket packetToSend;
453 uint32_t readSize;
454 SceVoiceBasePortInfo portInfo;
455 memset( &portInfo, 0, sizeof(portInfo) );
456 uint16_t frameGap = 0;
457
458 VoicePacket::Flags lastPlayerFlags[MAX_LOCAL_PLAYER_COUNT];
459
460 for(int i=0; i<MAX_LOCAL_PLAYER_COUNT;i++)
461 lastPlayerFlags[i] = m_localPlayerFlags[i];
462
463 bool flagsChanged = false;
464
465
466
467 // grab the status of all the local voices
468 for(int i=0; i<MAX_LOCAL_PLAYER_COUNT;i++)
469 {
470 if(m_localVoiceDevices[i].isValid())
471 {
472 bool bChatRestricted = false;
473 ProfileManager.GetChatAndContentRestrictions(i,true,&bChatRestricted,NULL,NULL);
474
475 if(bChatRestricted)
476 {
477 m_localPlayerFlags[i].m_bHasMicConnected = false;
478 }
479 else
480 {
481 m_localPlayerFlags[i].m_bHasMicConnected = true;
482 }
483
484
485
486 SceVoiceBasePortInfo portInfo;
487 int result = sceVoiceGetPortInfo(m_localVoiceDevices[i].m_microphonePort, &portInfo );
488 assert(result == SCE_OK);
489 switch(portInfo.state)
490 {
491 case SCEVOICE_PORTSTATE_READY:
492 case SCEVOICE_PORTSTATE_BUFFERING:
493 case SCEVOICE_PORTSTATE_IDLE:
494 m_localPlayerFlags[i].m_bTalking = false;
495 break;
496 case SCEVOICE_PORTSTATE_RUNNING:
497 m_localPlayerFlags[i].m_bTalking = true;
498 break;
499 default:
500 assert(0);
501 }
502 }
503 else
504 {
505 m_localPlayerFlags[i].m_bHasMicConnected = false;
506 m_localPlayerFlags[i].m_bTalking = false;
507 }
508 packetToSend.m_localPlayerFlags[i] = m_localPlayerFlags[i];
509 if(m_localPlayerFlags[i].m_bHasMicConnected != lastPlayerFlags[i].m_bHasMicConnected ||
510 m_localPlayerFlags[i].m_bTalking != lastPlayerFlags[i].m_bTalking)
511 flagsChanged = true;
512 }
513
514
515 if(sc_verbose)
516 {
517 EnterCriticalSection(&m_csRemoteConnections);
518 PrintAllOutputVoiceStates(m_remoteConnections);
519 LeaveCriticalSection(&m_csRemoteConnections);
520 }
521 result = sceVoiceGetPortInfo(m_voiceOutPort, &portInfo );
522 if (result != SCE_OK)
523 {
524 app.DebugPrintf("sceVoiceGetPortInfo failed %x\n", result);
525 assert(0);
526 }
527
528
529
530
531 outputPortBytes = portInfo.numByte;
532 outputPortBytes = (outputPortBytes>sizeof(packetToSend.m_data))?sizeof(packetToSend.m_data):outputPortBytes;
533 if( outputPortBytes || flagsChanged || m_forceSendPacket)
534 {
535 frameSendIndex += lastReadFrameCnt;
536 if(outputPortBytes)
537 {
538 readSize = outputPortBytes;
539 result = sceVoiceReadFromOPort(m_voiceOutPort, packetToSend.m_data, &readSize );
540 if (result != SCE_OK)
541 {
542 app.DebugPrintf("sceVoiceReadFromOPort failed %0x\n", result);
543 assert(0);
544 return;
545 }
546 lastReadFrameCnt = readSize/portInfo.frameSize;
547 assert(readSize%portInfo.frameSize == 0);
548
549 packetToSend.m_numFrames = lastReadFrameCnt;
550 packetToSend.m_frameSendIndex = frameSendIndex;
551 packetToSend.setChecksum(readSize);
552 }
553 else
554 {
555 readSize = 0;
556 packetToSend.m_numFrames = 0;
557 packetToSend.m_frameSendIndex = frameSendIndex;
558 packetToSend.setChecksum(readSize);
559
560 }
561
562
563 int packetSize = packetToSend.getPacketSize(readSize);
564
565 EnterCriticalSection(&m_csRemoteConnections);
566
567 // send this packet out to all our remote connections
568 for(int rIdx=0;rIdx<m_remoteConnections.size(); rIdx++)
569 {
570 SQRVoiceConnection* pVoice = m_remoteConnections[rIdx];
571 if(pVoice->m_bConnected)
572 m_remoteConnections[rIdx]->SendInternal(&packetToSend, packetSize);
573 }
574
575 LeaveCriticalSection(&m_csRemoteConnections);
576 }
577 m_forceSendPacket = false;
578}
579
580bool g_bPlaying = false;
581
582void SonyVoiceChat_Vita::playAllReceivedData()
583{
584 EnterCriticalSection(&m_csRemoteConnections);
585 // write all the incoming data from the network to each of the input voices
586 for(int rIdx=0;rIdx<m_remoteConnections.size(); rIdx++)
587 {
588 SQRVoiceConnection* pVoice = m_remoteConnections[rIdx];
589 VoicePacket packet;
590 while(pVoice->getNextPacket(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
591 {
592 int frameGap;
593 if (pVoice->m_nextExpectedFrameIndex == packet.m_frameSendIndex)
594 {
595 // no voice frame drop, continuous frames
596 frameGap = 0;
597 if(sc_verbose)
598 app.DebugPrintf("index@%d gets expected frame\n",pVoice->m_nextExpectedFrameIndex);
599 pVoice->m_nextExpectedFrameIndex = packet.m_frameSendIndex + packet.m_numFrames;
600 }
601 else if (pVoice->m_nextExpectedFrameIndex < packet.m_frameSendIndex)
602 {
603 // has voice frame drop, dropped forwarding frames
604 frameGap = packet.m_frameSendIndex - pVoice->m_nextExpectedFrameIndex;
605 if(sc_verbose)
606 app.DebugPrintf("index@%d gets dropped forwarding frames %d\n",pVoice->m_nextExpectedFrameIndex, frameGap);
607 pVoice->m_nextExpectedFrameIndex = packet.m_frameSendIndex + packet.m_numFrames;
608 }
609 else if (pVoice->m_nextExpectedFrameIndex > packet.m_frameSendIndex)
610 {
611 // has voice frame drop, dropped preceding frames, no reset on pVoice->m_nextExpectedFrameIndex
612 frameGap = packet.m_frameSendIndex - pVoice->m_nextExpectedFrameIndex;
613 if(sc_verbose)
614 app.DebugPrintf("index@%d gets dropped forwarding frames %d\n", pVoice->m_nextExpectedFrameIndex, frameGap);
615 }
616
617 SceVoiceBasePortInfo portInfo;
618 int result = sceVoiceGetPortInfo(pVoice->m_voiceInPort, &portInfo );
619 if (result != SCE_OK)
620 {
621 if(sc_verbose)
622 app.DebugPrintf("sceVoiceGetPortInfo LoopbackVoiceInPort failed %x\n", result);
623 assert(0);
624 LeaveCriticalSection(&m_csRemoteConnections);
625 return;
626 }
627 uint32_t writeSize = packet.m_numFrames * portInfo.frameSize;
628 int inputPortBytes = portInfo.numByte;
629 inputPortBytes = (inputPortBytes>writeSize)?writeSize:inputPortBytes;
630 writeSize = inputPortBytes;
631 result = sceVoiceWriteToIPort(pVoice->m_voiceInPort, packet.m_data, &writeSize, frameGap);
632 if (result != SCE_OK)
633 {
634 if(sc_verbose)
635 app.DebugPrintf("sceVoiceWriteToIPort failed %0x\n", result);
636 assert(0);
637 LeaveCriticalSection(&m_csRemoteConnections);
638 return;
639 }
640 if (writeSize != inputPortBytes)
641 {
642 // libvoice internal voice in port buffer fulls
643 if(sc_verbose)
644 app.DebugPrintf("internal voice in port buffer fulls. \n");
645 }
646 packet.m_numFrames = 0;
647
648 // copy the flags
649 for(int flagIndex=0;flagIndex<MAX_LOCAL_PLAYER_COUNT;flagIndex++)
650 pVoice->m_remotePlayerFlags[flagIndex] = packet.m_localPlayerFlags[flagIndex];
651 }
652 }
653 LeaveCriticalSection(&m_csRemoteConnections);
654
655}
656
657void SonyVoiceChat_Vita::tick()
658{
659 if(m_bInitialised)
660 {
661// DWORD tick = GetTickCount();
662// static DWORD lastTick = 0;
663// app.DebugPrintf("Time since last voice tick : %d ms\n", tick - lastTick);
664// lastTick = tick;
665 g_frameNum++;
666 sendAllVoiceData();
667 playAllReceivedData();
668
669 EnterCriticalSection(&m_csRemoteConnections);
670
671 for(int i=m_remoteConnections.size()-1;i>=0;i--)
672 {
673 if(m_remoteConnections[i]->m_bFlaggedForShutdown)
674 {
675 delete m_remoteConnections[i];
676 m_remoteConnections.erase(m_remoteConnections.begin() + i);
677 }
678 }
679
680 LeaveCriticalSection(&m_csRemoteConnections);
681
682 }
683}
684
685
686
687bool SonyVoiceChat_Vita::hasMicConnected(SQRNetworkPlayer* pNetPlayer)
688{
689 if(CGameNetworkManager::usingAdhocMode()) // no voice chat in adhoc
690 return false;
691
692 if(pNetPlayer->IsLocal())
693 {
694 return m_localPlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bHasMicConnected;
695 }
696 else
697 {
698 EnterCriticalSection(&m_csRemoteConnections);
699 for(int i=0;i<m_remoteConnections.size();i++)
700 {
701 SQRVoiceConnection* pVoice = m_remoteConnections[i];
702 if(pVoice->m_remoteRoomMemberId == pNetPlayer->m_roomMemberId)
703 {
704 bool bMicConnected = pVoice->m_remotePlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bHasMicConnected;
705 LeaveCriticalSection(&m_csRemoteConnections);
706 return bMicConnected;
707 }
708 }
709 LeaveCriticalSection(&m_csRemoteConnections);
710 }
711 // if we get here we've not found the player, panic!!
712 assert(0);
713 return false;
714}
715
716void SonyVoiceChat_Vita::mute( bool bMute )
717{
718}
719
720void SonyVoiceChat_Vita::mutePlayer( const SceNpMatching2RoomMemberId member_id, bool bMute ) /*Turn chat audio from a specified player on or off */
721{
722}
723
724void SonyVoiceChat_Vita::muteLocalPlayer( bool bMute ) /*Turn microphone input on or off */
725{
726}
727
728bool SonyVoiceChat_Vita::isMuted()
729{
730 return false;
731}
732
733bool SonyVoiceChat_Vita::isMutedPlayer( const PlayerUID& memberUID)
734{
735 return false;
736}
737
738bool SonyVoiceChat_Vita::isMutedLocalPlayer()
739{
740 return false;
741}
742
743
744bool SonyVoiceChat_Vita::isTalking(SQRNetworkPlayer* pNetPlayer)
745{
746 if(CGameNetworkManager::usingAdhocMode()) // no voice chat in adhoc
747 return false;
748
749 if(pNetPlayer->IsLocal())
750 {
751 return m_localPlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bTalking;
752 }
753 else
754 {
755 EnterCriticalSection(&m_csRemoteConnections);
756 for(int i=0;i<m_remoteConnections.size();i++)
757 {
758 SQRVoiceConnection* pVoice = m_remoteConnections[i];
759 if(pVoice->m_remoteRoomMemberId == pNetPlayer->m_roomMemberId)
760 {
761 bool bTalking = pVoice->m_remotePlayerFlags[pNetPlayer->GetLocalPlayerIndex()].m_bTalking;
762 LeaveCriticalSection(&m_csRemoteConnections);
763 return bTalking;
764 }
765 }
766 LeaveCriticalSection(&m_csRemoteConnections);
767 }
768 // if we get here we've not found the player, panic!!
769 assert(0);
770 return false;
771}
772
773
774void SQRLocalVoiceDevice::init(bool bChatRestricted)
775{
776 SceVoiceInitParam params;
777 SceVoicePortParam portArgs;
778
779 int returnCode = 0;
780 m_bChatRestricted = bChatRestricted;
781
782 portArgs.portType = SCEVOICE_PORTTYPE_IN_DEVICE;
783 portArgs.bMute = false;
784 portArgs.threshold = 0;
785 portArgs.volume = 1.0f;
786 portArgs.device.playerId = 0;
787// portArgs.device.type = SCE_AUDIO_IN_TYPE_VOICE;
788// portArgs.device.index = 0;
789 CreatePort( &m_microphonePort, &portArgs );
790// m_micAudioDevicePort = sceAudioInOpen(localUserID,
791// SCE_AUDIO_IN_TYPE_VOICE, 0,
792// SCE_AUDIO_IN_GRAIN_DEFAULT,
793// SCE_AUDIO_IN_FREQ_DEFAULT,
794// SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO);
795// assert(m_micAudioDevicePort >= 0);
796
797 portArgs.portType = SCEVOICE_PORTTYPE_OUT_DEVICE;
798 portArgs.bMute = false;
799 portArgs.threshold = 0;
800 portArgs.volume = 1.0f;
801 portArgs.device.playerId = 0;
802// portArgs.device.type = SCE_AUDIO_OUT_PORT_TYPE_VOICE;
803// portArgs.device.index = 0;
804 CreatePort( &m_headsetPort, &portArgs );
805
806 m_bValid = true;
807
808}
809
810
811
812void SQRLocalVoiceDevice::shutdown()
813{
814
815 assert(isValid());
816 m_bValid = false;
817 DeletePort(m_microphonePort);
818 DeletePort(m_headsetPort);
819// int err = sceAudioInClose(m_micAudioDevicePort);
820// assert(err == SCE_OK);
821// m_micAudioDevicePort = -1;
822}
823
824
825
826SQRVoiceConnection* SonyVoiceChat_Vita::addRemoteConnection( int RudpCxt, SceNpMatching2RoomMemberId peerMemberId)
827{
828 EnterCriticalSection(&m_csRemoteConnections);
829 SQRVoiceConnection* pConn = new SQRVoiceConnection(RudpCxt, peerMemberId);
830 m_remoteConnections.push_back(pConn);
831 m_forceSendPacket = true; // new connection, so we'll force a packet through for the flags
832 LeaveCriticalSection(&m_csRemoteConnections);
833
834 return pConn;
835}
836
837void SonyVoiceChat_Vita::connectPorts(uint32_t inPort, uint32_t outPort)
838{
839 int returnCode = sceVoiceConnectIPortToOPort(inPort, outPort);
840 if (returnCode != SCE_OK )
841 {
842 app.DebugPrintf("sceVoiceConnectIPortToOPort failed (0x%08x), inPort 0x%08x, outPort 0x%08x\n", returnCode, inPort, outPort);
843 assert(0);
844 }
845}
846void SonyVoiceChat_Vita::disconnectPorts(uint32_t inPort, uint32_t outPort)
847{
848 int returnCode = sceVoiceDisconnectIPortFromOPort(inPort, outPort);
849 if (returnCode != SCE_OK )
850 {
851 app.DebugPrintf("sceVoiceDisconnectIPortFromOPort failed (0x%08x), inPort 0x%08x, outPort 0x%08x\n", returnCode, inPort, outPort);
852 assert(0);
853 }
854}
855
856
857void SonyVoiceChat_Vita::makeLocalConnections()
858{
859 // connect all mics to other devices headsets, for local chat
860 for(int i=0;i<MAX_LOCAL_PLAYER_COUNT;i++)
861 {
862 SQRLocalVoiceDevice* pConnectFrom = &m_localVoiceDevices[i];
863 if(pConnectFrom->isValid())
864 {
865 for(int j=0;j<MAX_LOCAL_PLAYER_COUNT;j++)
866 {
867 SQRLocalVoiceDevice* pConnectTo = &m_localVoiceDevices[j];
868 if( (pConnectFrom!=pConnectTo) && pConnectTo->isValid())
869 {
870 if(pConnectFrom->m_localConnections[j] == false)
871 {
872 if(pConnectTo->m_bChatRestricted == false && pConnectFrom->m_bChatRestricted == false)
873 {
874 connectPorts(pConnectFrom->m_microphonePort, pConnectTo->m_headsetPort);
875 pConnectFrom->m_localConnections[j] = true;
876 }
877 }
878 }
879 }
880 }
881 }
882}
883
884void SonyVoiceChat_Vita::breakLocalConnections(int playerIdx)
885{
886 // break any connections with devices that are no longer valid
887 for(int i=0;i<MAX_LOCAL_PLAYER_COUNT;i++)
888 {
889 SQRLocalVoiceDevice* pConnectedFrom = &m_localVoiceDevices[i];
890 for(int j=0;j<MAX_LOCAL_PLAYER_COUNT;j++)
891 {
892 if(pConnectedFrom->m_localConnections[j] == true)
893 {
894 SQRLocalVoiceDevice* pConnectedTo = &m_localVoiceDevices[j];
895 if(i==playerIdx || j==playerIdx)
896 {
897 if(pConnectedTo->m_bChatRestricted == false && pConnectedFrom->m_bChatRestricted == false)
898 {
899 disconnectPorts(pConnectedFrom->m_microphonePort, pConnectedTo->m_headsetPort);
900 pConnectedFrom->m_localConnections[j] = false;
901 }
902 }
903 }
904 }
905 }
906}
907
908
909void SonyVoiceChat_Vita::initLocalPlayer(int playerIndex)
910{
911 if(m_localVoiceDevices[playerIndex].isValid() == false)
912 {
913 bool chatRestricted = false;
914 ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&chatRestricted,NULL,NULL);
915
916 // create all device ports required
917 m_localVoiceDevices[playerIndex].init(chatRestricted);
918 m_numLocalDevicesConnected++;
919 if(m_localVoiceDevices[playerIndex].m_bChatRestricted == false)
920 {
921 connectPorts(m_localVoiceDevices[playerIndex].m_microphonePort, m_voiceOutPort);
922 }
923 m_forceSendPacket = true; // new local device, so we'll force a packet through for the flags
924
925 }
926 makeLocalConnections();
927}
928
929void SonyVoiceChat_Vita::connectPlayer(SQRVoiceConnection* pConnection, int playerIndex)
930{
931 if((pConnection->m_headsetConnectionMask & (1 << playerIndex)) == 0)
932 {
933 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)
934 if(m_localVoiceDevices[playerIndex].m_bChatRestricted == false)
935 {
936 connectPorts(pConnection->m_voiceInPort, m_localVoiceDevices[playerIndex].m_headsetPort);
937 }
938 pConnection->m_headsetConnectionMask |= (1 << playerIndex);
939 app.DebugPrintf("Connecting player %d to rudp context %d\n", playerIndex, pConnection->m_rudpCtx);
940 m_forceSendPacket = true; // new connection, so we'll force a packet through for the flags
941 }
942}
943
944SQRVoiceConnection* SonyVoiceChat_Vita::GetVoiceConnectionFromRudpCtx( int RudpCtx )
945{
946 for(int i=0;i<m_remoteConnections.size();i++)
947 {
948 if(m_remoteConnections[i]->m_rudpCtx == RudpCtx)
949 return m_remoteConnections[i];
950 }
951 return NULL;
952}
953
954void SonyVoiceChat_Vita::connectPlayerToAll( int playerIndex )
955{
956 EnterCriticalSection(&m_csRemoteConnections);
957
958 for(int i=0;i<m_remoteConnections.size();i++)
959 {
960 SonyVoiceChat_Vita::connectPlayer(m_remoteConnections[i], playerIndex);
961 }
962
963 LeaveCriticalSection(&m_csRemoteConnections);
964}
965
966SQRVoiceConnection* SonyVoiceChat_Vita::getVoiceConnectionFromRoomMemberID( SceNpMatching2RoomMemberId roomMemberID )
967{
968 for(int i=0;i<m_remoteConnections.size();i++)
969 {
970 if(m_remoteConnections[i]->m_remoteRoomMemberId == roomMemberID)
971 {
972 return m_remoteConnections[i];
973 }
974 }
975
976 return NULL;
977}
978
979void SonyVoiceChat_Vita::disconnectLocalPlayer( int localIdx )
980{
981 if(m_localVoiceDevices[localIdx].isValid() == false)
982 return;
983
984 EnterCriticalSection(&m_csRemoteConnections);
985
986 if(m_localVoiceDevices[localIdx].m_bChatRestricted == false)
987 {
988 disconnectPorts(m_localVoiceDevices[localIdx].m_microphonePort, m_voiceOutPort);
989
990 for(int i=0;i<m_remoteConnections.size();i++)
991 {
992 disconnectPorts(m_remoteConnections[i]->m_voiceInPort, m_localVoiceDevices[localIdx].m_headsetPort);
993 m_remoteConnections[i]->m_headsetConnectionMask &= (~(1 << localIdx));
994 app.DebugPrintf("disconnecting player %d from rudp context %d\n", localIdx, m_remoteConnections[i]->m_rudpCtx);
995 }
996 }
997 m_numLocalDevicesConnected--;
998
999 if(m_numLocalDevicesConnected == 0) // no more local players, kill all the remote connections
1000 {
1001 for(int i=0;i<m_remoteConnections.size();i++)
1002 {
1003 delete m_remoteConnections[i];
1004 }
1005 m_remoteConnections.clear();
1006 }
1007
1008 LeaveCriticalSection(&m_csRemoteConnections);
1009
1010 breakLocalConnections(localIdx);
1011 m_localVoiceDevices[localIdx].shutdown();
1012}
1013
1014
1015void SonyVoiceChat_Vita::disconnectRemoteConnection( SQRVoiceConnection* pVoice )
1016{
1017 EnterCriticalSection(&m_csRemoteConnections);
1018
1019 int voiceIdx = -1;
1020 for(int i=0;i<m_remoteConnections.size();i++)
1021 {
1022 if(m_remoteConnections[i] == pVoice)
1023 voiceIdx = i;
1024 }
1025 assert(voiceIdx>=0);
1026 if(voiceIdx>=0)
1027 {
1028 m_remoteConnections[voiceIdx]->m_bFlaggedForShutdown = true;
1029 }
1030
1031 LeaveCriticalSection(&m_csRemoteConnections);
1032
1033}
1034
1035void SonyVoiceChat_Vita::setConnected( int RudpCtx )
1036{
1037 SQRVoiceConnection* pVoice = GetVoiceConnectionFromRudpCtx(RudpCtx);
1038 if(pVoice)
1039 {
1040 pVoice->m_bConnected = true;
1041 m_forceSendPacket = true;
1042 }
1043 else
1044 {
1045 assert(false);
1046 }
1047}
1048
1049
1050
1051
1052RingBuffer::RingBuffer( int sizeBytes )
1053{
1054 buffer = new char[sizeBytes];
1055 buf_size = sizeBytes;
1056 buf_full = buf_free = 0;
1057}
1058
1059
1060int RingBuffer::Write( char* data, int len_ )
1061{
1062 if (len_ <= 0) return len_;
1063 unsigned int len = (unsigned int)len_;
1064 unsigned int data_size = buf_size - (buf_free - buf_full);
1065 if (len > data_size)
1066 len = data_size;
1067 data_size = buf_size - (buf_free % buf_size);
1068 if (data_size > len)
1069 data_size = len;
1070 memcpy(buffer + (buf_free % buf_size), data, data_size);
1071 if (data_size != len)
1072 memcpy(buffer, data + data_size, len - data_size);
1073 buf_free += len;
1074 return len;
1075}
1076
1077int RingBuffer::Read( char* data, int max_bytes_ )
1078{
1079 if (max_bytes_ <= 0) return max_bytes_;
1080 unsigned int max_bytes = (unsigned int)max_bytes_;
1081 unsigned int result = buf_free - buf_full;
1082 if (result > max_bytes)
1083 result = max_bytes;
1084 unsigned int chunk = buf_size - (buf_full % buf_size);
1085 if (chunk > result)
1086 chunk = result;
1087 memcpy(data, buffer + (buf_full % buf_size), chunk);
1088 if (chunk != result)
1089 memcpy(data + chunk, buffer, result - chunk);
1090 buf_full += result;
1091 return result;
1092}