| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( | 80 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( |
| 81 AudioManagerWin* manager, AudioParameters params, int num_buffers, | 81 AudioManagerWin* manager, AudioParameters params, int num_buffers, |
| 82 UINT device_id) | 82 UINT device_id) |
| 83 : state_(PCMA_BRAND_NEW), | 83 : state_(PCMA_BRAND_NEW), |
| 84 manager_(manager), | 84 manager_(manager), |
| 85 device_id_(device_id), | 85 device_id_(device_id), |
| 86 waveout_(NULL), | 86 waveout_(NULL), |
| 87 callback_(NULL), | 87 callback_(NULL), |
| 88 num_buffers_(num_buffers), | 88 num_buffers_(num_buffers), |
| 89 buffer_(NULL), | 89 buffer_(NULL), |
| 90 buffer_size_(0), | 90 buffer_size_(params.GetPacketSize()), |
| 91 volume_(1), | 91 volume_(1), |
| 92 channels_(params.channels), | 92 channels_(params.channels), |
| 93 pending_bytes_(0) { | 93 pending_bytes_(0) { |
| 94 |
| 94 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | 95 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; |
| 95 format_.Format.nChannels = params.channels; | 96 format_.Format.nChannels = params.channels; |
| 96 format_.Format.nSamplesPerSec = params.sample_rate; | 97 format_.Format.nSamplesPerSec = params.sample_rate; |
| 97 format_.Format.wBitsPerSample = params.bits_per_sample; | 98 format_.Format.wBitsPerSample = params.bits_per_sample; |
| 98 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); | 99 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); |
| 99 // The next are computed from above. | 100 // The next are computed from above. |
| 100 format_.Format.nBlockAlign = (format_.Format.nChannels * | 101 format_.Format.nBlockAlign = (format_.Format.nChannels * |
| 101 format_.Format.wBitsPerSample) / 8; | 102 format_.Format.wBitsPerSample) / 8; |
| 102 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * | 103 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * |
| 103 format_.Format.nSamplesPerSec; | 104 format_.Format.nSamplesPerSec; |
| 104 if (params.channels > kMaxChannelsToMask) { | 105 if (params.channels > kMaxChannelsToMask) { |
| 105 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; | 106 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; |
| 106 } else { | 107 } else { |
| 107 format_.dwChannelMask = kChannelsToMask[params.channels]; | 108 format_.dwChannelMask = kChannelsToMask[params.channels]; |
| 108 } | 109 } |
| 109 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | 110 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; |
| 110 format_.Samples.wValidBitsPerSample = params.bits_per_sample; | 111 format_.Samples.wValidBitsPerSample = params.bits_per_sample; |
| 111 // The event is auto-reset. | 112 // The event is auto-reset. |
| 112 stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL)); | 113 stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL)); |
| 113 } | 114 } |
| 114 | 115 |
| 115 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { | 116 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { |
| 116 DCHECK(NULL == waveout_); | 117 DCHECK(NULL == waveout_); |
| 117 } | 118 } |
| 118 | 119 |
| 119 bool PCMWaveOutAudioOutputStream::Open(uint32 buffer_size) { | 120 bool PCMWaveOutAudioOutputStream::Open() { |
| 120 if (state_ != PCMA_BRAND_NEW) | 121 if (state_ != PCMA_BRAND_NEW) |
| 121 return false; | 122 return false; |
| 122 if (buffer_size > kMaxOpenBufferSize) | |
| 123 return false; | |
| 124 if (num_buffers_ < 2 || num_buffers_ > 5) | 123 if (num_buffers_ < 2 || num_buffers_ > 5) |
| 125 return false; | 124 return false; |
| 126 // Open the device. We'll be getting callback in WaveCallback function. | 125 // Open the device. We'll be getting callback in WaveCallback function. |
| 127 // They occur in a magic, time-critical thread that windows creates. | 126 // They occur in a magic, time-critical thread that windows creates. |
| 128 MMRESULT result = ::waveOutOpen(&waveout_, device_id_, | 127 MMRESULT result = ::waveOutOpen(&waveout_, device_id_, |
| 129 reinterpret_cast<LPCWAVEFORMATEX>(&format_), | 128 reinterpret_cast<LPCWAVEFORMATEX>(&format_), |
| 130 reinterpret_cast<DWORD_PTR>(WaveCallback), | 129 reinterpret_cast<DWORD_PTR>(WaveCallback), |
| 131 reinterpret_cast<DWORD_PTR>(this), | 130 reinterpret_cast<DWORD_PTR>(this), |
| 132 CALLBACK_FUNCTION); | 131 CALLBACK_FUNCTION); |
| 133 if (result != MMSYSERR_NOERROR) | 132 if (result != MMSYSERR_NOERROR) |
| 134 return false; | 133 return false; |
| 135 // If we don't have a packet size we use 100ms. | |
| 136 if (!buffer_size) | |
| 137 buffer_size = format_.Format.nAvgBytesPerSec / 10; | |
| 138 | 134 |
| 139 SetupBuffers(buffer_size); | 135 SetupBuffers(); |
| 140 buffer_size_ = buffer_size; | |
| 141 state_ = PCMA_READY; | 136 state_ = PCMA_READY; |
| 142 return true; | 137 return true; |
| 143 } | 138 } |
| 144 | 139 |
| 145 void PCMWaveOutAudioOutputStream::SetupBuffers(uint32 rq_size) { | 140 void PCMWaveOutAudioOutputStream::SetupBuffers() { |
| 146 WAVEHDR* last = NULL; | 141 WAVEHDR* last = NULL; |
| 147 WAVEHDR* first = NULL; | 142 WAVEHDR* first = NULL; |
| 148 for (int ix = 0; ix != num_buffers_; ++ix) { | 143 for (int ix = 0; ix != num_buffers_; ++ix) { |
| 149 uint32 sz = sizeof(WAVEHDR) + rq_size; | 144 uint32 sz = sizeof(WAVEHDR) + buffer_size_; |
| 150 buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]); | 145 buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]); |
| 151 buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR); | 146 buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR); |
| 152 buffer_->dwBufferLength = rq_size; | 147 buffer_->dwBufferLength = buffer_size_; |
| 153 buffer_->dwBytesRecorded = 0; | 148 buffer_->dwBytesRecorded = 0; |
| 154 buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last); | 149 buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last); |
| 155 buffer_->dwFlags = WHDR_DONE; | 150 buffer_->dwFlags = WHDR_DONE; |
| 156 buffer_->dwLoops = 0; | 151 buffer_->dwLoops = 0; |
| 157 if (ix == 0) | 152 if (ix == 0) |
| 158 first = buffer_; | 153 first = buffer_; |
| 159 last = buffer_; | 154 last = buffer_; |
| 160 // Tell windows sound drivers about our buffers. Not documented what | 155 // Tell windows sound drivers about our buffers. Not documented what |
| 161 // this does but we can guess that causes the OS to keep a reference to | 156 // this does but we can guess that causes the OS to keep a reference to |
| 162 // the memory pages so the driver can use them without worries. | 157 // the memory pages so the driver can use them without worries. |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 HandleError(::GetLastError()); | 223 HandleError(::GetLastError()); |
| 229 return; | 224 return; |
| 230 } | 225 } |
| 231 state_ = PCMA_STOPPED; | 226 state_ = PCMA_STOPPED; |
| 232 MMRESULT res = ::waveOutReset(waveout_); | 227 MMRESULT res = ::waveOutReset(waveout_); |
| 233 if (res != MMSYSERR_NOERROR) { | 228 if (res != MMSYSERR_NOERROR) { |
| 234 state_ = PCMA_PLAYING; | 229 state_ = PCMA_PLAYING; |
| 235 HandleError(res); | 230 HandleError(res); |
| 236 return; | 231 return; |
| 237 } | 232 } |
| 233 |
| 234 // Don't use callback after Stop(). |
| 235 callback_ = NULL; |
| 236 |
| 238 state_ = PCMA_READY; | 237 state_ = PCMA_READY; |
| 239 } | 238 } |
| 240 | 239 |
| 241 // We can Close in any state except that trying to close a stream that is | 240 // We can Close in any state except that trying to close a stream that is |
| 242 // playing Windows generates an error, which we propagate to the source. | 241 // playing Windows generates an error, which we propagate to the source. |
| 243 void PCMWaveOutAudioOutputStream::Close() { | 242 void PCMWaveOutAudioOutputStream::Close() { |
| 244 if (waveout_) { | 243 if (waveout_) { |
| 245 // waveOutClose generates a callback with WOM_CLOSE id in the same thread. | 244 // waveOutClose generates a callback with WOM_CLOSE id in the same thread. |
| 246 MMRESULT res = ::waveOutClose(waveout_); | 245 MMRESULT res = ::waveOutClose(waveout_); |
| 247 if (res != MMSYSERR_NOERROR) { | 246 if (res != MMSYSERR_NOERROR) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 obj->QueueNextPacket(buffer); | 339 obj->QueueNextPacket(buffer); |
| 341 | 340 |
| 342 // Time to send the buffer to the audio driver. Since we are reusing | 341 // Time to send the buffer to the audio driver. Since we are reusing |
| 343 // the same buffers we can get away without calling waveOutPrepareHeader. | 342 // the same buffers we can get away without calling waveOutPrepareHeader. |
| 344 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR)); | 343 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR)); |
| 345 if (result != MMSYSERR_NOERROR) | 344 if (result != MMSYSERR_NOERROR) |
| 346 obj->HandleError(result); | 345 obj->HandleError(result); |
| 347 | 346 |
| 348 obj->pending_bytes_ += buffer->dwBufferLength; | 347 obj->pending_bytes_ += buffer->dwBufferLength; |
| 349 | 348 |
| 350 } else if (msg == WOM_CLOSE) { | |
| 351 // We can be closed before calling Start, so it is possible to have a | |
| 352 // null callback at this point. | |
| 353 if (obj->callback_) | |
| 354 obj->callback_->OnClose(obj); | |
| 355 } | 349 } |
| 356 } | 350 } |
| OLD | NEW |