OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/win/waveout_output_win.h" | 5 #include "media/audio/win/waveout_output_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <mmsystem.h> | 8 #include <mmsystem.h> |
9 #pragma comment(lib, "winmm.lib") | 9 #pragma comment(lib, "winmm.lib") |
10 | 10 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 UINT device_id) | 80 UINT device_id) |
81 : state_(PCMA_BRAND_NEW), | 81 : state_(PCMA_BRAND_NEW), |
82 manager_(manager), | 82 manager_(manager), |
83 device_id_(device_id), | 83 device_id_(device_id), |
84 waveout_(NULL), | 84 waveout_(NULL), |
85 callback_(NULL), | 85 callback_(NULL), |
86 num_buffers_(num_buffers), | 86 num_buffers_(num_buffers), |
87 buffer_size_(params.GetPacketSize()), | 87 buffer_size_(params.GetPacketSize()), |
88 volume_(1), | 88 volume_(1), |
89 channels_(params.channels), | 89 channels_(params.channels), |
90 pending_bytes_(0) { | 90 pending_bytes_(0), |
| 91 thread_id_(GetCurrentThreadId()) { |
91 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | 92 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; |
92 format_.Format.nChannels = params.channels; | 93 format_.Format.nChannels = params.channels; |
93 format_.Format.nSamplesPerSec = params.sample_rate; | 94 format_.Format.nSamplesPerSec = params.sample_rate; |
94 format_.Format.wBitsPerSample = params.bits_per_sample; | 95 format_.Format.wBitsPerSample = params.bits_per_sample; |
95 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); | 96 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); |
96 // The next are computed from above. | 97 // The next are computed from above. |
97 format_.Format.nBlockAlign = (format_.Format.nChannels * | 98 format_.Format.nBlockAlign = (format_.Format.nChannels * |
98 format_.Format.wBitsPerSample) / 8; | 99 format_.Format.wBitsPerSample) / 8; |
99 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * | 100 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * |
100 format_.Format.nSamplesPerSec; | 101 format_.Format.nSamplesPerSec; |
101 if (params.channels > kMaxChannelsToMask) { | 102 if (params.channels > kMaxChannelsToMask) { |
102 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; | 103 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; |
103 } else { | 104 } else { |
104 format_.dwChannelMask = kChannelsToMask[params.channels]; | 105 format_.dwChannelMask = kChannelsToMask[params.channels]; |
105 } | 106 } |
106 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | 107 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; |
107 format_.Samples.wValidBitsPerSample = params.bits_per_sample; | 108 format_.Samples.wValidBitsPerSample = params.bits_per_sample; |
108 } | 109 } |
109 | 110 |
110 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { | 111 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { |
111 DCHECK(NULL == waveout_); | 112 DCHECK(NULL == waveout_); |
112 } | 113 } |
113 | 114 |
114 bool PCMWaveOutAudioOutputStream::Open() { | 115 bool PCMWaveOutAudioOutputStream::Open() { |
| 116 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
115 if (state_ != PCMA_BRAND_NEW) | 117 if (state_ != PCMA_BRAND_NEW) |
116 return false; | 118 return false; |
117 if (BufferSize() * num_buffers_ > kMaxOpenBufferSize) | 119 if (BufferSize() * num_buffers_ > kMaxOpenBufferSize) |
118 return false; | 120 return false; |
119 if (num_buffers_ < 2 || num_buffers_ > 5) | 121 if (num_buffers_ < 2 || num_buffers_ > 5) |
120 return false; | 122 return false; |
121 | 123 |
122 // Create buffer event. | 124 // Create buffer event. |
123 buffer_event_.Set(::CreateEvent(NULL, // Security attributes. | 125 buffer_event_.Set(::CreateEvent(NULL, // Security attributes. |
124 FALSE, // It will auto-reset. | 126 FALSE, // It will auto-reset. |
(...skipping 13 matching lines...) Expand all Loading... |
138 CALLBACK_EVENT); | 140 CALLBACK_EVENT); |
139 if (result != MMSYSERR_NOERROR) | 141 if (result != MMSYSERR_NOERROR) |
140 return false; | 142 return false; |
141 | 143 |
142 SetupBuffers(); | 144 SetupBuffers(); |
143 state_ = PCMA_READY; | 145 state_ = PCMA_READY; |
144 return true; | 146 return true; |
145 } | 147 } |
146 | 148 |
147 void PCMWaveOutAudioOutputStream::SetupBuffers() { | 149 void PCMWaveOutAudioOutputStream::SetupBuffers() { |
| 150 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
148 buffers_.reset(new char[BufferSize() * num_buffers_]); | 151 buffers_.reset(new char[BufferSize() * num_buffers_]); |
149 for (int ix = 0; ix != num_buffers_; ++ix) { | 152 for (int ix = 0; ix != num_buffers_; ++ix) { |
150 WAVEHDR* buffer = GetBuffer(ix); | 153 WAVEHDR* buffer = GetBuffer(ix); |
151 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR); | 154 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR); |
152 buffer->dwBufferLength = buffer_size_; | 155 buffer->dwBufferLength = buffer_size_; |
153 buffer->dwBytesRecorded = 0; | 156 buffer->dwBytesRecorded = 0; |
154 buffer->dwFlags = WHDR_DONE; | 157 buffer->dwFlags = WHDR_DONE; |
155 buffer->dwLoops = 0; | 158 buffer->dwLoops = 0; |
156 // Tell windows sound drivers about our buffers. Not documented what | 159 // Tell windows sound drivers about our buffers. Not documented what |
157 // this does but we can guess that causes the OS to keep a reference to | 160 // this does but we can guess that causes the OS to keep a reference to |
158 // the memory pages so the driver can use them without worries. | 161 // the memory pages so the driver can use them without worries. |
159 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR)); | 162 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR)); |
160 } | 163 } |
161 } | 164 } |
162 | 165 |
163 void PCMWaveOutAudioOutputStream::FreeBuffers() { | 166 void PCMWaveOutAudioOutputStream::FreeBuffers() { |
| 167 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
164 for (int ix = 0; ix != num_buffers_; ++ix) { | 168 for (int ix = 0; ix != num_buffers_; ++ix) { |
165 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); | 169 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); |
166 } | 170 } |
167 buffers_.reset(NULL); | 171 buffers_.reset(NULL); |
168 } | 172 } |
169 | 173 |
170 // Initially we ask the source to fill up all audio buffers. If we don't do | 174 // Initially we ask the source to fill up all audio buffers. If we don't do |
171 // this then we would always get the driver callback when it is about to run | 175 // this then we would always get the driver callback when it is about to run |
172 // samples and that would leave too little time to react. | 176 // samples and that would leave too little time to react. |
173 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { | 177 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { |
| 178 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
174 if (state_ != PCMA_READY) | 179 if (state_ != PCMA_READY) |
175 return; | 180 return; |
176 callback_ = callback; | 181 callback_ = callback; |
177 | 182 |
178 // Start watching for buffer events. | 183 // Start watching for buffer events. |
179 { | 184 { |
180 HANDLE waiting_handle = NULL; | 185 HANDLE waiting_handle = NULL; |
181 ::RegisterWaitForSingleObject(&waiting_handle, | 186 ::RegisterWaitForSingleObject(&waiting_handle, |
182 buffer_event_.Get(), | 187 buffer_event_.Get(), |
183 &BufferCallback, | 188 &BufferCallback, |
184 this, | 189 this, |
185 INFINITE, | 190 INFINITE, |
186 WT_EXECUTEDEFAULT); | 191 WT_EXECUTEDEFAULT); |
187 if (!waiting_handle) { | 192 if (!waiting_handle) { |
| 193 volatile DWORD code = GetLastError(); |
| 194 CHECK(false); |
188 HandleError(MMSYSERR_ERROR); | 195 HandleError(MMSYSERR_ERROR); |
189 return; | 196 return; |
190 } | 197 } |
191 waiting_handle_.Set(waiting_handle); | 198 waiting_handle_.Set(waiting_handle); |
192 } | 199 } |
193 | 200 |
194 state_ = PCMA_PLAYING; | 201 state_ = PCMA_PLAYING; |
195 | 202 |
196 // Queue the buffers. | 203 // Queue the buffers. |
197 pending_bytes_ = 0; | 204 pending_bytes_ = 0; |
198 for (int ix = 0; ix != num_buffers_; ++ix) { | 205 for (int ix = 0; ix != num_buffers_; ++ix) { |
199 WAVEHDR* buffer = GetBuffer(ix); | 206 WAVEHDR* buffer = GetBuffer(ix); |
200 // Caller waits for 1st packet to become available, but not for others, | 207 // Caller waits for 1st packet to become available, but not for others, |
201 // so we wait for them here. | 208 // so we wait for them here. |
202 if (ix != 0) | 209 if (ix != 0) |
203 callback_->WaitTillDataReady(); | 210 callback_->WaitTillDataReady(); |
204 QueueNextPacket(buffer); // Read more data. | 211 QueueNextPacket(buffer); // Read more data. |
205 pending_bytes_ += buffer->dwBufferLength; | 212 pending_bytes_ += buffer->dwBufferLength; |
206 } | 213 } |
207 | 214 |
208 // From now on |pending_bytes_| would be accessed by callback thread. | 215 // From now on |pending_bytes_| would be accessed by callback thread. |
209 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, | 216 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, |
210 // but issuing our own is safer. | 217 // but issuing our own is safer. |
211 MemoryBarrier(); | 218 MemoryBarrier(); |
212 | 219 |
213 MMRESULT result = ::waveOutPause(waveout_); | 220 MMRESULT result = ::waveOutPause(waveout_); |
214 if (result != MMSYSERR_NOERROR) { | 221 if (result != MMSYSERR_NOERROR) { |
| 222 CHECK(false); |
215 HandleError(result); | 223 HandleError(result); |
216 return; | 224 return; |
217 } | 225 } |
218 | 226 |
219 // Send the buffers to the audio driver. Note that the device is paused | 227 // Send the buffers to the audio driver. Note that the device is paused |
220 // so we avoid entering the callback method while still here. | 228 // so we avoid entering the callback method while still here. |
221 for (int ix = 0; ix != num_buffers_; ++ix) { | 229 for (int ix = 0; ix != num_buffers_; ++ix) { |
222 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); | 230 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); |
223 if (result != MMSYSERR_NOERROR) { | 231 if (result != MMSYSERR_NOERROR) { |
| 232 CHECK(false); |
224 HandleError(result); | 233 HandleError(result); |
225 break; | 234 break; |
226 } | 235 } |
227 } | 236 } |
228 result = ::waveOutRestart(waveout_); | 237 result = ::waveOutRestart(waveout_); |
229 if (result != MMSYSERR_NOERROR) { | 238 if (result != MMSYSERR_NOERROR) { |
| 239 CHECK(false); |
230 HandleError(result); | 240 HandleError(result); |
231 return; | 241 return; |
232 } | 242 } |
233 } | 243 } |
234 | 244 |
235 // Stopping is tricky if we want it be fast. | 245 // Stopping is tricky if we want it be fast. |
236 // For now just do it synchronously and avoid all the complexities. | 246 // For now just do it synchronously and avoid all the complexities. |
237 // TODO(enal): if we want faster Stop() we can create singleton that keeps track | 247 // TODO(enal): if we want faster Stop() we can create singleton that keeps track |
238 // of all currently playing streams. Then you don't have to wait | 248 // of all currently playing streams. Then you don't have to wait |
239 // till all callbacks are completed. Of course access to singleton | 249 // till all callbacks are completed. Of course access to singleton |
240 // should be under its own lock, and checking the liveness and | 250 // should be under its own lock, and checking the liveness and |
241 // acquiring the lock on stream should be done atomically. | 251 // acquiring the lock on stream should be done atomically. |
242 void PCMWaveOutAudioOutputStream::Stop() { | 252 void PCMWaveOutAudioOutputStream::Stop() { |
| 253 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
243 if (state_ != PCMA_PLAYING) | 254 if (state_ != PCMA_PLAYING) |
244 return; | 255 return; |
245 state_ = PCMA_STOPPING; | 256 state_ = PCMA_STOPPING; |
246 MemoryBarrier(); | 257 MemoryBarrier(); |
247 | 258 |
248 // Stop playback. | 259 // Stop playback. |
249 MMRESULT res = ::waveOutReset(waveout_); | 260 MMRESULT res = ::waveOutReset(waveout_); |
250 if (res != MMSYSERR_NOERROR) { | 261 if (res != MMSYSERR_NOERROR) { |
| 262 CHECK(false); |
251 state_ = PCMA_PLAYING; | 263 state_ = PCMA_PLAYING; |
252 HandleError(res); | 264 HandleError(res); |
253 return; | 265 return; |
254 } | 266 } |
255 | 267 |
256 // waveOutReset() leaves buffers in the unpredictable state, causing | 268 // waveOutReset() leaves buffers in the unpredictable state, causing |
257 // problems if we want to close, release, or reuse them. Fix the states. | 269 // problems if we want to close, release, or reuse them. Fix the states. |
258 for (int ix = 0; ix != num_buffers_; ++ix) { | 270 for (int ix = 0; ix != num_buffers_; ++ix) { |
259 GetBuffer(ix)->dwFlags = WHDR_PREPARED; | 271 GetBuffer(ix)->dwFlags = WHDR_PREPARED; |
260 } | 272 } |
261 | 273 |
262 // Stop watching for buffer event, wait till all the callbacks are complete. | 274 // Stop watching for buffer event, wait till all the callbacks are complete. |
263 // If UnregisterWaitEx() fails we cannot do anything, just continue normal | 275 // If UnregisterWaitEx() fails we cannot do anything, just continue normal |
264 // Stop() -- event would never be signalled because we already stopped the | 276 // Stop() -- event would never be signalled because we already stopped the |
265 // stream. | 277 // stream. |
266 HANDLE waiting_handle = waiting_handle_.Take(); | 278 HANDLE waiting_handle = waiting_handle_.Take(); |
267 if (waiting_handle) { | 279 if (waiting_handle) { |
268 BOOL unregister = UnregisterWaitEx(waiting_handle, INVALID_HANDLE_VALUE); | 280 BOOL unregister = UnregisterWaitEx(waiting_handle, INVALID_HANDLE_VALUE); |
269 if (!unregister) { | 281 if (!unregister) { |
| 282 volatile DWORD code = GetLastError(); |
| 283 CHECK(false); |
270 state_ = PCMA_PLAYING; | 284 state_ = PCMA_PLAYING; |
271 HandleError(MMSYSERR_ERROR); | 285 HandleError(MMSYSERR_ERROR); |
272 } | 286 } |
273 } | 287 } |
274 | 288 |
275 // Don't use callback after Stop(). | 289 // Don't use callback after Stop(). |
276 callback_ = NULL; | 290 callback_ = NULL; |
277 | 291 |
278 state_ = PCMA_READY; | 292 state_ = PCMA_READY; |
279 } | 293 } |
280 | 294 |
281 // We can Close in any state except that trying to close a stream that is | 295 // We can Close in any state except that trying to close a stream that is |
282 // playing Windows generates an error. We cannot propagate it to the source, | 296 // playing Windows generates an error. We cannot propagate it to the source, |
283 // as callback_ is set to NULL. Just print it and hope somebody somehow | 297 // as callback_ is set to NULL. Just print it and hope somebody somehow |
284 // will find it... | 298 // will find it... |
285 void PCMWaveOutAudioOutputStream::Close() { | 299 void PCMWaveOutAudioOutputStream::Close() { |
| 300 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
286 Stop(); // Just to be sure. No-op if not playing. | 301 Stop(); // Just to be sure. No-op if not playing. |
287 if (waveout_) { | 302 if (waveout_) { |
288 MMRESULT res = ::waveOutClose(waveout_); | 303 MMRESULT res = ::waveOutClose(waveout_); |
289 // The callback was cleared by the call to Stop(), so there's no point in | 304 if (res != MMSYSERR_NOERROR) { |
290 // calling HandleError at this point. Also, even though waveOutClose might | 305 CHECK(false); |
291 // fail, we do not want to attempt to close the handle again, so we always | 306 HandleError(res); |
292 // transfer to the closed state and NULL the handle. Moreover, we must | 307 } |
293 // always call ReleaseOutputStream(). | 308 // Even though waveOutClose might fail, we do not want to attempt to close |
294 DLOG_IF(ERROR, res != MMSYSERR_NOERROR) << "waveOutClose() failed"; | 309 // the handle again, so we always transfer to the closed state and NULL the |
| 310 // handle. Moreover, we must always call ReleaseOutputStream(). |
295 state_ = PCMA_CLOSED; | 311 state_ = PCMA_CLOSED; |
296 waveout_ = NULL; | 312 waveout_ = NULL; |
297 FreeBuffers(); | 313 FreeBuffers(); |
298 } | 314 } |
299 // Tell the audio manager that we have been released. This can result in | 315 // Tell the audio manager that we have been released. This can result in |
300 // the manager destroying us in-place so this needs to be the last thing | 316 // the manager destroying us in-place so this needs to be the last thing |
301 // we do on this function. | 317 // we do on this function. |
302 manager_->ReleaseOutputStream(this); | 318 manager_->ReleaseOutputStream(this); |
303 } | 319 } |
304 | 320 |
305 void PCMWaveOutAudioOutputStream::SetVolume(double volume) { | 321 void PCMWaveOutAudioOutputStream::SetVolume(double volume) { |
| 322 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
306 if (!waveout_) | 323 if (!waveout_) |
307 return; | 324 return; |
308 volume_ = static_cast<float>(volume); | 325 volume_ = static_cast<float>(volume); |
309 } | 326 } |
310 | 327 |
311 void PCMWaveOutAudioOutputStream::GetVolume(double* volume) { | 328 void PCMWaveOutAudioOutputStream::GetVolume(double* volume) { |
| 329 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
312 if (!waveout_) | 330 if (!waveout_) |
313 return; | 331 return; |
314 *volume = volume_; | 332 *volume = volume_; |
315 } | 333 } |
316 | 334 |
317 void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { | 335 void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { |
| 336 CHECK_EQ(thread_id_, GetCurrentThreadId()); |
318 DLOG(WARNING) << "PCMWaveOutAudio error " << error; | 337 DLOG(WARNING) << "PCMWaveOutAudio error " << error; |
319 if (callback_) | 338 if (callback_) |
320 callback_->OnError(this, error); | 339 callback_->OnError(this, error); |
321 } | 340 } |
322 | 341 |
323 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { | 342 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { |
324 // Call the source which will fill our buffer with pleasant sounds and | 343 // Call the source which will fill our buffer with pleasant sounds and |
325 // return to us how many bytes were used. | 344 // return to us how many bytes were used. |
326 // If we are down sampling to a smaller number of channels, we need to | 345 // If we are down sampling to a smaller number of channels, we need to |
327 // scale up the amount of pending bytes. | 346 // scale up the amount of pending bytes. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 // the same buffers we can get away without calling waveOutPrepareHeader. | 409 // the same buffers we can get away without calling waveOutPrepareHeader. |
391 MMRESULT result = ::waveOutWrite(stream->waveout_, | 410 MMRESULT result = ::waveOutWrite(stream->waveout_, |
392 buffer, | 411 buffer, |
393 sizeof(WAVEHDR)); | 412 sizeof(WAVEHDR)); |
394 if (result != MMSYSERR_NOERROR) | 413 if (result != MMSYSERR_NOERROR) |
395 stream->HandleError(result); | 414 stream->HandleError(result); |
396 stream->pending_bytes_ += buffer->dwBufferLength; | 415 stream->pending_bytes_ += buffer->dwBufferLength; |
397 } | 416 } |
398 } | 417 } |
399 } | 418 } |
OLD | NEW |