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 | |
12 | const sf::Uint8 audioData = 1; |
13 | const sf::Uint8 endOfStream = 2; |
14 | |
15 | |
16 | //////////////////////////////////////////////////////////// |
17 | /// Customized sound stream for acquiring audio data |
18 | /// from the network |
19 | //////////////////////////////////////////////////////////// |
20 | class NetworkAudioStream : public sf::SoundStream |
21 | { |
22 | public: |
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 | |
67 | private: |
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 | //////////////////////////////////////////////////////////// |
172 | void 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 | |