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