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 |