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

Side by Side Diff: media/audio/audio_output_device.cc

Issue 1323403005: Allow AudioOutputDevice objects to be initialized with a specific hardware output device and store … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Palmer's comments Created 5 years, 3 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
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/audio_output_device.h" 5 #include "media/audio/audio_output_device.h"
6 6
7 #include <string>
8
9 #include "base/callback_helpers.h" 7 #include "base/callback_helpers.h"
10 #include "base/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
11 #include "base/time/time.h" 9 #include "base/time/time.h"
12 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
13 #include "media/audio/audio_output_controller.h" 11 #include "media/audio/audio_output_controller.h"
14 #include "media/base/limits.h" 12 #include "media/base/limits.h"
15 13
16 namespace media { 14 namespace media {
17 15
18 // Takes care of invoking the render callback on the audio thread. 16 // Takes care of invoking the render callback on the audio thread.
(...skipping 15 matching lines...) Expand all
34 32
35 private: 33 private:
36 AudioRendererSink::RenderCallback* render_callback_; 34 AudioRendererSink::RenderCallback* render_callback_;
37 scoped_ptr<AudioBus> output_bus_; 35 scoped_ptr<AudioBus> output_bus_;
38 uint64 callback_num_; 36 uint64 callback_num_;
39 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 37 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
40 }; 38 };
41 39
42 AudioOutputDevice::AudioOutputDevice( 40 AudioOutputDevice::AudioOutputDevice(
43 scoped_ptr<AudioOutputIPC> ipc, 41 scoped_ptr<AudioOutputIPC> ipc,
44 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) 42 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
43 int session_id,
44 const std::string& device_id,
45 const url::Origin& security_origin)
45 : ScopedTaskRunnerObserver(io_task_runner), 46 : ScopedTaskRunnerObserver(io_task_runner),
46 callback_(NULL), 47 callback_(NULL),
47 ipc_(ipc.Pass()), 48 ipc_(ipc.Pass()),
48 state_(IDLE), 49 state_(IDLE),
50 start_on_authorized_(false),
49 play_on_start_(true), 51 play_on_start_(true),
50 session_id_(-1), 52 session_id_(session_id),
53 device_id_(device_id),
54 security_origin_(security_origin),
51 stopping_hack_(false), 55 stopping_hack_(false),
52 current_switch_request_id_(0) { 56 switch_output_device_on_start_(false),
57 did_set_output_params_(true, false) {
53 CHECK(ipc_); 58 CHECK(ipc_);
54 59
55 // The correctness of the code depends on the relative values assigned in the 60 // The correctness of the code depends on the relative values assigned in the
56 // State enum. 61 // State enum.
57 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 62 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
58 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1"); 63 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
59 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 2"); 64 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2");
60 static_assert(PAUSED < PLAYING, "invalid enum value assignment 3"); 65 static_assert(AUTHORIZED < CREATING_STREAM,
61 } 66 "invalid enum value assignment 3");
62 67 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4");
63 void AudioOutputDevice::InitializeWithSessionId(const AudioParameters& params, 68 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5");
64 RenderCallback* callback,
65 int session_id) {
66 DCHECK(!callback_) << "Calling InitializeWithSessionId() twice?";
67 DCHECK(params.IsValid());
68 audio_parameters_ = params;
69 callback_ = callback;
70 session_id_ = session_id;
71 } 69 }
72 70
73 void AudioOutputDevice::Initialize(const AudioParameters& params, 71 void AudioOutputDevice::Initialize(const AudioParameters& params,
74 RenderCallback* callback) { 72 RenderCallback* callback) {
75 InitializeWithSessionId(params, callback, 0); 73 DCHECK(!callback_) << "Calling Initialize() twice?";
74 DCHECK(params.IsValid());
75 audio_parameters_ = params;
76 callback_ = callback;
76 } 77 }
77 78
78 AudioOutputDevice::~AudioOutputDevice() { 79 AudioOutputDevice::~AudioOutputDevice() {
79 // The current design requires that the user calls Stop() before deleting 80 // The current design requires that the user calls Stop() before deleting
80 // this class. 81 // this class.
81 DCHECK(audio_thread_.IsStopped()); 82 DCHECK(audio_thread_.IsStopped());
82 83
83 // The following makes it possible for |current_switch_callback_| to release 84 // The following makes it possible for |current_switch_callback_| to release
84 // its bound parameters in the correct thread instead of implicitly releasing 85 // its bound parameters in the correct thread instead of implicitly releasing
85 // them in the thread where this destructor runs. 86 // them in the thread where this destructor runs.
86 if (!current_switch_callback_.is_null()) { 87 if (!current_switch_callback_.is_null()) {
87 base::ResetAndReturn(&current_switch_callback_).Run( 88 base::ResetAndReturn(&current_switch_callback_)
88 SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE); 89 .Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
89 } 90 }
91
92 // Unblock any blocked threads waiting for parameters
93 did_set_output_params_.Signal();
94 }
95
96 void AudioOutputDevice::RequestDeviceAuthorization() {
97 task_runner()->PostTask(
98 FROM_HERE,
99 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
100 this));
90 } 101 }
91 102
92 void AudioOutputDevice::Start() { 103 void AudioOutputDevice::Start() {
93 DCHECK(callback_) << "Initialize hasn't been called"; 104 DCHECK(callback_) << "Initialize hasn't been called";
94 task_runner()->PostTask(FROM_HERE, 105 task_runner()->PostTask(FROM_HERE,
95 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 106 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this,
96 audio_parameters_)); 107 audio_parameters_));
97 } 108 }
98 109
99 void AudioOutputDevice::Stop() { 110 void AudioOutputDevice::Stop() {
(...skipping 28 matching lines...) Expand all
128 139
129 return true; 140 return true;
130 } 141 }
131 142
132 OutputDevice* AudioOutputDevice::GetOutputDevice() { 143 OutputDevice* AudioOutputDevice::GetOutputDevice() {
133 return this; 144 return this;
134 } 145 }
135 146
136 void AudioOutputDevice::SwitchOutputDevice( 147 void AudioOutputDevice::SwitchOutputDevice(
137 const std::string& device_id, 148 const std::string& device_id,
138 const GURL& security_origin, 149 const url::Origin& security_origin,
139 const SwitchOutputDeviceCB& callback) { 150 const SwitchOutputDeviceCB& callback) {
140 DVLOG(1) << __FUNCTION__ << "(" << device_id << ")";
141 task_runner()->PostTask( 151 task_runner()->PostTask(
142 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread, 152 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread,
143 this, device_id, security_origin, callback)); 153 this, device_id, security_origin, callback));
144 } 154 }
145 155
156 AudioParameters AudioOutputDevice::GetOutputParameters() {
157 CHECK(!task_runner()->BelongsToCurrentThread());
158 did_set_output_params_.Wait();
159 return output_params_;
160 }
161
162 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
163 DCHECK(task_runner()->BelongsToCurrentThread());
164 DCHECK_EQ(state_, IDLE);
165 state_ = AUTHORIZING;
166 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
167 security_origin_);
168 }
169
146 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 170 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) {
147 DCHECK(task_runner()->BelongsToCurrentThread()); 171 DCHECK(task_runner()->BelongsToCurrentThread());
148 if (state_ == IDLE) { 172 switch (state_) {
149 state_ = CREATING_STREAM; 173 case IPC_CLOSED:
150 ipc_->CreateStream(this, params, session_id_); 174 if (callback_)
175 callback_->OnRenderError();
176 break;
177
178 case IDLE:
179 if (did_set_output_params_.IsSignaled() && device_id_.empty() &&
180 security_origin_.unique()) {
181 state_ = CREATING_STREAM;
182 ipc_->CreateStream(this, params);
183 } else {
184 RequestDeviceAuthorizationOnIOThread();
185 start_on_authorized_ = true;
186 }
187 break;
188
189 case AUTHORIZING:
190 start_on_authorized_ = true;
191 break;
192
193 case AUTHORIZED:
194 state_ = CREATING_STREAM;
195 ipc_->CreateStream(this, params);
196 start_on_authorized_ = false;
197 break;
198
199 case CREATING_STREAM:
200 case PAUSED:
201 case PLAYING:
202 NOTREACHED();
203 break;
151 } 204 }
152 } 205 }
153 206
154 void AudioOutputDevice::PlayOnIOThread() { 207 void AudioOutputDevice::PlayOnIOThread() {
155 DCHECK(task_runner()->BelongsToCurrentThread()); 208 DCHECK(task_runner()->BelongsToCurrentThread());
156 if (state_ == PAUSED) { 209 if (state_ == PAUSED) {
157 TRACE_EVENT_ASYNC_BEGIN0( 210 TRACE_EVENT_ASYNC_BEGIN0(
158 "audio", "StartingPlayback", audio_callback_.get()); 211 "audio", "StartingPlayback", audio_callback_.get());
159 ipc_->PlayStream(); 212 ipc_->PlayStream();
160 state_ = PLAYING; 213 state_ = PLAYING;
(...skipping 11 matching lines...) Expand all
172 ipc_->PauseStream(); 225 ipc_->PauseStream();
173 state_ = PAUSED; 226 state_ = PAUSED;
174 } 227 }
175 play_on_start_ = false; 228 play_on_start_ = false;
176 } 229 }
177 230
178 void AudioOutputDevice::ShutDownOnIOThread() { 231 void AudioOutputDevice::ShutDownOnIOThread() {
179 DCHECK(task_runner()->BelongsToCurrentThread()); 232 DCHECK(task_runner()->BelongsToCurrentThread());
180 233
181 // Close the stream, if we haven't already. 234 // Close the stream, if we haven't already.
182 if (state_ >= CREATING_STREAM) { 235 if (state_ >= AUTHORIZING) {
183 ipc_->CloseStream(); 236 ipc_->CloseStream();
184 state_ = IDLE; 237 state_ = IDLE;
185 } 238 }
239 start_on_authorized_ = false;
186 240
187 // We can run into an issue where ShutDownOnIOThread is called right after 241 // We can run into an issue where ShutDownOnIOThread is called right after
188 // OnStreamCreated is called in cases where Start/Stop are called before we 242 // OnStreamCreated is called in cases where Start/Stop are called before we
189 // get the OnStreamCreated callback. To handle that corner case, we call 243 // get the OnStreamCreated callback. To handle that corner case, we call
190 // Stop(). In most cases, the thread will already be stopped. 244 // Stop(). In most cases, the thread will already be stopped.
191 // 245 //
192 // Another situation is when the IO thread goes away before Stop() is called 246 // Another situation is when the IO thread goes away before Stop() is called
193 // in which case, we cannot use the message loop to close the thread handle 247 // in which case, we cannot use the message loop to close the thread handle
194 // and can't rely on the main thread existing either. 248 // and can't rely on the main thread existing either.
195 base::AutoLock auto_lock_(audio_thread_lock_); 249 base::AutoLock auto_lock_(audio_thread_lock_);
196 base::ThreadRestrictions::ScopedAllowIO allow_io; 250 base::ThreadRestrictions::ScopedAllowIO allow_io;
197 audio_thread_.Stop(NULL); 251 audio_thread_.Stop(NULL);
198 audio_callback_.reset(); 252 audio_callback_.reset();
199 stopping_hack_ = false; 253 stopping_hack_ = false;
200 } 254 }
201 255
202 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 256 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
203 DCHECK(task_runner()->BelongsToCurrentThread()); 257 DCHECK(task_runner()->BelongsToCurrentThread());
204 if (state_ >= CREATING_STREAM) 258 if (state_ >= CREATING_STREAM)
205 ipc_->SetVolume(volume); 259 ipc_->SetVolume(volume);
206 } 260 }
207 261
208 void AudioOutputDevice::SwitchOutputDeviceOnIOThread( 262 void AudioOutputDevice::SwitchOutputDeviceOnIOThread(
209 const std::string& device_id, 263 const std::string& device_id,
210 const GURL& security_origin, 264 const url::Origin& security_origin,
211 const SwitchOutputDeviceCB& callback) { 265 const SwitchOutputDeviceCB& callback) {
212 DCHECK(task_runner()->BelongsToCurrentThread()); 266 DCHECK(task_runner()->BelongsToCurrentThread());
213 DVLOG(1) << __FUNCTION__ << "(" << device_id << "," << security_origin << ")"; 267
268 // Do not allow concurrent SwitchOutputDevice requests
269 if (!current_switch_callback_.is_null()) {
270 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
271 return;
272 }
273
274 current_switch_callback_ = callback;
275 current_switch_device_id_ = device_id;
276 current_switch_security_origin_ = security_origin;
214 if (state_ >= CREATING_STREAM) { 277 if (state_ >= CREATING_STREAM) {
215 SetCurrentSwitchRequest(callback); 278 ipc_->SwitchOutputDevice(current_switch_device_id_,
216 ipc_->SwitchOutputDevice(device_id, security_origin, 279 current_switch_security_origin_);
217 current_switch_request_id_);
218 } else { 280 } else {
219 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED); 281 switch_output_device_on_start_ = true;
220 } 282 }
221 } 283 }
222 284
223 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 285 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
224 DCHECK(task_runner()->BelongsToCurrentThread()); 286 DCHECK(task_runner()->BelongsToCurrentThread());
225 287
226 // Do nothing if the stream has been closed. 288 // Do nothing if the stream has been closed.
227 if (state_ < CREATING_STREAM) 289 if (state_ < CREATING_STREAM)
228 return; 290 return;
229 291
(...skipping 13 matching lines...) Expand all
243 // a callback object via Start() and clear it in Stop(). 305 // a callback object via Start() and clear it in Stop().
244 if (!audio_thread_.IsStopped()) 306 if (!audio_thread_.IsStopped())
245 callback_->OnRenderError(); 307 callback_->OnRenderError();
246 break; 308 break;
247 default: 309 default:
248 NOTREACHED(); 310 NOTREACHED();
249 break; 311 break;
250 } 312 }
251 } 313 }
252 314
315 void AudioOutputDevice::OnDeviceAuthorized(
316 bool success,
317 const media::AudioParameters& output_params) {
318 DCHECK(task_runner()->BelongsToCurrentThread());
319 DCHECK_EQ(state_, AUTHORIZING);
320
321 if (success) {
322 state_ = AUTHORIZED;
323 if (!did_set_output_params_.IsSignaled()) {
324 output_params_ = output_params;
325 did_set_output_params_.Signal();
326 }
327 if (start_on_authorized_)
328 CreateStreamOnIOThread(audio_parameters_);
329 } else {
330 OnIPCClosed();
331 if (callback_)
332 callback_->OnRenderError();
333 }
334 }
335
253 void AudioOutputDevice::OnStreamCreated( 336 void AudioOutputDevice::OnStreamCreated(
254 base::SharedMemoryHandle handle, 337 base::SharedMemoryHandle handle,
255 base::SyncSocket::Handle socket_handle, 338 base::SyncSocket::Handle socket_handle,
256 int length) { 339 int length) {
257 DCHECK(task_runner()->BelongsToCurrentThread()); 340 DCHECK(task_runner()->BelongsToCurrentThread());
258 DCHECK(base::SharedMemory::IsHandleValid(handle)); 341 DCHECK(base::SharedMemory::IsHandleValid(handle));
259 #if defined(OS_WIN) 342 #if defined(OS_WIN)
260 DCHECK(socket_handle); 343 DCHECK(socket_handle);
261 #else 344 #else
262 DCHECK_GE(socket_handle, 0); 345 DCHECK_GE(socket_handle, 0);
263 #endif 346 #endif
264 DCHECK_GT(length, 0); 347 DCHECK_GT(length, 0);
265 348
266 if (state_ != CREATING_STREAM) 349 if (state_ != CREATING_STREAM)
267 return; 350 return;
268 351
269 // We can receive OnStreamCreated() on the IO thread after the client has 352 // We can receive OnStreamCreated() on the IO thread after the client has
270 // called Stop() but before ShutDownOnIOThread() is processed. In such a 353 // called Stop() but before ShutDownOnIOThread() is processed. In such a
271 // situation |callback_| might point to freed memory. Instead of starting 354 // situation |callback_| might point to freed memory. Instead of starting
272 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 355 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
273 // 356 //
274 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 357 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
275 // that |callback_| (which should own and outlive this object!) can point to 358 // that |callback_| (which should own and outlive this object!) can point to
276 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 359 // freed memory is a mess. AudioRendererSink should be non-refcounted so that
277 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 360 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
278 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 361 // delete as they see fit. AudioOutputDevice should internally use WeakPtr
279 // to handle teardown and thread hopping. See http://crbug.com/151051 for 362 // to handle teardown and thread hopping. See http://crbug.com/151051 for
280 // details. 363 // details.
281 base::AutoLock auto_lock(audio_thread_lock_); 364 {
282 if (stopping_hack_) 365 base::AutoLock auto_lock(audio_thread_lock_);
283 return; 366 if (stopping_hack_)
367 return;
284 368
285 DCHECK(audio_thread_.IsStopped()); 369 DCHECK(audio_thread_.IsStopped());
286 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 370 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
287 audio_parameters_, handle, length, callback_)); 371 audio_parameters_, handle, length, callback_));
288 audio_thread_.Start( 372 audio_thread_.Start(audio_callback_.get(), socket_handle,
289 audio_callback_.get(), socket_handle, "AudioOutputDevice", true); 373 "AudioOutputDevice", true);
290 state_ = PAUSED; 374 state_ = PAUSED;
291 375
292 // We handle the case where Play() and/or Pause() may have been called 376 // We handle the case where Play() and/or Pause() may have been called
293 // multiple times before OnStreamCreated() gets called. 377 // multiple times before OnStreamCreated() gets called.
294 if (play_on_start_) 378 if (play_on_start_)
295 PlayOnIOThread(); 379 PlayOnIOThread();
296 } 380 }
297 381
298 void AudioOutputDevice::SetCurrentSwitchRequest( 382 if (switch_output_device_on_start_) {
299 const SwitchOutputDeviceCB& callback) { 383 ipc_->SwitchOutputDevice(current_switch_device_id_,
300 DCHECK(task_runner()->BelongsToCurrentThread()); 384 current_switch_security_origin_);
301 DVLOG(1) << __FUNCTION__;
302 // If there is a previous unresolved request, resolve it as obsolete
303 if (!current_switch_callback_.is_null()) {
304 base::ResetAndReturn(&current_switch_callback_).Run(
305 SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE);
306 } 385 }
307 current_switch_callback_ = callback;
308 current_switch_request_id_++;
309 } 386 }
310 387
311 void AudioOutputDevice::OnOutputDeviceSwitched( 388 void AudioOutputDevice::OnOutputDeviceSwitched(
312 int request_id,
313 SwitchOutputDeviceResult result) { 389 SwitchOutputDeviceResult result) {
314 DCHECK(task_runner()->BelongsToCurrentThread()); 390 DCHECK(task_runner()->BelongsToCurrentThread());
315 DCHECK(request_id <= current_switch_request_id_); 391 if (result == SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS) {
316 DVLOG(1) << __FUNCTION__ 392 session_id_ = 0; // Output device is no longer attached to an input device
317 << "(" << request_id << ", " << result << ")"; 393 device_id_ = current_switch_device_id_;
318 if (request_id != current_switch_request_id_) { 394 security_origin_ = current_switch_security_origin_;
319 return;
320 } 395 }
396 DCHECK(!current_switch_callback_.is_null());
321 base::ResetAndReturn(&current_switch_callback_).Run(result); 397 base::ResetAndReturn(&current_switch_callback_).Run(result);
322 } 398 }
323 399
324 void AudioOutputDevice::OnIPCClosed() { 400 void AudioOutputDevice::OnIPCClosed() {
325 DCHECK(task_runner()->BelongsToCurrentThread()); 401 DCHECK(task_runner()->BelongsToCurrentThread());
326 state_ = IPC_CLOSED; 402 state_ = IPC_CLOSED;
327 ipc_.reset(); 403 ipc_.reset();
404
405 // Signal to unblock any blocked threads waiting for parameters
406 did_set_output_params_.Signal();
328 } 407 }
329 408
330 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 409 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
331 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 410 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
332 ShutDownOnIOThread(); 411 ShutDownOnIOThread();
333 } 412 }
334 413
335 // AudioOutputDevice::AudioThreadCallback 414 // AudioOutputDevice::AudioThreadCallback
336 415
337 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 416 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this); 450 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this);
372 } 451 }
373 452
374 // Update the audio-delay measurement then ask client to render audio. Since 453 // Update the audio-delay measurement then ask client to render audio. Since
375 // |output_bus_| is wrapping the shared memory the Render() call is writing 454 // |output_bus_| is wrapping the shared memory the Render() call is writing
376 // directly into the shared memory. 455 // directly into the shared memory.
377 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds); 456 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds);
378 } 457 }
379 458
380 } // namespace media. 459 } // namespace media.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698