Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: media/audio/win/waveout_output_win.cc

Issue 9147039: Add CHECKs to find root cause of Windows-only crash. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/win/waveout_output_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « media/audio/win/waveout_output_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698