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_NE(waiting_handle, static_cast<HANDLE>(NULL)); | |
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_EQ(result, static_cast<MMRESULT>(MMSYSERR_NOERROR)); | |
cpu_(ooo_6.6-7.5)
2012/01/11 01:00:39
in here (and some other cases) you are testing the
| |
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_EQ(result, static_cast<MMRESULT>(MMSYSERR_NOERROR)); | |
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_EQ(result, static_cast<MMRESULT>(MMSYSERR_NOERROR)); | |
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_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR)); | |
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_NE(unregister, FALSE); | |
cpu_(ooo_6.6-7.5)
2012/01/11 01:00:39
same here.
| |
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 if (res != MMSYSERR_NOERROR) { | 304 if (res != MMSYSERR_NOERROR) { |
305 CHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR)); | |
290 HandleError(res); | 306 HandleError(res); |
291 return; | 307 return; |
292 } | 308 } |
293 state_ = PCMA_CLOSED; | 309 state_ = PCMA_CLOSED; |
294 waveout_ = NULL; | 310 waveout_ = NULL; |
295 FreeBuffers(); | 311 FreeBuffers(); |
296 } | 312 } |
297 // Tell the audio manager that we have been released. This can result in | 313 // Tell the audio manager that we have been released. This can result in |
298 // the manager destroying us in-place so this needs to be the last thing | 314 // the manager destroying us in-place so this needs to be the last thing |
299 // we do on this function. | 315 // we do on this function. |
300 manager_->ReleaseOutputStream(this); | 316 manager_->ReleaseOutputStream(this); |
301 } | 317 } |
302 | 318 |
303 void PCMWaveOutAudioOutputStream::SetVolume(double volume) { | 319 void PCMWaveOutAudioOutputStream::SetVolume(double volume) { |
320 CHECK_EQ(thread_id_, GetCurrentThreadId()); | |
304 if (!waveout_) | 321 if (!waveout_) |
305 return; | 322 return; |
306 volume_ = static_cast<float>(volume); | 323 volume_ = static_cast<float>(volume); |
307 } | 324 } |
308 | 325 |
309 void PCMWaveOutAudioOutputStream::GetVolume(double* volume) { | 326 void PCMWaveOutAudioOutputStream::GetVolume(double* volume) { |
327 CHECK_EQ(thread_id_, GetCurrentThreadId()); | |
310 if (!waveout_) | 328 if (!waveout_) |
311 return; | 329 return; |
312 *volume = volume_; | 330 *volume = volume_; |
313 } | 331 } |
314 | 332 |
315 void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { | 333 void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { |
334 CHECK_EQ(thread_id_, GetCurrentThreadId()); | |
316 DLOG(WARNING) << "PCMWaveOutAudio error " << error; | 335 DLOG(WARNING) << "PCMWaveOutAudio error " << error; |
317 if (callback_) | 336 if (callback_) |
318 callback_->OnError(this, error); | 337 callback_->OnError(this, error); |
319 } | 338 } |
320 | 339 |
321 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { | 340 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { |
322 // Call the source which will fill our buffer with pleasant sounds and | 341 // Call the source which will fill our buffer with pleasant sounds and |
323 // return to us how many bytes were used. | 342 // return to us how many bytes were used. |
324 // If we are down sampling to a smaller number of channels, we need to | 343 // If we are down sampling to a smaller number of channels, we need to |
325 // scale up the amount of pending bytes. | 344 // scale up the amount of pending bytes. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 // the same buffers we can get away without calling waveOutPrepareHeader. | 407 // the same buffers we can get away without calling waveOutPrepareHeader. |
389 MMRESULT result = ::waveOutWrite(stream->waveout_, | 408 MMRESULT result = ::waveOutWrite(stream->waveout_, |
390 buffer, | 409 buffer, |
391 sizeof(WAVEHDR)); | 410 sizeof(WAVEHDR)); |
392 if (result != MMSYSERR_NOERROR) | 411 if (result != MMSYSERR_NOERROR) |
393 stream->HandleError(result); | 412 stream->HandleError(result); |
394 stream->pending_bytes_ += buffer->dwBufferLength; | 413 stream->pending_bytes_ += buffer->dwBufferLength; |
395 } | 414 } |
396 } | 415 } |
397 } | 416 } |
OLD | NEW |