// inputBuffer and outputBuffer is an array of SAMPLE of count framesPerBuffer // A sample is one unit of sound. // The sample rate is the number of sound samples taken per second // I think one frame is a set of samples equal to the number of channels. I'm not sure though or how that sample is arranged. static int PACallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { if (inputBuffer && !mute) { // TODO - if the input data is mostly silence, don't send and save the bandwidth. #ifndef _TEST_LOOPBACK unsigned i; for (i=0; i < rakPeer->GetMaximumNumberOfPeers(); i++) { rakVoice.SendFrame(rakPeer->GetGUIDFromIndex(i), inputBuffer); } #else rakVoice.SendFrame(RakNet::UNASSIGNED_SYSTEM_ADDRESS, inputBuffer); #endif } rakVoice.ReceiveFrame(outputBuffer); return 0; }
// Prints the current encoder parameters void PrintParameters(void) { printf("\nComplexity=%3d Noise filter=%3s VAD=%3s VBR=%3s\n" ,rakVoice.GetEncoderComplexity() ,(rakVoice.IsNoiseFilterActive()) ? "ON" : "OFF" ,(rakVoice.IsVADActive()) ? "ON" : "OFF" ,(rakVoice.IsVBRActive()) ? "ON" : "OFF"); }
// Keeps a record of the last 20 calls, to give a faster response to traffic change void LogStats(){ const int numStats = 20; static myStat data[numStats]; for(int i=0; i<=numStats-2; i++){ data[i] = data[i+1]; } RakNet::RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0)); unsigned int currTime = RakNet::GetTimeMS(); data[numStats-1].time = currTime; data[numStats-1].bitsSent = BYTES_TO_BITS(rss->runningTotal[RakNet::USER_MESSAGE_BYTES_SENT]); data[numStats-1].bitsRec = BYTES_TO_BITS(rss->runningTotal[RakNet::USER_MESSAGE_BYTES_RECEIVED_PROCESSED]); float totalTime = (data[numStats-1].time - data[0].time) / 1000.f ; unsigned int totalBitsSent = data[numStats-1].bitsSent - data[0].bitsSent; unsigned int totalBitsRec = data[numStats-1].bitsRec - data[0].bitsRec; float bpsSent = totalBitsSent/totalTime; float bpsRec = totalBitsRec/totalTime; float avgBpsSent = rss->valueOverLastSecond[RakNet::USER_MESSAGE_BYTES_SENT]; float avgBpsRec = rss->valueOverLastSecond[RakNet::USER_MESSAGE_BYTES_RECEIVED_PROCESSED]; printf("avgKbpsSent=%02.1f avgKbpsRec=%02.1f kbpsSent=%02.1f kbpsRec=%02.1f \r", avgBpsSent/1000, avgBpsRec/1000, bpsSent/1000 , bpsRec/1000, rakVoice.GetBufferedBytesToReturn(RakNet::UNASSIGNED_RAKNET_GUID)); //printf("MsgBuf=%6i SndBuf=%10i RcvBuf=%10i \r", rakVoice.GetRakPeerInterface()->GetStatistics(RakNet::UNASSIGNED_SYSTEM_ADDRESS)->messageSendBuffer[HIGH_PRIORITY], rakVoice.GetBufferedBytesToSend(RakNet::UNASSIGNED_SYSTEM_ADDRESS), rakVoice.GetBufferedBytesToReturn(RakNet::UNASSIGNED_SYSTEM_ADDRESS)); }
int main(void) { printf("A sample on how to use RakVoice together with DirectSound.\n"); printf("You need a microphone for this sample.\n"); printf("RakVoice relies on Speex for voice encoding and decoding.\n"); printf("See DependentExtensions/RakVoice/speex-1.2beta3 for speex projects.\n"); printf("For windows, I had to define HAVE_CONFIG_H, include win32/config.h,\n"); printf("and include the files under libspeex, except those that start with test.\n"); printf("Difficulty: Advanced\n\n"); bool mute=false; bool quit; char ch; char port[256]; rakPeer = RakNet::RakPeerInterface::GetInstance(); #if defined(INTERACTIVE) printf("Enter local port: "); Gets(port, sizeof(port)); if (port[0]==0) #endif strcpy(port, "60000"); RakNet::SocketDescriptor socketDescriptor(atoi(port),0); rakPeer->Startup(4, &socketDescriptor, 1); rakPeer->SetMaximumIncomingConnections(4); rakPeer->AttachPlugin(&rakVoice); rakVoice.Init(SAMPLE_RATE, FRAMES_PER_BUFFER*sizeof(SAMPLE)); // Initialize our connection with DirectSound if (!RakNet::DSoundVoiceAdapter::Instance()->SetupAdapter(&rakVoice, GetConsoleHwnd(), DSSCL_EXCLUSIVE)) { printf("An error occurred while initializing DirectSound.\n"); exit(-1); } RakNet::Packet *p; quit=false; #if defined(INTERACTIVE) printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n"); printf("(+/-)encoder complexity. (N)oise filter on/off. (V)AD on/off. (B)vbr on/off.\n"); #else rakPeer->Connect("1.1.1.1", 60000, 0,0); #endif PrintParameters(); while (!quit) { #if defined(INTERACTIVE) if (kbhit()) { ch=getch(); if (ch=='+'){ // Increase encoder complexity int v = rakVoice.GetEncoderComplexity(); if (v<10) rakVoice.SetEncoderComplexity(v+1); PrintParameters(); } else if (ch=='-'){ // Decrease encoder complexity int v = rakVoice.GetEncoderComplexity(); if (v>0) rakVoice.SetEncoderComplexity(v-1); PrintParameters(); } else if (ch=='n'){ // Turn on/off noise filter rakVoice.SetNoiseFilter(!rakVoice.IsNoiseFilterActive()); PrintParameters(); } else if (ch=='v') { // Turn on/off Voice detection rakVoice.SetVAD(!rakVoice.IsVADActive()); PrintParameters(); } else if (ch=='b') { // Turn on/off VBR rakVoice.SetVBR(!rakVoice.IsVBRActive()); PrintParameters(); } else if (ch=='y') { quit=true; } else if (ch=='c') { char ip[256]; printf("\nEnter IP of remote system: "); Gets(ip, sizeof(ip)); if (ip[0]==0) strcpy(ip, "127.0.0.1"); printf("\nEnter port of remote system: "); Gets(port, sizeof(port)); if (port[0]==0) strcpy(port, "60000"); rakPeer->Connect(ip, atoi(port), 0,0); } else if (ch=='m') { mute=!mute; RakNet::DSoundVoiceAdapter::Instance()->SetMute(mute); if (mute) printf("\nNow muted.\n"); else printf("\nNo longer muted.\n"); } else if (ch=='d') { rakPeer->Shutdown(100,0); } else if (ch==' ') { char message[2048]; RakNet::RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0)); StatisticsToString(rss, message, 2); printf("%s", message); } else if (ch=='q') quit=true; ch=0; } #endif p=rakPeer->Receive(); while (p) { if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED) { printf("\nID_CONNECTION_REQUEST_ACCEPTED from %s\n", p->systemAddress.ToString()); rakVoice.RequestVoiceChannel(p->guid); } else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REQUEST) { printf("\nOpen Channel request from %s\n", p->systemAddress.ToString()); } else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REPLY) { printf("\nGot new channel from %s\n", p->systemAddress.ToString()); } rakPeer->DeallocatePacket(p); p=rakPeer->Receive(); } // Update our connection with DirectSound RakNet::DSoundVoiceAdapter::Instance()->Update(); LogStats(); RakSleep(20); } // Release any FMOD resources we used, and shutdown FMOD itself RakNet::DSoundVoiceAdapter::Instance()->Release(); rakPeer->Shutdown(300); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; }
int main(void) { PortAudioStream *stream; PaError err; mute=false; bool quit; char ch; printf("A sample on how to use RakVoice. You need a microphone for this sample.\n"); printf("RakVoice relies on Speex for voice encoding and decoding.\n"); printf("See DependentExtensions/RakVoice/speex-1.1.12 for speex projects.\n"); printf("For windows, I had to define HAVE_CONFIG_H, include win32/config.h,\n"); printf("and include the files under libspeex, except those that start with test.\n"); printf("PortAudio is also included and is used to read and write audio data. You\n"); printf("can substitute whatever you want if you do not want to use portaudio.\n"); printf("Difficulty: Advanced\n\n"); // Since voice is peer to peer, we give the option to use the nat punchthrough client if desired. RakNet::NatPunchthroughClient natPunchthroughClient; char port[256]; rakPeer = RakNet::RakPeerInterface::GetInstance(); printf("Enter local port (enter for default): "); Gets(port, sizeof(port)); if (port[0]==0) strcpy(port, "60000"); RakNet::SocketDescriptor socketDescriptor(atoi(port),0); rakPeer->Startup(4, &socketDescriptor, 1); rakPeer->SetMaximumIncomingConnections(4); rakPeer->AttachPlugin(&rakVoice); rakPeer->AttachPlugin(&natPunchthroughClient); rakVoice.Init(SAMPLE_RATE, FRAMES_PER_BUFFER*sizeof(SAMPLE)); err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), 1, // Num channels, whatever that means PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), 1, // Num channels PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ 0, /* paDitherOff, // flags */ PACallback, 0 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Support NAT punchthrough? (y/n)? "); bool useNatPunchthrough; useNatPunchthrough=(getche()=='y'); printf("\n"); char facilitatorIP[256]; {//Linux fix. Won't compile without it. Because of the goto error above, the scope is ambigious. Make it a block to define that it will not be used after the jump. //Doesn't change current logic RakNet::SystemAddress facilitator; if (useNatPunchthrough) { printf("My GUID is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString()); printf("Enter IP of facilitator (enter for default): "); Gets(facilitatorIP,sizeof(facilitatorIP)); if (facilitatorIP[0]==0) strcpy(facilitatorIP, "natpunch.jenkinssoftware.com"); facilitator.FromString(facilitatorIP); facilitator.SetPortHostOrder(NAT_PUNCHTHROUGH_FACILITATOR_PORT); rakPeer->Connect(facilitatorIP, NAT_PUNCHTHROUGH_FACILITATOR_PORT, 0, 0); printf("Connecting to facilitator...\n"); } else { printf("Not supporting NAT punchthrough.\n"); } RakNet::Packet *p; quit=false; if (useNatPunchthrough==false) printf("(Q)uit. (C)onnect. (D)isconnect. C(l)ose voice channels. (M)ute. ' ' for stats.\n"); while (!quit) { if (kbhit()) { ch=getch(); if (ch=='y') { quit=true; } else if (ch=='c') { if (useNatPunchthrough) { RakNet::RakNetGUID destination; printf("Enter GUID of destination: "); char guidStr[256]; while (1) { Gets(guidStr,sizeof(guidStr)); if (!destination.FromString(guidStr)) printf("Invalid GUID format. Try again.\nEnter GUID of destination: "); else break; } printf("Starting NAT punch. Please wait...\n"); natPunchthroughClient.OpenNAT(destination,facilitator); } else { char ip[256]; printf("Enter IP of remote system: "); Gets(ip, sizeof(ip)); if (ip[0]==0) strcpy(ip, "127.0.0.1"); printf("Enter port of remote system: "); Gets(port, sizeof(port)); if (port[0]==0) strcpy(port, "60000"); rakPeer->Connect(ip, atoi(port), 0,0); } } else if (ch=='m') { mute=!mute; if (mute) printf("Now muted.\n"); else printf("No longer muted.\n"); } else if (ch=='d') { rakPeer->Shutdown(100,0); } else if (ch=='l') { rakVoice.CloseAllChannels(); } else if (ch==' ') { char message[2048]; RakNet::RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0)); StatisticsToString(rss, message, 2); printf("%s", message); } else if (ch=='q') quit=true; ch=0; } p=rakPeer->Receive(); while (p) { if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED) { if (p->systemAddress==facilitator) { printf("Connection to facilitator completed\n"); printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n"); } else { printf("ID_CONNECTION_REQUEST_ACCEPTED from %s\n", p->systemAddress.ToString()); rakVoice.RequestVoiceChannel(p->guid); } } else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED) { if (p->systemAddress==facilitator) { printf("Connection to facilitator failed. Using direct connections\n"); useNatPunchthrough=false; printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n"); } else { printf("ID_CONNECTION_ATTEMPT_FAILED\n"); } } else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REQUEST || p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REPLY) { printf("Got new channel from %s\n", p->systemAddress.ToString()); } else if (p->data[0]==ID_NAT_TARGET_NOT_CONNECTED) { RakNet::RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_TARGET_NOT_CONNECTED for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_TARGET_UNRESPONSIVE) { RakNet::RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_TARGET_UNRESPONSIVE for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST) { RakNet::RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_CONNECTION_TO_TARGET_LOST for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_ALREADY_IN_PROGRESS) { RakNet::RakNetGUID g; RakNet::BitStream b(p->data, p->length, false); b.IgnoreBits(8); // Ignore the ID_... b.Read(g); printf("ID_NAT_ALREADY_IN_PROGRESS for %s\n", g.ToString()); } else if (p->data[0]==ID_NAT_PUNCHTHROUGH_FAILED) { printf("ID_NAT_PUNCHTHROUGH_FAILED for %s\n", p->guid.ToString()); } else if (p->data[0]==ID_NAT_PUNCHTHROUGH_SUCCEEDED) { printf("ID_NAT_PUNCHTHROUGH_SUCCEEDED for %s. Connecting...\n", p->guid.ToString()); rakPeer->Connect(p->systemAddress.ToString(false),p->systemAddress.GetPort(),0,0); } else if (p->data[0]==ID_ALREADY_CONNECTED) { printf("ID_ALREADY_CONNECTED\n"); } else if (p->data[0]==ID_RAKVOICE_CLOSE_CHANNEL) { printf("ID_RAKVOICE_CLOSE_CHANNEL\n"); } else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION) { printf("ID_DISCONNECTION_NOTIFICATION\n"); } else if (p->data[0]==ID_NEW_INCOMING_CONNECTION) { printf("ID_NEW_INCOMING_CONNECTION\n"); } else { printf("Unknown packet ID %i\n", p->data[0]); } rakPeer->DeallocatePacket(p); p=rakPeer->Receive(); } Pa_Sleep( 30 ); } } err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); rakPeer->Shutdown(300); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }