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

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

Issue 8591028: Change the way we are sending audio data to driver when using WaveOut API. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 1 month 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
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/at_exit.h"
11 #include "base/basictypes.h" 12 #include "base/basictypes.h"
13 #include "base/bind.h"
12 #include "base/debug/trace_event.h" 14 #include "base/debug/trace_event.h"
13 #include "base/logging.h" 15 #include "base/logging.h"
14 #include "media/audio/audio_io.h" 16 #include "media/audio/audio_io.h"
15 #include "media/audio/audio_util.h" 17 #include "media/audio/audio_util.h"
16 #include "media/audio/win/audio_manager_win.h" 18 #include "media/audio/win/audio_manager_win.h"
17 19
18 // Number of times InitializeCriticalSectionAndSpinCount() spins 20 base::Lock PCMWaveOutAudioOutputStream::g_lock_;
19 // before going to sleep. 21 volatile DWORD PCMWaveOutAudioOutputStream::g_ordinal_;
20 const DWORD kSpinCount = 2000; 22 scoped_ptr<std::map<PCMWaveOutAudioOutputStream*, DWORD> >
23 PCMWaveOutAudioOutputStream::g_streams_map_;
tommi (sloooow) - chröme 2011/11/18 09:53:21 All these objects should belong to one singleton o
enal1 2011/11/19 00:59:19 Done.
21 24
22 // Some general thoughts about the waveOut API which is badly documented : 25 // Some general thoughts about the waveOut API which is badly documented :
23 // - We use CALLBACK_FUNCTION mode in which XP secretly creates two threads 26 // - We use CALLBACK_FUNCTION mode in which XP secretly creates two threads
24 // named _MixerCallbackThread and _waveThread which have real-time priority. 27 // named _MixerCallbackThread and _waveThread which have real-time priority.
25 // The callbacks occur in _waveThread. 28 // The callbacks occur in _waveThread.
26 // - Windows does not provide a way to query if the device is playing or paused 29 // - Windows does not provide a way to query if the device is playing or paused
27 // thus it forces you to maintain state, which naturally is not exactly 30 // thus it forces you to maintain state, which naturally is not exactly
28 // synchronized to the actual device state. 31 // synchronized to the actual device state.
29 // - Some functions, like waveOutReset cannot be called in the callback thread 32 // - 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 33 // or called in any random state because they deadlock. This results in a
31 // non- instantaneous Stop() method. waveOutPrepareHeader seems to be in the 34 // non- instantaneous Stop() method. waveOutWrite() and waveOutPrepareHeader
32 // same boat. 35 // seem to be in the same boat.
33 // - waveOutReset() will forcefully kill the _waveThread so it is important 36 // - We have to use separate "feeder" thread that calls waveOutWrite() to feed
34 // to make sure we are not executing inside the audio source's OnMoreData() 37 // buffers to driver, cannot do it from the callback.
35 // or that we take locks inside WaveCallback() or QueueNextPacket(). 38 // - Stopping is tricky, see comment below.
36
37 // Sixty four MB is the maximum buffer size per AudioOutputStream.
38 static const uint32 kMaxOpenBufferSize = 1024 * 1024 * 64;
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 39
46 // See Also 40 // See Also
47 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/ 41 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/
48 // http://en.wikipedia.org/wiki/Surround_sound 42 // http://en.wikipedia.org/wiki/Surround_sound
49 43
50 static const int kMaxChannelsToMask = 8; 44 static const int kMaxChannelsToMask = 8;
51 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = { 45 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = {
52 0, 46 0,
53 // 1 = Mono 47 // 1 = Mono
54 SPEAKER_FRONT_CENTER, 48 SPEAKER_FRONT_CENTER,
(...skipping 26 matching lines...) Expand all
81 75
82 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( 76 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream(
83 AudioManagerWin* manager, const AudioParameters& params, int num_buffers, 77 AudioManagerWin* manager, const AudioParameters& params, int num_buffers,
84 UINT device_id) 78 UINT device_id)
85 : state_(PCMA_BRAND_NEW), 79 : state_(PCMA_BRAND_NEW),
86 manager_(manager), 80 manager_(manager),
87 device_id_(device_id), 81 device_id_(device_id),
88 waveout_(NULL), 82 waveout_(NULL),
89 callback_(NULL), 83 callback_(NULL),
90 num_buffers_(num_buffers), 84 num_buffers_(num_buffers),
91 buffer_(NULL), 85 buffers_(NULL),
92 buffer_size_(params.GetPacketSize()), 86 buffer_size_(params.GetPacketSize()),
93 volume_(1), 87 volume_(1),
94 channels_(params.channels), 88 channels_(params.channels),
95 pending_bytes_(0) { 89 pending_bytes_(0),
96 ::InitializeCriticalSectionAndSpinCount(&lock_, kSpinCount); 90 ordinal_(0) {
91 InitializeGlobalsIfNecessary();
97 92
98 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 93 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
99 format_.Format.nChannels = params.channels; 94 format_.Format.nChannels = params.channels;
100 format_.Format.nSamplesPerSec = params.sample_rate; 95 format_.Format.nSamplesPerSec = params.sample_rate;
101 format_.Format.wBitsPerSample = params.bits_per_sample; 96 format_.Format.wBitsPerSample = params.bits_per_sample;
102 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); 97 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX);
103 // The next are computed from above. 98 // The next are computed from above.
104 format_.Format.nBlockAlign = (format_.Format.nChannels * 99 format_.Format.nBlockAlign = (format_.Format.nChannels *
105 format_.Format.wBitsPerSample) / 8; 100 format_.Format.wBitsPerSample) / 8;
106 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * 101 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign *
107 format_.Format.nSamplesPerSec; 102 format_.Format.nSamplesPerSec;
108 if (params.channels > kMaxChannelsToMask) { 103 if (params.channels > kMaxChannelsToMask) {
109 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; 104 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask];
110 } else { 105 } else {
111 format_.dwChannelMask = kChannelsToMask[params.channels]; 106 format_.dwChannelMask = kChannelsToMask[params.channels];
112 } 107 }
113 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 108 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
114 format_.Samples.wValidBitsPerSample = params.bits_per_sample; 109 format_.Samples.wValidBitsPerSample = params.bits_per_sample;
115 } 110 }
116 111
117 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { 112 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() {
118 DCHECK(NULL == waveout_); 113 DCHECK(NULL == waveout_);
119 ::DeleteCriticalSection(&lock_);
120 } 114 }
121 115
122 bool PCMWaveOutAudioOutputStream::Open() { 116 bool PCMWaveOutAudioOutputStream::Open() {
123 if (state_ != PCMA_BRAND_NEW) 117 if (state_ != PCMA_BRAND_NEW)
124 return false; 118 return false;
125 if (num_buffers_ < 2 || num_buffers_ > 5) 119 if (num_buffers_ < 2 || num_buffers_ > 5)
126 return false; 120 return false;
127 // Open the device. We'll be getting callback in WaveCallback function. 121 // Open the device. We'll be getting callback in WaveCallback function.
128 // They occur in a magic, time-critical thread that windows creates. 122 // They occur in a magic, time-critical thread that windows creates.
129 MMRESULT result = ::waveOutOpen(&waveout_, device_id_, 123 MMRESULT result = ::waveOutOpen(&waveout_, device_id_,
130 reinterpret_cast<LPCWAVEFORMATEX>(&format_), 124 reinterpret_cast<LPCWAVEFORMATEX>(&format_),
131 reinterpret_cast<DWORD_PTR>(WaveCallback), 125 reinterpret_cast<DWORD_PTR>(WaveCallback),
132 reinterpret_cast<DWORD_PTR>(this), 126 reinterpret_cast<DWORD_PTR>(this),
133 CALLBACK_FUNCTION); 127 CALLBACK_FUNCTION);
134 if (result != MMSYSERR_NOERROR) 128 if (result != MMSYSERR_NOERROR)
135 return false; 129 return false;
136 130
137 SetupBuffers(); 131 SetupBuffers();
138 state_ = PCMA_READY; 132 state_ = PCMA_READY;
139 return true; 133 return true;
140 } 134 }
141 135
142 void PCMWaveOutAudioOutputStream::SetupBuffers() { 136 void PCMWaveOutAudioOutputStream::SetupBuffers() {
143 WAVEHDR* last = NULL; 137 buffers_ = new char[CbBuffer() * num_buffers_];
144 WAVEHDR* first = NULL;
145 for (int ix = 0; ix != num_buffers_; ++ix) { 138 for (int ix = 0; ix != num_buffers_; ++ix) {
146 uint32 sz = sizeof(WAVEHDR) + buffer_size_; 139 WAVEHDR *buffer = GetBuffer(ix);
147 buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]); 140 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR);
148 buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR); 141 buffer->dwBufferLength = buffer_size_;
149 buffer_->dwBufferLength = buffer_size_; 142 buffer->dwBytesRecorded = 0;
150 buffer_->dwBytesRecorded = 0; 143 buffer->dwUser = 0;
151 buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last); 144 buffer->dwFlags = WHDR_DONE;
152 buffer_->dwFlags = WHDR_DONE; 145 buffer->dwLoops = 0;
153 buffer_->dwLoops = 0;
154 if (ix == 0)
155 first = buffer_;
156 last = buffer_;
157 // Tell windows sound drivers about our buffers. Not documented what 146 // Tell windows sound drivers about our buffers. Not documented what
158 // this does but we can guess that causes the OS to keep a reference to 147 // this does but we can guess that causes the OS to keep a reference to
159 // the memory pages so the driver can use them without worries. 148 // the memory pages so the driver can use them without worries.
160 ::waveOutPrepareHeader(waveout_, buffer_, sizeof(WAVEHDR)); 149 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR));
161 } 150 }
162 // Fix the first buffer to point to the last one.
163 first->dwUser = reinterpret_cast<DWORD_PTR>(last);
164 } 151 }
165 152
166 void PCMWaveOutAudioOutputStream::FreeBuffers() { 153 void PCMWaveOutAudioOutputStream::FreeBuffers() {
167 WAVEHDR* current = buffer_;
168 for (int ix = 0; ix != num_buffers_; ++ix) { 154 for (int ix = 0; ix != num_buffers_; ++ix) {
169 WAVEHDR* next = GetNextBuffer(current); 155 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR));
170 ::waveOutUnprepareHeader(waveout_, current, sizeof(WAVEHDR));
171 delete[] reinterpret_cast<char*>(current);
172 current = next;
173 } 156 }
174 buffer_ = NULL; 157 delete[] buffers_;
tommi (sloooow) - chröme 2011/11/18 09:53:21 use scoped_array?
enal1 2011/11/19 00:59:19 Done.
175 } 158 }
176 159
177 // Initially we ask the source to fill up both audio buffers. If we don't do 160 // Initially we ask the source to fill up all audio buffers. If we don't do
178 // this then we would always get the driver callback when it is about to run 161 // this then we would always get the driver callback when it is about to run
179 // samples and that would leave too little time to react. 162 // samples and that would leave too little time to react.
180 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { 163 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) {
181 if (state_ != PCMA_READY) 164 if (state_ != PCMA_READY)
182 return; 165 return;
183 callback_ = callback; 166 callback_ = callback;
184 state_ = PCMA_PLAYING; 167 state_ = PCMA_PLAYING;
168
169 // Place "this" into map. Do it under global lock.
170 {
171 base::AutoLock auto_lock(g_lock_);
172 ordinal_ = g_ordinal_;
173 ++g_ordinal_;
174 DCHECK(g_streams_map_->find(this) == g_streams_map_->end());
175 (*g_streams_map_)[this] = ordinal_;
176 }
177
178 // Queue the buffers.
179 // TODO(enal): If there are more than 2, queue only first 2 and schedule
180 // remaining to be filled in the "feeder" thread. Non-trivial because we have
181 // to be sure that data is ready. Can be done by storing time of last
182 // OnMoreData() call and scheduling delayed task in FeedBuffer() if data is
183 // not ready yet.
185 pending_bytes_ = 0; 184 pending_bytes_ = 0;
186 WAVEHDR* buffer = buffer_;
187 for (int ix = 0; ix != num_buffers_; ++ix) { 185 for (int ix = 0; ix != num_buffers_; ++ix) {
186 WAVEHDR* buffer = GetBuffer(ix);
187 buffer->dwUser = ordinal_;
188 // 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,
189 // so we wait for them here. 189 // so we wait for them here.
190 if (ix != 0) 190 if (ix != 0)
191 callback_->WaitTillDataReady(); 191 callback_->WaitTillDataReady();
192 QueueNextPacket(buffer); // Read more data. 192 QueueNextPacket(buffer); // Read more data.
193 pending_bytes_ += buffer->dwBufferLength; 193 pending_bytes_ += buffer->dwBufferLength;
194 buffer = GetNextBuffer(buffer);
195 } 194 }
196 buffer = buffer_;
197 195
198 // From now on |pending_bytes_| would be accessed by callback thread. 196 // From now on |pending_bytes_| would be accessed by callback thread.
199 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, 197 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier,
200 // but issuing our own is safer. 198 // but issuing our own is safer.
201 MemoryBarrier(); 199 MemoryBarrier();
202 200
203 MMRESULT result = ::waveOutPause(waveout_); 201 MMRESULT result = ::waveOutPause(waveout_);
204 if (result != MMSYSERR_NOERROR) { 202 if (result != MMSYSERR_NOERROR) {
205 HandleError(result); 203 HandleError(result);
206 return; 204 return;
207 } 205 }
208 206
209 // Send the buffers to the audio driver. Note that the device is paused 207 // Send the buffers to the audio driver. Note that the device is paused
210 // so we avoid entering the callback method while still here. 208 // so we avoid entering the callback method while still here.
211 for (int ix = 0; ix != num_buffers_; ++ix) { 209 for (int ix = 0; ix != num_buffers_; ++ix) {
212 result = ::waveOutWrite(waveout_, buffer, sizeof(WAVEHDR)); 210 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR));
213 if (result != MMSYSERR_NOERROR) { 211 if (result != MMSYSERR_NOERROR) {
214 HandleError(result); 212 HandleError(result);
215 break; 213 break;
216 } 214 }
217 buffer = GetNextBuffer(buffer);
218 } 215 }
219 result = ::waveOutRestart(waveout_); 216 result = ::waveOutRestart(waveout_);
220 if (result != MMSYSERR_NOERROR) { 217 if (result != MMSYSERR_NOERROR) {
221 HandleError(result); 218 HandleError(result);
222 return; 219 return;
223 } 220 }
224 } 221 }
225 222
226 // Stopping is tricky. First, no buffer should be locked by the audio driver 223 // Stopping is tricky. We want to avoid stopping while feeder thread feeds
227 // or else the waveOutReset() will deadlock and secondly, the callback should 224 // buffer to driver, so
228 // not be inside the AudioSource's OnMoreData because waveOutReset() forcefully 225 // * Here:
229 // kills the callback thread after releasing all buffers. 226 // (a) get object lock
tommi (sloooow) - chröme 2011/11/18 09:53:21 why do we need the object lock while we hold the o
enal1 2011/11/19 00:59:19 Got rid of other lock. Done.
227 // (b) get global lock
228 // (c) remove object from map
229 // (d) release both locks
230 // ...do real stopping...
231 // * In feeder thread:
232 // (e) get global lock
233 // (f) if object is not in the map, exit
234 // (g) try getting object lock; if fail, exit
235 // (h) release global lock
236 // ...do real feeding...
237 // There is no way for object to be alive in (f) but stopped/deleted in (g).
238 // For object to be stopped between (f) and (g), Stop() should acquire global
239 // lock, but it is already acquired by feeder. So it is safe to touch object
240 // lock at (g)...
230 void PCMWaveOutAudioOutputStream::Stop() { 241 void PCMWaveOutAudioOutputStream::Stop() {
231 if (state_ != PCMA_PLAYING) 242 if (state_ != PCMA_PLAYING)
232 return; 243 return;
244 state_ = PCMA_STOPPING;
245 MMRESULT res = MMSYSERR_NOERROR;
246 {
247 base::AutoLock auto_lock(lock_);
233 248
234 // Enter into critical section and call ::waveOutReset(). The fact that we 249 // Remove us from the map.
235 // entered critical section means that callback is out of critical section and 250 {
236 // it is safe to reset. 251 base::AutoLock auto_lock(g_lock_);
237 ::EnterCriticalSection(&lock_); 252 g_streams_map_->erase(this);
238 MMRESULT res = ::waveOutReset(waveout_); 253 }
239 ::LeaveCriticalSection(&lock_); 254 res = ::waveOutReset(waveout_);
255 }
240 if (res != MMSYSERR_NOERROR) { 256 if (res != MMSYSERR_NOERROR) {
241 HandleError(res); 257 HandleError(res);
242 return; 258 return;
243 } 259 }
tommi (sloooow) - chröme 2011/11/18 09:53:21 it's ok to keep the empty line below this one imo.
enal1 2011/11/19 00:59:19 Done.
244
245 // Don't use callback after Stop(). 260 // Don't use callback after Stop().
246 callback_ = NULL; 261 callback_ = NULL;
247
248 state_ = PCMA_READY; 262 state_ = PCMA_READY;
249 } 263 }
250 264
251 // We can Close in any state except that trying to close a stream that is 265 // We can Close in any state except that trying to close a stream that is
252 // playing Windows generates an error, which we propagate to the source. 266 // playing Windows generates an error, which we propagate to the source.
253 void PCMWaveOutAudioOutputStream::Close() { 267 void PCMWaveOutAudioOutputStream::Close() {
254 if (waveout_) { 268 if (waveout_) {
255 // waveOutClose generates a callback with WOM_CLOSE id in the same thread. 269 // waveOutClose generates a callback with WOM_CLOSE id in the same thread.
256 MMRESULT res = ::waveOutClose(waveout_); 270 MMRESULT res = ::waveOutClose(waveout_);
257 if (res != MMSYSERR_NOERROR) { 271 if (res != MMSYSERR_NOERROR) {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 format_.Format.wBitsPerSample >> 3, 323 format_.Format.wBitsPerSample >> 3,
310 volume_); 324 volume_);
311 } 325 }
312 } else { 326 } else {
313 HandleError(0); 327 HandleError(0);
314 return; 328 return;
315 } 329 }
316 buffer->dwFlags = WHDR_PREPARED; 330 buffer->dwFlags = WHDR_PREPARED;
317 } 331 }
318 332
333 void PCMWaveOutAudioOutputStream::FeedBuffer(
334 PCMWaveOutAudioOutputStream* stream,
335 WAVEHDR* buffer,
336 HWAVEOUT hwo,
337 DWORD ordinal) {
338 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::FeedBuffer");
339 // Is stream still alive and playing? Check is tricky.
340 // See comment in PCMWaveOutAudioOutputStream::Stop() explaining what
341 // exactly happens.
tommi (sloooow) - chröme 2011/11/18 09:53:21 Are we doing this check to avoid touching an objec
enal1 2011/11/19 00:59:19 Yes, we had very complicated checking to avoid tou
342 bool stopped = true;
343 {
344 base::AutoLock auto_lock(g_lock_);
345 std::map<PCMWaveOutAudioOutputStream*, DWORD>::iterator it =
346 g_streams_map_->find(stream);
347 stopped = (it == g_streams_map_->end() ||
348 it->second != ordinal ||
349 !stream->lock_.Try());
tommi (sloooow) - chröme 2011/11/18 09:53:21 Maybe add a comment that here is where you acquire
enal1 2011/11/19 00:59:19 Code totally rewritten.
350 }
351 if (stopped)
tommi (sloooow) - chröme 2011/11/18 09:53:21 what about checking the state_ variable for != PCM
enal1 2011/11/19 00:59:19 Again, could not do that because object could be d
352 return;
353
354 // Before we queue the next packet, we need to adjust the number of
355 // pending bytes since the last write to hardware.
356 stream->pending_bytes_ -= buffer->dwBufferLength;
357
358 stream->QueueNextPacket(buffer);
359
360 // Time to send the buffer to the audio driver. Since we are reusing
361 // the same buffers we can get away without calling waveOutPrepareHeader.
362 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR));
363 if (result != MMSYSERR_NOERROR)
364 stream->HandleError(result);
365
366 stream->pending_bytes_ += buffer->dwBufferLength;
367 stream->lock_.Release();
368 }
369
319 // Windows call us back in this function when some events happen. Most notably 370 // Windows call us back in this function when some events happen. Most notably
320 // when it is done playing a buffer. Since we use double buffering it is 371 // when it is done playing a buffer. Cannot feed freed buffer back to the system
321 // convenient to think of |buffer| as free and GetNextBuffer(buffer) as in 372 // from here, have to schedule it for the separate therad.
tommi (sloooow) - chröme 2011/11/18 09:53:21 therad -> thread
enal1 2011/11/19 00:59:19 Done.
322 // use by the driver.
323 void PCMWaveOutAudioOutputStream::WaveCallback(HWAVEOUT hwo, UINT msg, 373 void PCMWaveOutAudioOutputStream::WaveCallback(HWAVEOUT hwo, UINT msg,
324 DWORD_PTR instance, 374 DWORD_PTR instance,
325 DWORD_PTR param1, DWORD_PTR) { 375 DWORD_PTR param1, DWORD_PTR) {
326 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::WaveCallback"); 376 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::WaveCallback");
327 377
328 if (msg == WOM_DONE) { 378 if (msg == WOM_DONE) {
329 // WOM_DONE indicates that the driver is done with our buffer, we can 379 // WOM_DONE indicates that the driver is done with our buffer,
330 // either ask the source for more data or check if we need to stop playing. 380 // if still playing ask "feedef" thread to buffer more data.
331 WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1); 381 WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1);
332 buffer->dwFlags = WHDR_DONE; 382 buffer->dwFlags = WHDR_DONE;
333 383
334 PCMWaveOutAudioOutputStream* stream = 384 PCMWaveOutAudioOutputStream* stream =
335 reinterpret_cast<PCMWaveOutAudioOutputStream*>(instance); 385 reinterpret_cast<PCMWaveOutAudioOutputStream*>(instance);
336 386
337 // Do real work only if main thread has not yet called waveOutReset(). 387 if (stream->state_ == PCMA_PLAYING) {
338 if (::TryEnterCriticalSection(&stream->lock_)) { 388 stream->manager_->GetMessageLoop()->PostTask(
339 // Before we queue the next packet, we need to adjust the number of 389 FROM_HERE,
340 // pending bytes since the last write to hardware. 390 base::Bind(&PCMWaveOutAudioOutputStream::FeedBuffer,
341 stream->pending_bytes_ -= buffer->dwBufferLength; 391 stream,
342 392 buffer,
343 stream->QueueNextPacket(buffer); 393 hwo,
344 394 buffer->dwUser));
345 // Time to send the buffer to the audio driver. Since we are reusing
346 // the same buffers we can get away without calling waveOutPrepareHeader.
347 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR));
348 if (result != MMSYSERR_NOERROR)
349 stream->HandleError(result);
350
351 stream->pending_bytes_ += buffer->dwBufferLength;
352 ::LeaveCriticalSection(&stream->lock_);
353 } 395 }
354 } 396 }
355 } 397 }
398 // Initialize globals, if necessary. Use double-checked locking,
399 // it is safe on Windows as long as you are checking volatile variable.
400 // static
401 void PCMWaveOutAudioOutputStream::InitializeGlobalsIfNecessary() {
402 if (g_ordinal_ == 0) {
403 base::AutoLock auto_lock(g_lock_);
404 if (g_ordinal_ == 0) {
405 g_streams_map_.reset(new std::map<PCMWaveOutAudioOutputStream*, DWORD>);
406 base::AtExitManager::RegisterCallback(
407 &PCMWaveOutAudioOutputStream::CleanupGlobals, NULL);
408 // Volatile stores have release semantics, no separate memory
409 // barrier necessary.
410 g_ordinal_ = 1;
411 }
412 }
413 }
414
415 // static
416 void PCMWaveOutAudioOutputStream::CleanupGlobals(void* not_used) {
417 g_streams_map_.reset(NULL);
418 }
OLDNEW
« media/audio/win/waveout_output_win.h ('K') | « 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