PageRenderTime 35ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/examples/voip/Server.cpp

http://github.com/LaurentGomila/SFML
C++ | 200 lines | 109 code | 30 blank | 61 comment | 21 complexity | 607bd9dd5a8409165a6a3134e427c52d MD5 | raw file
  1. ////////////////////////////////////////////////////////////
  2. // Headers
  3. ////////////////////////////////////////////////////////////
  4. #include <SFML/Audio.hpp>
  5. #include <SFML/Network.hpp>
  6. #include <iomanip>
  7. #include <iostream>
  8. #include <iterator>
  9. const sf::Uint8 audioData = 1;
  10. const sf::Uint8 endOfStream = 2;
  11. ////////////////////////////////////////////////////////////
  12. /// Customized sound stream for acquiring audio data
  13. /// from the network
  14. ////////////////////////////////////////////////////////////
  15. class NetworkAudioStream : public sf::SoundStream
  16. {
  17. public:
  18. ////////////////////////////////////////////////////////////
  19. /// Default constructor
  20. ///
  21. ////////////////////////////////////////////////////////////
  22. NetworkAudioStream() :
  23. m_offset (0),
  24. m_hasFinished(false)
  25. {
  26. // Set the sound parameters
  27. initialize(1, 44100);
  28. }
  29. ////////////////////////////////////////////////////////////
  30. /// Run the server, stream audio data from the client
  31. ///
  32. ////////////////////////////////////////////////////////////
  33. void start(unsigned short port)
  34. {
  35. if (!m_hasFinished)
  36. {
  37. // Listen to the given port for incoming connections
  38. if (m_listener.listen(port) != sf::Socket::Done)
  39. return;
  40. std::cout << "Server is listening to port " << port << ", waiting for connections... " << std::endl;
  41. // Wait for a connection
  42. if (m_listener.accept(m_client) != sf::Socket::Done)
  43. return;
  44. std::cout << "Client connected: " << m_client.getRemoteAddress() << std::endl;
  45. // Start playback
  46. play();
  47. // Start receiving audio data
  48. receiveLoop();
  49. }
  50. else
  51. {
  52. // Start playback
  53. play();
  54. }
  55. }
  56. private:
  57. ////////////////////////////////////////////////////////////
  58. /// /see SoundStream::OnGetData
  59. ///
  60. ////////////////////////////////////////////////////////////
  61. virtual bool onGetData(sf::SoundStream::Chunk& data)
  62. {
  63. // We have reached the end of the buffer and all audio data have been played: we can stop playback
  64. if ((m_offset >= m_samples.size()) && m_hasFinished)
  65. return false;
  66. // No new data has arrived since last update: wait until we get some
  67. while ((m_offset >= m_samples.size()) && !m_hasFinished)
  68. sf::sleep(sf::milliseconds(10));
  69. // Copy samples into a local buffer to avoid synchronization problems
  70. // (don't forget that we run in two separate threads)
  71. {
  72. sf::Lock lock(m_mutex);
  73. m_tempBuffer.assign(m_samples.begin() + m_offset, m_samples.end());
  74. }
  75. // Fill audio data to pass to the stream
  76. data.samples = &m_tempBuffer[0];
  77. data.sampleCount = m_tempBuffer.size();
  78. // Update the playing offset
  79. m_offset += m_tempBuffer.size();
  80. return true;
  81. }
  82. ////////////////////////////////////////////////////////////
  83. /// /see SoundStream::OnSeek
  84. ///
  85. ////////////////////////////////////////////////////////////
  86. virtual void onSeek(sf::Time timeOffset)
  87. {
  88. m_offset = timeOffset.asMilliseconds() * getSampleRate() * getChannelCount() / 1000;
  89. }
  90. ////////////////////////////////////////////////////////////
  91. /// Get audio data from the client until playback is stopped
  92. ///
  93. ////////////////////////////////////////////////////////////
  94. void receiveLoop()
  95. {
  96. while (!m_hasFinished)
  97. {
  98. // Get waiting audio data from the network
  99. sf::Packet packet;
  100. if (m_client.receive(packet) != sf::Socket::Done)
  101. break;
  102. // Extract the message ID
  103. sf::Uint8 id;
  104. packet >> id;
  105. if (id == audioData)
  106. {
  107. // Extract audio samples from the packet, and append it to our samples buffer
  108. const sf::Int16* samples = reinterpret_cast<const sf::Int16*>(static_cast<const char*>(packet.getData()) + 1);
  109. std::size_t sampleCount = (packet.getDataSize() - 1) / sizeof(sf::Int16);
  110. // Don't forget that the other thread can access the sample array at any time
  111. // (so we protect any operation on it with the mutex)
  112. {
  113. sf::Lock lock(m_mutex);
  114. std::copy(samples, samples + sampleCount, std::back_inserter(m_samples));
  115. }
  116. }
  117. else if (id == endOfStream)
  118. {
  119. // End of stream reached: we stop receiving audio data
  120. std::cout << "Audio data has been 100% received!" << std::endl;
  121. m_hasFinished = true;
  122. }
  123. else
  124. {
  125. // Something's wrong...
  126. std::cout << "Invalid packet received..." << std::endl;
  127. m_hasFinished = true;
  128. }
  129. }
  130. }
  131. ////////////////////////////////////////////////////////////
  132. // Member data
  133. ////////////////////////////////////////////////////////////
  134. sf::TcpListener m_listener;
  135. sf::TcpSocket m_client;
  136. sf::Mutex m_mutex;
  137. std::vector<sf::Int16> m_samples;
  138. std::vector<sf::Int16> m_tempBuffer;
  139. std::size_t m_offset;
  140. bool m_hasFinished;
  141. };
  142. ////////////////////////////////////////////////////////////
  143. /// Launch a server and wait for incoming audio data from
  144. /// a connected client
  145. ///
  146. ////////////////////////////////////////////////////////////
  147. void doServer(unsigned short port)
  148. {
  149. // Build an audio stream to play sound data as it is received through the network
  150. NetworkAudioStream audioStream;
  151. audioStream.start(port);
  152. // Loop until the sound playback is finished
  153. while (audioStream.getStatus() != sf::SoundStream::Stopped)
  154. {
  155. // Leave some CPU time for other threads
  156. sf::sleep(sf::milliseconds(100));
  157. }
  158. std::cin.ignore(10000, '\n');
  159. // Wait until the user presses 'enter' key
  160. std::cout << "Press enter to replay the sound..." << std::endl;
  161. std::cin.ignore(10000, '\n');
  162. // Replay the sound (just to make sure replaying the received data is OK)
  163. audioStream.play();
  164. // Loop until the sound playback is finished
  165. while (audioStream.getStatus() != sf::SoundStream::Stopped)
  166. {
  167. // Leave some CPU time for other threads
  168. sf::sleep(sf::milliseconds(100));
  169. }
  170. }