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

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

Issue 8753001: Revert 112147 - Did not get LGTM from all reviewers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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
11 #include "base/basictypes.h" 11 #include "base/basictypes.h"
12 #include "base/debug/trace_event.h" 12 #include "base/debug/trace_event.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "media/audio/audio_io.h" 14 #include "media/audio/audio_io.h"
15 #include "media/audio/audio_util.h" 15 #include "media/audio/audio_util.h"
16 #include "media/audio/win/audio_manager_win.h" 16 #include "media/audio/win/audio_manager_win.h"
17 17
18 // Number of times InitializeCriticalSectionAndSpinCount() spins
19 // before going to sleep.
20 const DWORD kSpinCount = 2000;
21
18 // Some general thoughts about the waveOut API which is badly documented : 22 // Some general thoughts about the waveOut API which is badly documented :
19 // - We use CALLBACK_EVENT mode in which XP signals events such as buffer 23 // - We use CALLBACK_FUNCTION mode in which XP secretly creates two threads
20 // releases. 24 // named _MixerCallbackThread and _waveThread which have real-time priority.
21 // - We use RegisterWaitForSingleObject() so one of threads in thread pool 25 // The callbacks occur in _waveThread.
22 // automatically calls our callback that feeds more data to Windows.
23 // - Windows does not provide a way to query if the device is playing or paused 26 // - Windows does not provide a way to query if the device is playing or paused
24 // thus it forces you to maintain state, which naturally is not exactly 27 // thus it forces you to maintain state, which naturally is not exactly
25 // synchronized to the actual device state. 28 // synchronized to the actual device state.
29 // - Some functions, like waveOutReset cannot be called in the callback thread
30 // or called in any random state because they deadlock. This results in a
31 // non- instantaneous Stop() method. waveOutPrepareHeader seems to be in the
32 // same boat.
33 // - waveOutReset() will forcefully kill the _waveThread so it is important
34 // to make sure we are not executing inside the audio source's OnMoreData()
35 // or that we take locks inside WaveCallback() or QueueNextPacket().
26 36
27 // Sixty four MB is the maximum buffer size per AudioOutputStream. 37 // Sixty four MB is the maximum buffer size per AudioOutputStream.
28 static const uint32 kMaxOpenBufferSize = 1024 * 1024 * 64; 38 static const uint32 kMaxOpenBufferSize = 1024 * 1024 * 64;
29 39
40 // Our sound buffers are allocated once and kept in a linked list using the
41 // the WAVEHDR::dwUser variable. The last buffer points to the first buffer.
42 static WAVEHDR* GetNextBuffer(WAVEHDR* current) {
43 return reinterpret_cast<WAVEHDR*>(current->dwUser);
44 }
45
30 // See Also 46 // See Also
31 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/ 47 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/
32 // http://en.wikipedia.org/wiki/Surround_sound 48 // http://en.wikipedia.org/wiki/Surround_sound
33 49
34 static const int kMaxChannelsToMask = 8; 50 static const int kMaxChannelsToMask = 8;
35 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = { 51 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = {
36 0, 52 0,
37 // 1 = Mono 53 // 1 = Mono
38 SPEAKER_FRONT_CENTER, 54 SPEAKER_FRONT_CENTER,
39 // 2 = Stereo 55 // 2 = Stereo
(...skipping 16 matching lines...) Expand all
56 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 72 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
57 SPEAKER_BACK_CENTER, 73 SPEAKER_BACK_CENTER,
58 // 8 = 7.1 74 // 8 = 7.1
59 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 75 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
60 SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | 76 SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
61 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 77 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
62 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT 78 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
63 // TODO(fbarchard): Add additional masks for 7.2 and beyond. 79 // TODO(fbarchard): Add additional masks for 7.2 and beyond.
64 }; 80 };
65 81
66 inline size_t PCMWaveOutAudioOutputStream::BufferSize() const {
67 // Round size of buffer up to the nearest 16 bytes.
68 return (sizeof(WAVEHDR) + buffer_size_ + 15u) & static_cast<size_t>(~15);
69 }
70
71 inline WAVEHDR* PCMWaveOutAudioOutputStream::GetBuffer(int n) const {
72 DCHECK_GE(n, 0);
73 DCHECK_LT(n, num_buffers_);
74 return reinterpret_cast<WAVEHDR*>(&buffers_[n * BufferSize()]);
75 }
76
77
78 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( 82 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream(
79 AudioManagerWin* manager, const AudioParameters& params, int num_buffers, 83 AudioManagerWin* manager, const AudioParameters& params, int num_buffers,
80 UINT device_id) 84 UINT device_id)
81 : state_(PCMA_BRAND_NEW), 85 : state_(PCMA_BRAND_NEW),
82 manager_(manager), 86 manager_(manager),
83 device_id_(device_id), 87 device_id_(device_id),
84 waveout_(NULL), 88 waveout_(NULL),
85 callback_(NULL), 89 callback_(NULL),
86 num_buffers_(num_buffers), 90 num_buffers_(num_buffers),
91 buffer_(NULL),
87 buffer_size_(params.GetPacketSize()), 92 buffer_size_(params.GetPacketSize()),
88 volume_(1), 93 volume_(1),
89 channels_(params.channels), 94 channels_(params.channels),
90 pending_bytes_(0) { 95 pending_bytes_(0) {
96 ::InitializeCriticalSectionAndSpinCount(&lock_, kSpinCount);
97
91 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 98 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
92 format_.Format.nChannels = params.channels; 99 format_.Format.nChannels = params.channels;
93 format_.Format.nSamplesPerSec = params.sample_rate; 100 format_.Format.nSamplesPerSec = params.sample_rate;
94 format_.Format.wBitsPerSample = params.bits_per_sample; 101 format_.Format.wBitsPerSample = params.bits_per_sample;
95 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); 102 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX);
96 // The next are computed from above. 103 // The next are computed from above.
97 format_.Format.nBlockAlign = (format_.Format.nChannels * 104 format_.Format.nBlockAlign = (format_.Format.nChannels *
98 format_.Format.wBitsPerSample) / 8; 105 format_.Format.wBitsPerSample) / 8;
99 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * 106 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign *
100 format_.Format.nSamplesPerSec; 107 format_.Format.nSamplesPerSec;
101 if (params.channels > kMaxChannelsToMask) { 108 if (params.channels > kMaxChannelsToMask) {
102 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; 109 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask];
103 } else { 110 } else {
104 format_.dwChannelMask = kChannelsToMask[params.channels]; 111 format_.dwChannelMask = kChannelsToMask[params.channels];
105 } 112 }
106 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 113 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
107 format_.Samples.wValidBitsPerSample = params.bits_per_sample; 114 format_.Samples.wValidBitsPerSample = params.bits_per_sample;
108 } 115 }
109 116
110 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { 117 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() {
111 DCHECK(NULL == waveout_); 118 DCHECK(NULL == waveout_);
119 ::DeleteCriticalSection(&lock_);
112 } 120 }
113 121
114 bool PCMWaveOutAudioOutputStream::Open() { 122 bool PCMWaveOutAudioOutputStream::Open() {
115 if (state_ != PCMA_BRAND_NEW) 123 if (state_ != PCMA_BRAND_NEW)
116 return false; 124 return false;
117 if (BufferSize() * num_buffers_ > kMaxOpenBufferSize)
118 return false;
119 if (num_buffers_ < 2 || num_buffers_ > 5) 125 if (num_buffers_ < 2 || num_buffers_ > 5)
120 return false; 126 return false;
121 127 // Open the device. We'll be getting callback in WaveCallback function.
122 // Create buffer event. 128 // They occur in a magic, time-critical thread that windows creates.
123 buffer_event_.Set(::CreateEvent(NULL, // Security attributes 129 MMRESULT result = ::waveOutOpen(&waveout_, device_id_,
124 FALSE, // It will auto-reset 130 reinterpret_cast<LPCWAVEFORMATEX>(&format_),
125 FALSE, // Initial state 131 reinterpret_cast<DWORD_PTR>(WaveCallback),
126 NULL // No name 132 reinterpret_cast<DWORD_PTR>(this),
127 )); 133 CALLBACK_FUNCTION);
128 if (!buffer_event_.Get()) {
129 return false;
130 }
131
132 // Open the device.
133 // We'll be getting buffer_event_ events when it's time to refill the buffer.
134 MMRESULT result = ::waveOutOpen(
135 &waveout_,
136 device_id_,
137 reinterpret_cast<LPCWAVEFORMATEX>(&format_),
138 reinterpret_cast<DWORD_PTR>(buffer_event_.Get()),
139 NULL,
140 CALLBACK_EVENT);
141 if (result != MMSYSERR_NOERROR) 134 if (result != MMSYSERR_NOERROR)
142 return false; 135 return false;
143 136
144 SetupBuffers(); 137 SetupBuffers();
145 state_ = PCMA_READY; 138 state_ = PCMA_READY;
146 return true; 139 return true;
147 } 140 }
148 141
149 void PCMWaveOutAudioOutputStream::SetupBuffers() { 142 void PCMWaveOutAudioOutputStream::SetupBuffers() {
150 buffers_.reset(new char[BufferSize() * num_buffers_]); 143 WAVEHDR* last = NULL;
144 WAVEHDR* first = NULL;
151 for (int ix = 0; ix != num_buffers_; ++ix) { 145 for (int ix = 0; ix != num_buffers_; ++ix) {
152 WAVEHDR* buffer = GetBuffer(ix); 146 uint32 sz = sizeof(WAVEHDR) + buffer_size_;
153 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR); 147 buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]);
154 buffer->dwBufferLength = buffer_size_; 148 buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR);
155 buffer->dwBytesRecorded = 0; 149 buffer_->dwBufferLength = buffer_size_;
156 buffer->dwFlags = WHDR_DONE; 150 buffer_->dwBytesRecorded = 0;
157 buffer->dwLoops = 0; 151 buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last);
152 buffer_->dwFlags = WHDR_DONE;
153 buffer_->dwLoops = 0;
154 if (ix == 0)
155 first = buffer_;
156 last = buffer_;
158 // Tell windows sound drivers about our buffers. Not documented what 157 // Tell windows sound drivers about our buffers. Not documented what
159 // this does but we can guess that causes the OS to keep a reference to 158 // this does but we can guess that causes the OS to keep a reference to
160 // the memory pages so the driver can use them without worries. 159 // the memory pages so the driver can use them without worries.
161 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR)); 160 ::waveOutPrepareHeader(waveout_, buffer_, sizeof(WAVEHDR));
162 } 161 }
162 // Fix the first buffer to point to the last one.
163 first->dwUser = reinterpret_cast<DWORD_PTR>(last);
163 } 164 }
164 165
165 void PCMWaveOutAudioOutputStream::FreeBuffers() { 166 void PCMWaveOutAudioOutputStream::FreeBuffers() {
167 WAVEHDR* current = buffer_;
166 for (int ix = 0; ix != num_buffers_; ++ix) { 168 for (int ix = 0; ix != num_buffers_; ++ix) {
167 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); 169 WAVEHDR* next = GetNextBuffer(current);
170 ::waveOutUnprepareHeader(waveout_, current, sizeof(WAVEHDR));
171 delete[] reinterpret_cast<char*>(current);
172 current = next;
168 } 173 }
169 buffers_.reset(NULL); 174 buffer_ = NULL;
170 } 175 }
171 176
172 // Initially we ask the source to fill up all audio buffers. If we don't do 177 // Initially we ask the source to fill up both audio buffers. If we don't do
173 // this then we would always get the driver callback when it is about to run 178 // this then we would always get the driver callback when it is about to run
174 // samples and that would leave too little time to react. 179 // samples and that would leave too little time to react.
175 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { 180 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) {
176 if (state_ != PCMA_READY) 181 if (state_ != PCMA_READY)
177 return; 182 return;
178 callback_ = callback; 183 callback_ = callback;
179
180 // Start watching for buffer events.
181 {
182 HANDLE waiting_handle = NULL;
183 ::RegisterWaitForSingleObject(&waiting_handle,
184 buffer_event_.Get(),
185 &BufferCallback,
186 static_cast<void*>(this),
187 INFINITE,
188 WT_EXECUTEDEFAULT);
189 if (!waiting_handle) {
190 HandleError(MMSYSERR_ERROR);
191 return;
192 }
193 waiting_handle_.Set(waiting_handle);
194 }
195
196 state_ = PCMA_PLAYING; 184 state_ = PCMA_PLAYING;
197
198 // Queue the buffers.
199 pending_bytes_ = 0; 185 pending_bytes_ = 0;
186 WAVEHDR* buffer = buffer_;
200 for (int ix = 0; ix != num_buffers_; ++ix) { 187 for (int ix = 0; ix != num_buffers_; ++ix) {
201 WAVEHDR* buffer = GetBuffer(ix);
202 // Caller waits for 1st packet to become available, but not for others, 188 // Caller waits for 1st packet to become available, but not for others,
203 // so we wait for them here. 189 // so we wait for them here.
204 if (ix != 0) 190 if (ix != 0)
205 callback_->WaitTillDataReady(); 191 callback_->WaitTillDataReady();
206 QueueNextPacket(buffer); // Read more data. 192 QueueNextPacket(buffer); // Read more data.
207 pending_bytes_ += buffer->dwBufferLength; 193 pending_bytes_ += buffer->dwBufferLength;
194 buffer = GetNextBuffer(buffer);
208 } 195 }
196 buffer = buffer_;
209 197
210 // From now on |pending_bytes_| would be accessed by callback thread. 198 // From now on |pending_bytes_| would be accessed by callback thread.
211 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, 199 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier,
212 // but issuing our own is safer. 200 // but issuing our own is safer.
213 MemoryBarrier(); 201 MemoryBarrier();
214 202
215 MMRESULT result = ::waveOutPause(waveout_); 203 MMRESULT result = ::waveOutPause(waveout_);
216 if (result != MMSYSERR_NOERROR) { 204 if (result != MMSYSERR_NOERROR) {
217 HandleError(result); 205 HandleError(result);
218 return; 206 return;
219 } 207 }
220 208
221 // Send the buffers to the audio driver. Note that the device is paused 209 // Send the buffers to the audio driver. Note that the device is paused
222 // so we avoid entering the callback method while still here. 210 // so we avoid entering the callback method while still here.
223 for (int ix = 0; ix != num_buffers_; ++ix) { 211 for (int ix = 0; ix != num_buffers_; ++ix) {
224 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); 212 result = ::waveOutWrite(waveout_, buffer, sizeof(WAVEHDR));
225 if (result != MMSYSERR_NOERROR) { 213 if (result != MMSYSERR_NOERROR) {
226 HandleError(result); 214 HandleError(result);
227 break; 215 break;
228 } 216 }
217 buffer = GetNextBuffer(buffer);
229 } 218 }
230 result = ::waveOutRestart(waveout_); 219 result = ::waveOutRestart(waveout_);
231 if (result != MMSYSERR_NOERROR) { 220 if (result != MMSYSERR_NOERROR) {
232 HandleError(result); 221 HandleError(result);
233 return; 222 return;
234 } 223 }
235 } 224 }
236 225
237 // Stopping is tricky if we want it be fast. 226 // Stopping is tricky. First, no buffer should be locked by the audio driver
238 // For now just do it synchronously and avoid all the complexities. 227 // or else the waveOutReset() will deadlock and secondly, the callback should
239 // TODO(enal): if we want faster Stop() we can create singleton that keeps track 228 // not be inside the AudioSource's OnMoreData because waveOutReset() forcefully
240 // of all currently playing streams. Then you don't have to wait 229 // kills the callback thread after releasing all buffers.
241 // till all callbacks are completed. Of course access to singleton
242 // should be under its own lock, and checking the liveness and
243 // acquiring the lock on stream should be done atomically.
244 void PCMWaveOutAudioOutputStream::Stop() { 230 void PCMWaveOutAudioOutputStream::Stop() {
245 if (state_ != PCMA_PLAYING) 231 if (state_ != PCMA_PLAYING)
246 return; 232 return;
247 state_ = PCMA_STOPPING;
248 MemoryBarrier();
249 233
250 // Stop playback. 234 // Enter into critical section and call ::waveOutReset(). The fact that we
235 // entered critical section means that callback is out of critical section and
236 // it is safe to reset.
237 ::EnterCriticalSection(&lock_);
251 MMRESULT res = ::waveOutReset(waveout_); 238 MMRESULT res = ::waveOutReset(waveout_);
239 ::LeaveCriticalSection(&lock_);
252 if (res != MMSYSERR_NOERROR) { 240 if (res != MMSYSERR_NOERROR) {
253 state_ = PCMA_PLAYING;
254 HandleError(res); 241 HandleError(res);
255 return; 242 return;
256 } 243 }
257 244
258 // Stop watching for buffer event, wait till all the callbacks are complete.
259 BOOL unregister = UnregisterWaitEx(waiting_handle_.Take(),
260 INVALID_HANDLE_VALUE);
261 if (!unregister) {
262 state_ = PCMA_PLAYING;
263 HandleError(MMSYSERR_ERROR);
264 return;
265 }
266
267 // waveOutReset() leaves buffers in the unpredictable state, causing
268 // problems if we want to release or reuse them. Fix the states.
269 for (int ix = 0; ix != num_buffers_; ++ix) {
270 GetBuffer(ix)->dwFlags = WHDR_PREPARED;
271 }
272
273 // Don't use callback after Stop(). 245 // Don't use callback after Stop().
274 callback_ = NULL; 246 callback_ = NULL;
275 247
276 state_ = PCMA_READY; 248 state_ = PCMA_READY;
277 } 249 }
278 250
279 // We can Close in any state except that trying to close a stream that is 251 // We can Close in any state except that trying to close a stream that is
280 // playing Windows generates an error, which we propagate to the source. 252 // playing Windows generates an error, which we propagate to the source.
281 void PCMWaveOutAudioOutputStream::Close() { 253 void PCMWaveOutAudioOutputStream::Close() {
282 Stop(); // Just to be sure. No-op if not playing.
283 if (waveout_) { 254 if (waveout_) {
255 // waveOutClose generates a callback with WOM_CLOSE id in the same thread.
284 MMRESULT res = ::waveOutClose(waveout_); 256 MMRESULT res = ::waveOutClose(waveout_);
285 if (res != MMSYSERR_NOERROR) { 257 if (res != MMSYSERR_NOERROR) {
286 HandleError(res); 258 HandleError(res);
287 return; 259 return;
288 } 260 }
289 state_ = PCMA_CLOSED; 261 state_ = PCMA_CLOSED;
290 waveout_ = NULL; 262 waveout_ = NULL;
291 FreeBuffers(); 263 FreeBuffers();
292 } 264 }
293 // Tell the audio manager that we have been released. This can result in 265 // Tell the audio manager that we have been released. This can result in
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 format_.Format.wBitsPerSample >> 3, 309 format_.Format.wBitsPerSample >> 3,
338 volume_); 310 volume_);
339 } 311 }
340 } else { 312 } else {
341 HandleError(0); 313 HandleError(0);
342 return; 314 return;
343 } 315 }
344 buffer->dwFlags = WHDR_PREPARED; 316 buffer->dwFlags = WHDR_PREPARED;
345 } 317 }
346 318
347 // One of the threads in our thread pool asynchronously calls this function when 319 // Windows call us back in this function when some events happen. Most notably
348 // buffer_event_ is signalled. Search through all the buffers looking for freed 320 // when it is done playing a buffer. Since we use double buffering it is
349 // ones, fills them with data, and "feed" the Windows. 321 // convenient to think of |buffer| as free and GetNextBuffer(buffer) as in
350 // Note: by searching through all the buffers we guarantee that we fill all the 322 // use by the driver.
351 // buffers, even when "event loss" happens, i.e. if Windows signals event 323 void PCMWaveOutAudioOutputStream::WaveCallback(HWAVEOUT hwo, UINT msg,
352 // when it did not flip into unsignaled state from the previous signal. 324 DWORD_PTR instance,
353 void NTAPI PCMWaveOutAudioOutputStream::BufferCallback(PVOID lpParameter, 325 DWORD_PTR param1, DWORD_PTR) {
354 BOOLEAN) { 326 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::WaveCallback");
355 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::BufferCallback");
356 327
357 PCMWaveOutAudioOutputStream* stream = 328 if (msg == WOM_DONE) {
358 reinterpret_cast<PCMWaveOutAudioOutputStream*>(lpParameter); 329 // WOM_DONE indicates that the driver is done with our buffer, we can
330 // either ask the source for more data or check if we need to stop playing.
331 WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1);
332 buffer->dwFlags = WHDR_DONE;
359 333
360 // Lock the stream so 2 callbacks do not interfere with each other. 334 PCMWaveOutAudioOutputStream* stream =
361 // Two callbacks can be called simultaneously by 2 different threads in the 335 reinterpret_cast<PCMWaveOutAudioOutputStream*>(instance);
362 // thread pool if one of the callbacks is slow, or system is very busy and
363 // one of scheduled callbacks is not called on time.
364 base::AutoLock auto_lock(stream->lock_);
365 if (stream->state_ != PCMA_PLAYING)
366 return;
367 336
368 for (int ix = 0; ix != stream->num_buffers_; ++ix) { 337 // Do real work only if main thread has not yet called waveOutReset().
369 WAVEHDR* buffer = stream->GetBuffer(ix); 338 if (::TryEnterCriticalSection(&stream->lock_)) {
370 if (buffer->dwFlags & WHDR_DONE) {
371 // Before we queue the next packet, we need to adjust the number of 339 // Before we queue the next packet, we need to adjust the number of
372 // pending bytes since the last write to hardware. 340 // pending bytes since the last write to hardware.
373 stream->pending_bytes_ -= buffer->dwBufferLength; 341 stream->pending_bytes_ -= buffer->dwBufferLength;
342
374 stream->QueueNextPacket(buffer); 343 stream->QueueNextPacket(buffer);
375 344
376 // QueueNextPacket() can take a long time, especially if several of them
377 // were called back-to-back. Check if we are stopping now.
378 if (stream->state_ != PCMA_PLAYING)
379 return;
380
381 // Time to send the buffer to the audio driver. Since we are reusing 345 // Time to send the buffer to the audio driver. Since we are reusing
382 // the same buffers we can get away without calling waveOutPrepareHeader. 346 // the same buffers we can get away without calling waveOutPrepareHeader.
383 MMRESULT result = ::waveOutWrite(stream->waveout_, 347 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR));
384 buffer,
385 sizeof(WAVEHDR));
386 if (result != MMSYSERR_NOERROR) 348 if (result != MMSYSERR_NOERROR)
387 stream->HandleError(result); 349 stream->HandleError(result);
350
388 stream->pending_bytes_ += buffer->dwBufferLength; 351 stream->pending_bytes_ += buffer->dwBufferLength;
352 ::LeaveCriticalSection(&stream->lock_);
389 } 353 }
390 } 354 }
391 } 355 }
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