| 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 |