main.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <memory.h>
  13. #include "portaudio.h"
  14. #include "Kbhit.h"
  15. #include "RakPeerInterface.h"
  16. #include "MessageIdentifiers.h"
  17. #include "RakVoice.h"
  18. #include "RakNetStatistics.h"
  19. #include "NatPunchthroughClient.h"
  20. #include "BitStream.h"
  21. #include "Getche.h"
  22. #include "Gets.h"
  23. /// To test sending to myself. Also uncomment in RakVoice.cpp
  24. //#define _TEST_LOOPBACK
  25. // RakVoice only works with 16-bits sound data
  26. #define PA_SAMPLE_TYPE paInt16
  27. typedef short SAMPLE;
  28. // Reads and writes per second of the sound data
  29. // Speex only supports these 3 values
  30. #define SAMPLE_RATE (8000)
  31. //#define SAMPLE_RATE (16000)
  32. //#define SAMPLE_RATE (32000)
  33. RakNet::RakPeerInterface *rakPeer;
  34. // I think one buffer has to be full (of samples) before you hear the sound.
  35. // So higher frames per buffer means that there will be a larger latency before you hear the sound
  36. // However, it would lock and unlock the buffer more often, hindering performance.
  37. #define FRAMES_PER_BUFFER (2048 / (32000 / SAMPLE_RATE))
  38. bool mute;
  39. RakNet::RakVoice rakVoice;
  40. // inputBuffer and outputBuffer is an array of SAMPLE of count framesPerBuffer
  41. // A sample is one unit of sound.
  42. // The sample rate is the number of sound samples taken per second
  43. // 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.
  44. static int PACallback( void *inputBuffer, void *outputBuffer,
  45. unsigned long framesPerBuffer,
  46. PaTimestamp outTime, void *userData )
  47. {
  48. if (inputBuffer && !mute)
  49. {
  50. // TODO - if the input data is mostly silence, don't send and save the bandwidth.
  51. #ifndef _TEST_LOOPBACK
  52. unsigned i;
  53. for (i=0; i < rakPeer->GetMaximumNumberOfPeers(); i++)
  54. {
  55. rakVoice.SendFrame(rakPeer->GetGUIDFromIndex(i), inputBuffer);
  56. }
  57. #else
  58. rakVoice.SendFrame(RakNet::UNASSIGNED_SYSTEM_ADDRESS, inputBuffer);
  59. #endif
  60. }
  61. rakVoice.ReceiveFrame(outputBuffer);
  62. return 0;
  63. }
  64. #define NAT_PUNCHTHROUGH_FACILITATOR_PORT 61111
  65. int main(void)
  66. {
  67. PortAudioStream *stream;
  68. PaError err;
  69. mute=false;
  70. bool quit;
  71. char ch;
  72. printf("A sample on how to use RakVoice. You need a microphone for this sample.\n");
  73. printf("RakVoice relies on Speex for voice encoding and decoding.\n");
  74. printf("See DependentExtensions/RakVoice/speex-1.1.12 for speex projects.\n");
  75. printf("For windows, I had to define HAVE_CONFIG_H, include win32/config.h,\n");
  76. printf("and include the files under libspeex, except those that start with test.\n");
  77. printf("PortAudio is also included and is used to read and write audio data. You\n");
  78. printf("can substitute whatever you want if you do not want to use portaudio.\n");
  79. printf("Difficulty: Advanced\n\n");
  80. // Since voice is peer to peer, we give the option to use the nat punchthrough client if desired.
  81. RakNet::NatPunchthroughClient natPunchthroughClient;
  82. char port[256];
  83. rakPeer = RakNet::RakPeerInterface::GetInstance();
  84. printf("Enter local port (enter for default): ");
  85. Gets(port, sizeof(port));
  86. if (port[0]==0)
  87. strcpy(port, "60000");
  88. RakNet::SocketDescriptor socketDescriptor(atoi(port),0);
  89. rakPeer->Startup(4, &socketDescriptor, 1);
  90. rakPeer->SetMaximumIncomingConnections(4);
  91. rakPeer->AttachPlugin(&rakVoice);
  92. rakPeer->AttachPlugin(&natPunchthroughClient);
  93. rakVoice.Init(SAMPLE_RATE, FRAMES_PER_BUFFER*sizeof(SAMPLE));
  94. err = Pa_Initialize();
  95. if( err != paNoError ) goto error;
  96. err = Pa_OpenStream(
  97. &stream,
  98. Pa_GetDefaultInputDeviceID(),
  99. 1, // Num channels, whatever that means
  100. PA_SAMPLE_TYPE,
  101. NULL,
  102. Pa_GetDefaultOutputDeviceID(),
  103. 1, // Num channels
  104. PA_SAMPLE_TYPE,
  105. NULL,
  106. SAMPLE_RATE,
  107. FRAMES_PER_BUFFER, /* frames per buffer */
  108. 0, /* number of buffers, if zero then use default minimum */
  109. 0, /* paDitherOff, // flags */
  110. PACallback,
  111. 0 );
  112. if( err != paNoError ) goto error;
  113. err = Pa_StartStream( stream );
  114. if( err != paNoError ) goto error;
  115. printf("Support NAT punchthrough? (y/n)? ");
  116. bool useNatPunchthrough;
  117. useNatPunchthrough=(getche()=='y');
  118. printf("\n");
  119. char facilitatorIP[256];
  120. {//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.
  121. //Doesn't change current logic
  122. RakNet::SystemAddress facilitator;
  123. if (useNatPunchthrough)
  124. {
  125. printf("My GUID is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
  126. printf("Enter IP of facilitator (enter for default): ");
  127. Gets(facilitatorIP,sizeof(facilitatorIP));
  128. if (facilitatorIP[0]==0)
  129. strcpy(facilitatorIP, "natpunch.jenkinssoftware.com");
  130. facilitator.FromString(facilitatorIP);
  131. facilitator.SetPortHostOrder(NAT_PUNCHTHROUGH_FACILITATOR_PORT);
  132. rakPeer->Connect(facilitatorIP, NAT_PUNCHTHROUGH_FACILITATOR_PORT, 0, 0);
  133. printf("Connecting to facilitator...\n");
  134. }
  135. else
  136. {
  137. printf("Not supporting NAT punchthrough.\n");
  138. }
  139. RakNet::Packet *p;
  140. quit=false;
  141. if (useNatPunchthrough==false)
  142. printf("(Q)uit. (C)onnect. (D)isconnect. C(l)ose voice channels. (M)ute. ' ' for stats.\n");
  143. while (!quit)
  144. {
  145. if (kbhit())
  146. {
  147. ch=getch();
  148. if (ch=='y')
  149. {
  150. quit=true;
  151. }
  152. else if (ch=='c')
  153. {
  154. if (useNatPunchthrough)
  155. {
  156. RakNet::RakNetGUID destination;
  157. printf("Enter GUID of destination: ");
  158. char guidStr[256];
  159. while (1)
  160. {
  161. Gets(guidStr,sizeof(guidStr));
  162. if (!destination.FromString(guidStr))
  163. printf("Invalid GUID format. Try again.\nEnter GUID of destination: ");
  164. else
  165. break;
  166. }
  167. printf("Starting NAT punch. Please wait...\n");
  168. natPunchthroughClient.OpenNAT(destination,facilitator);
  169. }
  170. else
  171. {
  172. char ip[256];
  173. printf("Enter IP of remote system: ");
  174. Gets(ip, sizeof(ip));
  175. if (ip[0]==0)
  176. strcpy(ip, "127.0.0.1");
  177. printf("Enter port of remote system: ");
  178. Gets(port, sizeof(port));
  179. if (port[0]==0)
  180. strcpy(port, "60000");
  181. rakPeer->Connect(ip, atoi(port), 0,0);
  182. }
  183. }
  184. else if (ch=='m')
  185. {
  186. mute=!mute;
  187. if (mute)
  188. printf("Now muted.\n");
  189. else
  190. printf("No longer muted.\n");
  191. }
  192. else if (ch=='d')
  193. {
  194. rakPeer->Shutdown(100,0);
  195. }
  196. else if (ch=='l')
  197. {
  198. rakVoice.CloseAllChannels();
  199. }
  200. else if (ch==' ')
  201. {
  202. char message[2048];
  203. RakNet::RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0));
  204. StatisticsToString(rss, message, 2);
  205. printf("%s", message);
  206. }
  207. else if (ch=='q')
  208. quit=true;
  209. ch=0;
  210. }
  211. p=rakPeer->Receive();
  212. while (p)
  213. {
  214. if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
  215. {
  216. if (p->systemAddress==facilitator)
  217. {
  218. printf("Connection to facilitator completed\n");
  219. printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n");
  220. }
  221. else
  222. {
  223. printf("ID_CONNECTION_REQUEST_ACCEPTED from %s\n", p->systemAddress.ToString());
  224. rakVoice.RequestVoiceChannel(p->guid);
  225. }
  226. }
  227. else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED)
  228. {
  229. if (p->systemAddress==facilitator)
  230. {
  231. printf("Connection to facilitator failed. Using direct connections\n");
  232. useNatPunchthrough=false;
  233. printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n");
  234. }
  235. else
  236. {
  237. printf("ID_CONNECTION_ATTEMPT_FAILED\n");
  238. }
  239. }
  240. else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REQUEST || p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REPLY)
  241. {
  242. printf("Got new channel from %s\n", p->systemAddress.ToString());
  243. }
  244. else if (p->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
  245. {
  246. RakNet::RakNetGUID g;
  247. RakNet::BitStream b(p->data, p->length, false);
  248. b.IgnoreBits(8); // Ignore the ID_...
  249. b.Read(g);
  250. printf("ID_NAT_TARGET_NOT_CONNECTED for %s\n", g.ToString());
  251. }
  252. else if (p->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
  253. {
  254. RakNet::RakNetGUID g;
  255. RakNet::BitStream b(p->data, p->length, false);
  256. b.IgnoreBits(8); // Ignore the ID_...
  257. b.Read(g);
  258. printf("ID_NAT_TARGET_UNRESPONSIVE for %s\n", g.ToString());
  259. }
  260. else if (p->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
  261. {
  262. RakNet::RakNetGUID g;
  263. RakNet::BitStream b(p->data, p->length, false);
  264. b.IgnoreBits(8); // Ignore the ID_...
  265. b.Read(g);
  266. printf("ID_NAT_CONNECTION_TO_TARGET_LOST for %s\n", g.ToString());
  267. }
  268. else if (p->data[0]==ID_NAT_ALREADY_IN_PROGRESS)
  269. {
  270. RakNet::RakNetGUID g;
  271. RakNet::BitStream b(p->data, p->length, false);
  272. b.IgnoreBits(8); // Ignore the ID_...
  273. b.Read(g);
  274. printf("ID_NAT_ALREADY_IN_PROGRESS for %s\n", g.ToString());
  275. }
  276. else if (p->data[0]==ID_NAT_PUNCHTHROUGH_FAILED)
  277. {
  278. printf("ID_NAT_PUNCHTHROUGH_FAILED for %s\n", p->guid.ToString());
  279. }
  280. else if (p->data[0]==ID_NAT_PUNCHTHROUGH_SUCCEEDED)
  281. {
  282. printf("ID_NAT_PUNCHTHROUGH_SUCCEEDED for %s. Connecting...\n", p->guid.ToString());
  283. rakPeer->Connect(p->systemAddress.ToString(false),p->systemAddress.GetPort(),0,0);
  284. }
  285. else if (p->data[0]==ID_ALREADY_CONNECTED)
  286. {
  287. printf("ID_ALREADY_CONNECTED\n");
  288. }
  289. else if (p->data[0]==ID_RAKVOICE_CLOSE_CHANNEL)
  290. {
  291. printf("ID_RAKVOICE_CLOSE_CHANNEL\n");
  292. }
  293. else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
  294. {
  295. printf("ID_DISCONNECTION_NOTIFICATION\n");
  296. }
  297. else if (p->data[0]==ID_NEW_INCOMING_CONNECTION)
  298. {
  299. printf("ID_NEW_INCOMING_CONNECTION\n");
  300. }
  301. else
  302. {
  303. printf("Unknown packet ID %i\n", p->data[0]);
  304. }
  305. rakPeer->DeallocatePacket(p);
  306. p=rakPeer->Receive();
  307. }
  308. Pa_Sleep( 30 );
  309. }
  310. }
  311. err = Pa_CloseStream( stream );
  312. if( err != paNoError ) goto error;
  313. Pa_Terminate();
  314. rakPeer->Shutdown(300);
  315. RakNet::RakPeerInterface::DestroyInstance(rakPeer);
  316. return 0;
  317. error:
  318. Pa_Terminate();
  319. fprintf( stderr, "An error occured while using the portaudio stream\n" );
  320. fprintf( stderr, "Error number: %d\n", err );
  321. fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
  322. return -1;
  323. }
粤ICP备19079148号