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

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 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
22 // Some general thoughts about the waveOut API which is badly documented : 18 // Some general thoughts about the waveOut API which is badly documented :
23 // - We use CALLBACK_FUNCTION mode in which XP secretly creates two threads 19 // - We use CALLBACK_EVENT mode in which XP signals events such as buffer
24 // named _MixerCallbackThread and _waveThread which have real-time priority. 20 // releases.
25 // The callbacks occur in _waveThread. 21 // - We use RegisterWaitForSingleObject() so one of threads in thread pool
22 // automatically calls our callback that feeds more data to Windows.
26 // - Windows does not provide a way to query if the device is playing or paused 23 // - 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 24 // thus it forces you to maintain state, which naturally is not exactly
28 // synchronized to the actual device state. 25 // 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().
36
37 // Sixty four MB is the maximum buffer size per AudioOutputStream.
38 static const uint32 kMaxOpenBufferSize = 1024 * 1024 * 64;
cpu_(ooo_6.6-7.5) 2011/11/23 22:39:56 the limits were added after a couple of security r
enal 2011/11/28 22:40:21 Constant was not used anywhere. Check was removed
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 26
46 // See Also 27 // See Also
47 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/ 28 // http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-sp eaker-set-up/
48 // http://en.wikipedia.org/wiki/Surround_sound 29 // http://en.wikipedia.org/wiki/Surround_sound
49 30
50 static const int kMaxChannelsToMask = 8; 31 static const int kMaxChannelsToMask = 8;
51 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = { 32 static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = {
52 0, 33 0,
53 // 1 = Mono 34 // 1 = Mono
54 SPEAKER_FRONT_CENTER, 35 SPEAKER_FRONT_CENTER,
(...skipping 17 matching lines...) Expand all
72 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 53 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
73 SPEAKER_BACK_CENTER, 54 SPEAKER_BACK_CENTER,
74 // 8 = 7.1 55 // 8 = 7.1
75 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 56 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
76 SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | 57 SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
77 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 58 SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
78 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT 59 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
79 // TODO(fbarchard): Add additional masks for 7.2 and beyond. 60 // TODO(fbarchard): Add additional masks for 7.2 and beyond.
80 }; 61 };
81 62
63 inline size_t PCMWaveOutAudioOutputStream::BufferSize() const {
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Why is this alignment needed? Benefits?
enal 2011/11/28 22:40:21 If data is properly aligned compiler/libraries can
64 // Round size of buffer up to the nearest 16 bytes.
65 return (sizeof(WAVEHDR) + buffer_size_ + 15u) & static_cast<size_t>(~15);
66 }
67
68 inline WAVEHDR* PCMWaveOutAudioOutputStream::GetBuffer(int n) const {
69 DCHECK_GE(n, 0);
70 DCHECK_LT(n, num_buffers_);
71 return reinterpret_cast<WAVEHDR*>(&buffers_[n * BufferSize()]);
72 }
73
74
82 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( 75 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream(
83 AudioManagerWin* manager, const AudioParameters& params, int num_buffers, 76 AudioManagerWin* manager, const AudioParameters& params, int num_buffers,
84 UINT device_id) 77 UINT device_id)
85 : state_(PCMA_BRAND_NEW), 78 : state_(PCMA_BRAND_NEW),
86 manager_(manager), 79 manager_(manager),
87 device_id_(device_id), 80 device_id_(device_id),
88 waveout_(NULL), 81 waveout_(NULL),
89 callback_(NULL), 82 callback_(NULL),
90 num_buffers_(num_buffers), 83 num_buffers_(num_buffers),
91 buffer_(NULL),
92 buffer_size_(params.GetPacketSize()), 84 buffer_size_(params.GetPacketSize()),
93 volume_(1), 85 volume_(1),
94 channels_(params.channels), 86 channels_(params.channels),
95 pending_bytes_(0) { 87 pending_bytes_(0) {
96 ::InitializeCriticalSectionAndSpinCount(&lock_, kSpinCount);
97
98 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 88 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
99 format_.Format.nChannels = params.channels; 89 format_.Format.nChannels = params.channels;
100 format_.Format.nSamplesPerSec = params.sample_rate; 90 format_.Format.nSamplesPerSec = params.sample_rate;
101 format_.Format.wBitsPerSample = params.bits_per_sample; 91 format_.Format.wBitsPerSample = params.bits_per_sample;
102 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); 92 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX);
103 // The next are computed from above. 93 // The next are computed from above.
104 format_.Format.nBlockAlign = (format_.Format.nChannels * 94 format_.Format.nBlockAlign = (format_.Format.nChannels *
105 format_.Format.wBitsPerSample) / 8; 95 format_.Format.wBitsPerSample) / 8;
106 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * 96 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign *
107 format_.Format.nSamplesPerSec; 97 format_.Format.nSamplesPerSec;
108 if (params.channels > kMaxChannelsToMask) { 98 if (params.channels > kMaxChannelsToMask) {
109 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; 99 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask];
110 } else { 100 } else {
111 format_.dwChannelMask = kChannelsToMask[params.channels]; 101 format_.dwChannelMask = kChannelsToMask[params.channels];
112 } 102 }
113 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 103 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
114 format_.Samples.wValidBitsPerSample = params.bits_per_sample; 104 format_.Samples.wValidBitsPerSample = params.bits_per_sample;
115 } 105 }
116 106
117 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { 107 PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() {
118 DCHECK(NULL == waveout_); 108 DCHECK(NULL == waveout_);
119 ::DeleteCriticalSection(&lock_);
120 } 109 }
121 110
122 bool PCMWaveOutAudioOutputStream::Open() { 111 bool PCMWaveOutAudioOutputStream::Open() {
123 if (state_ != PCMA_BRAND_NEW) 112 if (state_ != PCMA_BRAND_NEW)
124 return false; 113 return false;
125 if (num_buffers_ < 2 || num_buffers_ > 5) 114 if (num_buffers_ < 2 || num_buffers_ > 5)
126 return false; 115 return false;
127 // Open the device. We'll be getting callback in WaveCallback function. 116 // Create buffer event.
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Empty line above comment.
enal 2011/11/28 22:40:21 Done.
128 // They occur in a magic, time-critical thread that windows creates. 117 buffer_event_.Set(::CreateEvent(NULL, FALSE, FALSE, NULL));
cpu_(ooo_6.6-7.5) 2011/11/23 23:04:17 please add in the comment that this is an auto-res
enal 2011/11/28 22:40:21 Done.
129 MMRESULT result = ::waveOutOpen(&waveout_, device_id_, 118 if (!buffer_event_.Get()) {
130 reinterpret_cast<LPCWAVEFORMATEX>(&format_), 119 return false;
131 reinterpret_cast<DWORD_PTR>(WaveCallback), 120 }
132 reinterpret_cast<DWORD_PTR>(this), 121 // Open the device.
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Empty line above comment.
enal 2011/11/28 22:40:21 Done.
133 CALLBACK_FUNCTION); 122 // We'll be getting buffer_event_ events when it's time to refill the buffer.
123 MMRESULT result = ::waveOutOpen(
124 &waveout_,
125 device_id_,
126 reinterpret_cast<LPCWAVEFORMATEX>(&format_),
127 reinterpret_cast<DWORD_PTR>(buffer_event_.Get()),
128 NULL,
129 CALLBACK_EVENT);
134 if (result != MMSYSERR_NOERROR) 130 if (result != MMSYSERR_NOERROR)
135 return false; 131 return false;
136 132
137 SetupBuffers(); 133 SetupBuffers();
138 state_ = PCMA_READY; 134 state_ = PCMA_READY;
139 return true; 135 return true;
140 } 136 }
141 137
142 void PCMWaveOutAudioOutputStream::SetupBuffers() { 138 void PCMWaveOutAudioOutputStream::SetupBuffers() {
143 WAVEHDR* last = NULL; 139 buffers_.reset(new char[BufferSize() * num_buffers_]);
144 WAVEHDR* first = NULL;
145 for (int ix = 0; ix != num_buffers_; ++ix) { 140 for (int ix = 0; ix != num_buffers_; ++ix) {
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Can you explain some more on why you have modified
cpu_(ooo_6.6-7.5) 2011/11/23 22:39:56 +1
enal 2011/11/28 22:40:21 For historical reasons :-) It is 3rd major rewrit
146 uint32 sz = sizeof(WAVEHDR) + buffer_size_; 141 WAVEHDR* buffer = GetBuffer(ix);
147 buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]); 142 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR);
148 buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR); 143 buffer->dwBufferLength = buffer_size_;
149 buffer_->dwBufferLength = buffer_size_; 144 buffer->dwBytesRecorded = 0;
150 buffer_->dwBytesRecorded = 0; 145 buffer->dwFlags = WHDR_DONE;
151 buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last); 146 buffer->dwLoops = 0;
152 buffer_->dwFlags = WHDR_DONE;
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 147 // 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 148 // 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. 149 // the memory pages so the driver can use them without worries.
160 ::waveOutPrepareHeader(waveout_, buffer_, sizeof(WAVEHDR)); 150 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR));
161 } 151 }
162 // Fix the first buffer to point to the last one.
163 first->dwUser = reinterpret_cast<DWORD_PTR>(last);
164 } 152 }
165 153
166 void PCMWaveOutAudioOutputStream::FreeBuffers() { 154 void PCMWaveOutAudioOutputStream::FreeBuffers() {
167 WAVEHDR* current = buffer_;
168 for (int ix = 0; ix != num_buffers_; ++ix) { 155 for (int ix = 0; ix != num_buffers_; ++ix) {
169 WAVEHDR* next = GetNextBuffer(current); 156 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR));
170 ::waveOutUnprepareHeader(waveout_, current, sizeof(WAVEHDR));
171 delete[] reinterpret_cast<char*>(current);
172 current = next;
173 } 157 }
174 buffer_ = NULL; 158 buffers_.reset(NULL);
175 } 159 }
176 160
177 // Initially we ask the source to fill up both audio buffers. If we don't do 161 // 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 162 // 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. 163 // samples and that would leave too little time to react.
180 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { 164 void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) {
181 if (state_ != PCMA_READY) 165 if (state_ != PCMA_READY)
182 return; 166 return;
183 callback_ = callback; 167 callback_ = callback;
168
169 // Start watching for buffer events.
170 {
171 HANDLE waiting_handle = NULL;
172 RegisterWaitForSingleObject(&waiting_handle,
cpu_(ooo_6.6-7.5) 2011/11/23 22:39:56 use :: for windows calls.
enal 2011/11/28 22:40:21 Done.
173 buffer_event_.Get(),
174 &BufferCallback,
175 static_cast<void*>(this),
176 INFINITE,
177 WT_EXECUTEDEFAULT);
cpu_(ooo_6.6-7.5) 2011/11/23 22:39:56 People complain in the internet about the some lag
enal 2011/11/28 22:40:21 I also don't know. MSDN says 'execute long' hints
178 if (!waiting_handle) {
179 HandleError(MMSYSERR_ERROR);
180 return;
181 }
182 waiting_handle_.Set(waiting_handle);
183 }
184
184 state_ = PCMA_PLAYING; 185 state_ = PCMA_PLAYING;
186
187 // Queue the buffers.
185 pending_bytes_ = 0; 188 pending_bytes_ = 0;
186 WAVEHDR* buffer = buffer_;
187 for (int ix = 0; ix != num_buffers_; ++ix) { 189 for (int ix = 0; ix != num_buffers_; ++ix) {
190 WAVEHDR* buffer = GetBuffer(ix);
188 // Caller waits for 1st packet to become available, but not for others, 191 // Caller waits for 1st packet to become available, but not for others,
189 // so we wait for them here. 192 // so we wait for them here.
190 if (ix != 0) 193 if (ix != 0)
191 callback_->WaitTillDataReady(); 194 callback_->WaitTillDataReady();
192 QueueNextPacket(buffer); // Read more data. 195 QueueNextPacket(buffer); // Read more data.
193 pending_bytes_ += buffer->dwBufferLength; 196 pending_bytes_ += buffer->dwBufferLength;
194 buffer = GetNextBuffer(buffer);
195 } 197 }
196 buffer = buffer_;
197 198
198 // From now on |pending_bytes_| would be accessed by callback thread. 199 // From now on |pending_bytes_| would be accessed by callback thread.
199 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, 200 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier,
200 // but issuing our own is safer. 201 // but issuing our own is safer.
201 MemoryBarrier(); 202 MemoryBarrier();
202 203
203 MMRESULT result = ::waveOutPause(waveout_); 204 MMRESULT result = ::waveOutPause(waveout_);
204 if (result != MMSYSERR_NOERROR) { 205 if (result != MMSYSERR_NOERROR) {
205 HandleError(result); 206 HandleError(result);
206 return; 207 return;
207 } 208 }
208 209
209 // Send the buffers to the audio driver. Note that the device is paused 210 // Send the buffers to the audio driver. Note that the device is paused
210 // so we avoid entering the callback method while still here. 211 // so we avoid entering the callback method while still here.
211 for (int ix = 0; ix != num_buffers_; ++ix) { 212 for (int ix = 0; ix != num_buffers_; ++ix) {
212 result = ::waveOutWrite(waveout_, buffer, sizeof(WAVEHDR)); 213 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR));
213 if (result != MMSYSERR_NOERROR) { 214 if (result != MMSYSERR_NOERROR) {
214 HandleError(result); 215 HandleError(result);
215 break; 216 break;
216 } 217 }
217 buffer = GetNextBuffer(buffer);
218 } 218 }
219 result = ::waveOutRestart(waveout_); 219 result = ::waveOutRestart(waveout_);
220 if (result != MMSYSERR_NOERROR) { 220 if (result != MMSYSERR_NOERROR) {
221 HandleError(result); 221 HandleError(result);
222 return; 222 return;
223 } 223 }
224 } 224 }
225 225
226 // Stopping is tricky. First, no buffer should be locked by the audio driver 226 // Stopping is tricky if we want it be fast.
227 // or else the waveOutReset() will deadlock and secondly, the callback should 227 // For now just do it synchronously and avoid all the complexities.
228 // not be inside the AudioSource's OnMoreData because waveOutReset() forcefully 228 // TODO(enal): if we want faster Stop() we can create singleton that keeps track
229 // kills the callback thread after releasing all buffers. 229 // of all currently playing streams. Then you don't have to wait
230 // till all callbacks are completed. Of course access to singleton
231 // should be under its own lock, and checking the liveness and
232 // acquiring the lock on stream should be done atomically.
230 void PCMWaveOutAudioOutputStream::Stop() { 233 void PCMWaveOutAudioOutputStream::Stop() {
231 if (state_ != PCMA_PLAYING) 234 if (state_ != PCMA_PLAYING)
232 return; 235 return;
236 state_ = PCMA_STOPPING;
237 MemoryBarrier();
233 238
234 // Enter into critical section and call ::waveOutReset(). The fact that we 239 // Stop playback.
235 // entered critical section means that callback is out of critical section and
236 // it is safe to reset.
237 ::EnterCriticalSection(&lock_);
238 MMRESULT res = ::waveOutReset(waveout_); 240 MMRESULT res = ::waveOutReset(waveout_);
239 ::LeaveCriticalSection(&lock_);
240 if (res != MMSYSERR_NOERROR) { 241 if (res != MMSYSERR_NOERROR) {
242 state_ = PCMA_PLAYING;
241 HandleError(res); 243 HandleError(res);
242 return; 244 return;
243 } 245 }
244 246
247 // Stop watching for buffer event, wait till all the callbacks are complete.
248 BOOL unregister = UnregisterWaitEx(waiting_handle_.Take(),
249 INVALID_HANDLE_VALUE);
250 if (!unregister) {
251 state_ = PCMA_PLAYING;
252 HandleError(MMSYSERR_ERROR);
253 return;
254 }
255
256 // waveOutReset() leaves buffers in the unpredictable state, causing
257 // problems if we want to release or reuse them. Fix the states.
258 for (int ix = 0; ix != num_buffers_; ++ix) {
259 GetBuffer(ix)->dwFlags = WHDR_PREPARED;
260 }
261
245 // Don't use callback after Stop(). 262 // Don't use callback after Stop().
246 callback_ = NULL; 263 callback_ = NULL;
247 264
248 state_ = PCMA_READY; 265 state_ = PCMA_READY;
249 } 266 }
250 267
251 // We can Close in any state except that trying to close a stream that is 268 // 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. 269 // playing Windows generates an error, which we propagate to the source.
253 void PCMWaveOutAudioOutputStream::Close() { 270 void PCMWaveOutAudioOutputStream::Close() {
271 Stop(); // Just to be sure. No-op if not playing.
254 if (waveout_) { 272 if (waveout_) {
255 // waveOutClose generates a callback with WOM_CLOSE id in the same thread.
256 MMRESULT res = ::waveOutClose(waveout_); 273 MMRESULT res = ::waveOutClose(waveout_);
257 if (res != MMSYSERR_NOERROR) { 274 if (res != MMSYSERR_NOERROR) {
258 HandleError(res); 275 HandleError(res);
259 return; 276 return;
260 } 277 }
261 state_ = PCMA_CLOSED; 278 state_ = PCMA_CLOSED;
262 waveout_ = NULL; 279 waveout_ = NULL;
263 FreeBuffers(); 280 FreeBuffers();
264 } 281 }
265 // Tell the audio manager that we have been released. This can result in 282 // 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
309 format_.Format.wBitsPerSample >> 3, 326 format_.Format.wBitsPerSample >> 3,
310 volume_); 327 volume_);
311 } 328 }
312 } else { 329 } else {
313 HandleError(0); 330 HandleError(0);
314 return; 331 return;
315 } 332 }
316 buffer->dwFlags = WHDR_PREPARED; 333 buffer->dwFlags = WHDR_PREPARED;
317 } 334 }
318 335
319 // Windows call us back in this function when some events happen. Most notably 336 // Windows call us back in this function when buffer_event_ is signalled.
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Are you saying that we now can set a buffer size o
enal 2011/11/28 22:40:21 Modified comment.
320 // when it is done playing a buffer. Since we use double buffering it is 337 // Search through all the buffers looking for freed one, fill it with data,
321 // convenient to think of |buffer| as free and GetNextBuffer(buffer) as in 338 // and "feed" the Windows.
322 // use by the driver. 339 void NTAPI PCMWaveOutAudioOutputStream::BufferCallback(PVOID lpParameter,
323 void PCMWaveOutAudioOutputStream::WaveCallback(HWAVEOUT hwo, UINT msg, 340 BOOLEAN) {
324 DWORD_PTR instance, 341 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::BufferCallback");
325 DWORD_PTR param1, DWORD_PTR) {
326 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::WaveCallback");
327 342
328 if (msg == WOM_DONE) { 343 PCMWaveOutAudioOutputStream* stream =
329 // WOM_DONE indicates that the driver is done with our buffer, we can 344 reinterpret_cast<PCMWaveOutAudioOutputStream*>(lpParameter);
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;
333 345
334 PCMWaveOutAudioOutputStream* stream = 346 // Lock the stream. Two callbacks can be called simultaneously.
henrika (OOO until Aug 14) 2011/11/23 07:12:50 Please elaborate. Not sure if I understand why thi
enal 2011/11/28 22:40:21 Done.
335 reinterpret_cast<PCMWaveOutAudioOutputStream*>(instance); 347 base::AutoLock auto_lock(stream->lock_);
348 if (stream->state_ != PCMA_PLAYING)
349 return;
336 350
337 // Do real work only if main thread has not yet called waveOutReset(). 351 for (int ix = 0; ix != stream->num_buffers_; ++ix) {
338 if (::TryEnterCriticalSection(&stream->lock_)) { 352 WAVEHDR* buffer = stream->GetBuffer(ix);
353 if (buffer->dwFlags & WHDR_DONE) {
339 // Before we queue the next packet, we need to adjust the number of 354 // Before we queue the next packet, we need to adjust the number of
340 // pending bytes since the last write to hardware. 355 // pending bytes since the last write to hardware.
341 stream->pending_bytes_ -= buffer->dwBufferLength; 356 stream->pending_bytes_ -= buffer->dwBufferLength;
342
343 stream->QueueNextPacket(buffer); 357 stream->QueueNextPacket(buffer);
344
345 // Time to send the buffer to the audio driver. Since we are reusing 358 // Time to send the buffer to the audio driver. Since we are reusing
346 // the same buffers we can get away without calling waveOutPrepareHeader. 359 // the same buffers we can get away without calling waveOutPrepareHeader.
347 MMRESULT result = ::waveOutWrite(hwo, buffer, sizeof(WAVEHDR)); 360 MMRESULT result = ::waveOutWrite(stream->waveout_,
361 buffer,
362 sizeof(WAVEHDR));
348 if (result != MMSYSERR_NOERROR) 363 if (result != MMSYSERR_NOERROR)
349 stream->HandleError(result); 364 stream->HandleError(result);
350
351 stream->pending_bytes_ += buffer->dwBufferLength; 365 stream->pending_bytes_ += buffer->dwBufferLength;
352 ::LeaveCriticalSection(&stream->lock_); 366 return;
353 } 367 }
354 } 368 }
cpu_(ooo_6.6-7.5) 2011/11/23 23:04:17 looks like if the event is signaled twice while a
enal 2011/11/28 22:40:21 I doubt we can hit such a problem. We always have
355 } 369 }
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