Chromium Code Reviews| 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 |