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