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

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: Split permissions check and device-ID translation for clarity 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 16 matching lines...) Expand all
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 : AudioOutputDevice(ipc.Pass(),
44 io_task_runner,
45 0,
46 std::string(),
47 GURL::EmptyGURL()) {}
48
49 AudioOutputDevice::AudioOutputDevice(
50 scoped_ptr<AudioOutputIPC> ipc,
51 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
52 int session_id,
53 const std::string& device_id,
54 const GURL& security_origin)
45 : ScopedTaskRunnerObserver(io_task_runner), 55 : ScopedTaskRunnerObserver(io_task_runner),
46 callback_(NULL), 56 callback_(NULL),
47 ipc_(ipc.Pass()), 57 ipc_(ipc.Pass()),
48 state_(IDLE), 58 state_(IDLE),
49 play_on_start_(true), 59 play_on_start_(true),
50 session_id_(-1), 60 session_id_(session_id),
61 device_id_(device_id),
62 security_origin_(security_origin),
51 stopping_hack_(false), 63 stopping_hack_(false),
52 current_switch_request_id_(0) { 64 switch_output_device_on_start_(false),
65 did_set_output_params_(true, false),
66 authorization_failed_(false) {
DaleCurtis 2015/09/09 01:31:57 Should this be another state? That avoid mixing tw
Guido Urdaneta 2015/09/09 16:22:23 Done. Now we have NOT_AUTHORIZED and AUTHORIZED as
53 CHECK(ipc_); 67 CHECK(ipc_);
54 68
55 // The correctness of the code depends on the relative values assigned in the 69 // The correctness of the code depends on the relative values assigned in the
56 // State enum. 70 // State enum.
57 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 71 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
58 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1"); 72 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
59 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 2"); 73 static_assert(AUTHORIZING < CREATING_STREAM,
DaleCurtis 2015/09/09 01:31:57 Seems there should be an authorized state?
Guido Urdaneta 2015/09/09 16:22:23 Done.
60 static_assert(PAUSED < PLAYING, "invalid enum value assignment 3"); 74 "invalid enum value assignment 2");
75 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 3");
76 static_assert(PAUSED < PLAYING, "invalid enum value assignment 4");
61 } 77 }
62 78
63 void AudioOutputDevice::InitializeWithSessionId(const AudioParameters& params, 79 void AudioOutputDevice::Initialize(const AudioParameters& params,
64 RenderCallback* callback, 80 RenderCallback* callback) {
65 int session_id) {
66 DCHECK(!callback_) << "Calling InitializeWithSessionId() twice?"; 81 DCHECK(!callback_) << "Calling InitializeWithSessionId() twice?";
67 DCHECK(params.IsValid()); 82 DCHECK(params.IsValid());
68 audio_parameters_ = params; 83 audio_parameters_ = params;
69 callback_ = callback; 84 callback_ = callback;
70 session_id_ = session_id;
71 }
72
73 void AudioOutputDevice::Initialize(const AudioParameters& params,
74 RenderCallback* callback) {
75 InitializeWithSessionId(params, callback, 0);
76 } 85 }
77 86
78 AudioOutputDevice::~AudioOutputDevice() { 87 AudioOutputDevice::~AudioOutputDevice() {
79 // The current design requires that the user calls Stop() before deleting 88 // The current design requires that the user calls Stop() before deleting
80 // this class. 89 // this class.
81 DCHECK(audio_thread_.IsStopped()); 90 DCHECK(audio_thread_.IsStopped());
82 91
83 // The following makes it possible for |current_switch_callback_| to release 92 // The following makes it possible for |current_switch_callback_| to release
84 // its bound parameters in the correct thread instead of implicitly releasing 93 // its bound parameters in the correct thread instead of implicitly releasing
85 // them in the thread where this destructor runs. 94 // them in the thread where this destructor runs.
86 if (!current_switch_callback_.is_null()) { 95 if (!current_switch_callback_.is_null()) {
87 base::ResetAndReturn(&current_switch_callback_).Run( 96 base::ResetAndReturn(&current_switch_callback_)
88 SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE); 97 .Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
89 } 98 }
90 } 99 }
91 100
101 void AudioOutputDevice::RequestDeviceAuthorization() {
102 task_runner()->PostTask(
103 FROM_HERE,
104 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
105 this));
106 }
107
92 void AudioOutputDevice::Start() { 108 void AudioOutputDevice::Start() {
93 DCHECK(callback_) << "Initialize hasn't been called"; 109 DCHECK(callback_) << "Initialize hasn't been called";
94 task_runner()->PostTask(FROM_HERE, 110 task_runner()->PostTask(FROM_HERE,
95 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 111 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this,
96 audio_parameters_)); 112 audio_parameters_));
97 } 113 }
98 114
99 void AudioOutputDevice::Stop() { 115 void AudioOutputDevice::Stop() {
100 { 116 {
101 base::AutoLock auto_lock(audio_thread_lock_); 117 base::AutoLock auto_lock(audio_thread_lock_);
(...skipping 28 matching lines...) Expand all
130 } 146 }
131 147
132 OutputDevice* AudioOutputDevice::GetOutputDevice() { 148 OutputDevice* AudioOutputDevice::GetOutputDevice() {
133 return this; 149 return this;
134 } 150 }
135 151
136 void AudioOutputDevice::SwitchOutputDevice( 152 void AudioOutputDevice::SwitchOutputDevice(
137 const std::string& device_id, 153 const std::string& device_id,
138 const GURL& security_origin, 154 const GURL& security_origin,
139 const SwitchOutputDeviceCB& callback) { 155 const SwitchOutputDeviceCB& callback) {
140 DVLOG(1) << __FUNCTION__ << "(" << device_id << ")";
141 task_runner()->PostTask( 156 task_runner()->PostTask(
142 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread, 157 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread,
143 this, device_id, security_origin, callback)); 158 this, device_id, security_origin, callback));
144 } 159 }
145 160
146 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 161 AudioParameters AudioOutputDevice::GetOutputParameters() {
162 CHECK(!task_runner()->BelongsToCurrentThread());
163 did_set_output_params_.Wait();
164 return output_params_;
165 }
166
167 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
147 DCHECK(task_runner()->BelongsToCurrentThread()); 168 DCHECK(task_runner()->BelongsToCurrentThread());
169 // Request authorization only if the stream is stopped
148 if (state_ == IDLE) { 170 if (state_ == IDLE) {
DaleCurtis 2015/09/09 01:31:57 DCHECK_EQ? Nothing should be calling this before t
Guido Urdaneta 2015/09/09 16:22:23 Done.
149 state_ = CREATING_STREAM; 171 state_ = AUTHORIZING;
150 ipc_->CreateStream(this, params, session_id_); 172 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
173 security_origin_);
151 } 174 }
152 } 175 }
153 176
177 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) {
178 DCHECK(task_runner()->BelongsToCurrentThread());
179 if (authorization_failed_) {
180 callback_->OnRenderError();
181 return;
182 }
183
184 // Request device authorization again if the stream was stopped
DaleCurtis 2015/09/09 01:31:57 Why when stopped? Shouldn't authorization persist
Guido Urdaneta 2015/09/09 16:22:23 For practical reasons, authorization also ends at
185 RequestDeviceAuthorizationOnIOThread();
DaleCurtis 2015/09/09 01:31:57 Why is this necessary? If it's a non-default devic
Guido Urdaneta 2015/09/09 16:22:23 I guess my comment above explains why it is necess
186
DaleCurtis 2015/09/09 01:31:57 DCHECK(state_ == AUTHORIZING || state_ == AUTHORIZ
Guido Urdaneta 2015/09/09 16:22:23 Can also be NOT_AUTHORIZED, or IDLE after a Stop()
187 if (state_ == AUTHORIZING) {
188 state_ = CREATING_STREAM;
189 ipc_->CreateStream(this, params);
190 }
191 }
192
154 void AudioOutputDevice::PlayOnIOThread() { 193 void AudioOutputDevice::PlayOnIOThread() {
155 DCHECK(task_runner()->BelongsToCurrentThread()); 194 DCHECK(task_runner()->BelongsToCurrentThread());
156 if (state_ == PAUSED) { 195 if (state_ == PAUSED) {
157 TRACE_EVENT_ASYNC_BEGIN0( 196 TRACE_EVENT_ASYNC_BEGIN0(
158 "audio", "StartingPlayback", audio_callback_.get()); 197 "audio", "StartingPlayback", audio_callback_.get());
159 ipc_->PlayStream(); 198 ipc_->PlayStream();
160 state_ = PLAYING; 199 state_ = PLAYING;
161 play_on_start_ = false; 200 play_on_start_ = false;
162 } else { 201 } else {
163 play_on_start_ = true; 202 play_on_start_ = true;
164 } 203 }
165 } 204 }
166 205
167 void AudioOutputDevice::PauseOnIOThread() { 206 void AudioOutputDevice::PauseOnIOThread() {
168 DCHECK(task_runner()->BelongsToCurrentThread()); 207 DCHECK(task_runner()->BelongsToCurrentThread());
169 if (state_ == PLAYING) { 208 if (state_ == PLAYING) {
170 TRACE_EVENT_ASYNC_END0( 209 TRACE_EVENT_ASYNC_END0(
171 "audio", "StartingPlayback", audio_callback_.get()); 210 "audio", "StartingPlayback", audio_callback_.get());
172 ipc_->PauseStream(); 211 ipc_->PauseStream();
173 state_ = PAUSED; 212 state_ = PAUSED;
174 } 213 }
175 play_on_start_ = false; 214 play_on_start_ = false;
176 } 215 }
177 216
178 void AudioOutputDevice::ShutDownOnIOThread() { 217 void AudioOutputDevice::ShutDownOnIOThread() {
179 DCHECK(task_runner()->BelongsToCurrentThread()); 218 DCHECK(task_runner()->BelongsToCurrentThread());
180 219
181 // Close the stream, if we haven't already. 220 // Close the stream, if we haven't already.
182 if (state_ >= CREATING_STREAM) { 221 if (state_ > IDLE) {
183 ipc_->CloseStream(); 222 ipc_->CloseStream();
184 state_ = IDLE; 223 state_ = IDLE;
185 } 224 }
186 225
187 // We can run into an issue where ShutDownOnIOThread is called right after 226 // 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 227 // OnStreamCreated is called in cases where Start/Stop are called before we
189 // get the OnStreamCreated callback. To handle that corner case, we call 228 // get the OnStreamCreated callback. To handle that corner case, we call
190 // Stop(). In most cases, the thread will already be stopped. 229 // Stop(). In most cases, the thread will already be stopped.
191 // 230 //
192 // Another situation is when the IO thread goes away before Stop() is called 231 // Another situation is when the IO thread goes away before Stop() is called
(...skipping 10 matching lines...) Expand all
203 DCHECK(task_runner()->BelongsToCurrentThread()); 242 DCHECK(task_runner()->BelongsToCurrentThread());
204 if (state_ >= CREATING_STREAM) 243 if (state_ >= CREATING_STREAM)
205 ipc_->SetVolume(volume); 244 ipc_->SetVolume(volume);
206 } 245 }
207 246
208 void AudioOutputDevice::SwitchOutputDeviceOnIOThread( 247 void AudioOutputDevice::SwitchOutputDeviceOnIOThread(
209 const std::string& device_id, 248 const std::string& device_id,
210 const GURL& security_origin, 249 const GURL& security_origin,
211 const SwitchOutputDeviceCB& callback) { 250 const SwitchOutputDeviceCB& callback) {
212 DCHECK(task_runner()->BelongsToCurrentThread()); 251 DCHECK(task_runner()->BelongsToCurrentThread());
213 DVLOG(1) << __FUNCTION__ << "(" << device_id << "," << security_origin << ")"; 252
253 // Do not allow concurrent SwitchOutputDevice requests
254 if (!current_switch_callback_.is_null()) {
255 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
256 return;
257 }
258
259 current_switch_callback_ = callback;
260 current_switch_device_id_ = device_id;
261 current_switch_security_origin_ = security_origin;
214 if (state_ >= CREATING_STREAM) { 262 if (state_ >= CREATING_STREAM) {
DaleCurtis 2015/09/09 01:31:57 I think this code should instead store the current
Guido Urdaneta 2015/09/09 16:22:23 We still have the shared memory size issue. The or
215 SetCurrentSwitchRequest(callback); 263 ipc_->SwitchOutputDevice(current_switch_device_id_,
216 ipc_->SwitchOutputDevice(device_id, security_origin, 264 current_switch_security_origin_);
217 current_switch_request_id_);
218 } else { 265 } else {
219 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED); 266 switch_output_device_on_start_ = true;
DaleCurtis 2015/09/09 01:31:57 Instead of having this, can we set the state back
Guido Urdaneta 2015/09/09 16:22:23 This isn't intended to address authorization probl
220 } 267 }
221 } 268 }
222 269
223 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 270 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
224 DCHECK(task_runner()->BelongsToCurrentThread()); 271 DCHECK(task_runner()->BelongsToCurrentThread());
225 272
226 // Do nothing if the stream has been closed. 273 // Do nothing if the stream has been closed.
227 if (state_ < CREATING_STREAM) 274 if (state_ < CREATING_STREAM)
228 return; 275 return;
229 276
(...skipping 13 matching lines...) Expand all
243 // a callback object via Start() and clear it in Stop(). 290 // a callback object via Start() and clear it in Stop().
244 if (!audio_thread_.IsStopped()) 291 if (!audio_thread_.IsStopped())
245 callback_->OnRenderError(); 292 callback_->OnRenderError();
246 break; 293 break;
247 default: 294 default:
248 NOTREACHED(); 295 NOTREACHED();
249 break; 296 break;
250 } 297 }
251 } 298 }
252 299
300 void AudioOutputDevice::OnDeviceAuthorized(
301 bool success,
302 const media::AudioParameters& output_params) {
303 DCHECK(task_runner()->BelongsToCurrentThread());
304 if (success) {
305 SetOutputParams(output_params);
DaleCurtis 2015/09/09 01:31:57 Seems small to be its own function, just inline?
Guido Urdaneta 2015/09/09 16:22:23 Done.
306 return;
307 }
308
309 authorization_failed_ = true;
310 if (callback_)
311 callback_->OnRenderError();
312 }
313
253 void AudioOutputDevice::OnStreamCreated( 314 void AudioOutputDevice::OnStreamCreated(
254 base::SharedMemoryHandle handle, 315 base::SharedMemoryHandle handle,
255 base::SyncSocket::Handle socket_handle, 316 base::SyncSocket::Handle socket_handle,
256 int length) { 317 int length) {
257 DCHECK(task_runner()->BelongsToCurrentThread()); 318 DCHECK(task_runner()->BelongsToCurrentThread());
258 DCHECK(base::SharedMemory::IsHandleValid(handle)); 319 DCHECK(base::SharedMemory::IsHandleValid(handle));
259 #if defined(OS_WIN) 320 #if defined(OS_WIN)
260 DCHECK(socket_handle); 321 DCHECK(socket_handle);
261 #else 322 #else
262 DCHECK_GE(socket_handle, 0); 323 DCHECK_GE(socket_handle, 0);
263 #endif 324 #endif
264 DCHECK_GT(length, 0); 325 DCHECK_GT(length, 0);
265 326
266 if (state_ != CREATING_STREAM) 327 if (state_ != CREATING_STREAM)
267 return; 328 return;
268 329
269 // We can receive OnStreamCreated() on the IO thread after the client has 330 // We can receive OnStreamCreated() on the IO thread after the client has
270 // called Stop() but before ShutDownOnIOThread() is processed. In such a 331 // called Stop() but before ShutDownOnIOThread() is processed. In such a
271 // situation |callback_| might point to freed memory. Instead of starting 332 // situation |callback_| might point to freed memory. Instead of starting
272 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 333 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
273 // 334 //
274 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 335 // 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 336 // 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 337 // freed memory is a mess. AudioRendererSink should be non-refcounted so that
277 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 338 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
278 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 339 // delete as they see fit. AudioOutputDevice should internally use WeakPtr
279 // to handle teardown and thread hopping. See http://crbug.com/151051 for 340 // to handle teardown and thread hopping. See http://crbug.com/151051 for
280 // details. 341 // details.
281 base::AutoLock auto_lock(audio_thread_lock_); 342 {
282 if (stopping_hack_) 343 base::AutoLock auto_lock(audio_thread_lock_);
283 return; 344 if (stopping_hack_)
345 return;
284 346
285 DCHECK(audio_thread_.IsStopped()); 347 DCHECK(audio_thread_.IsStopped());
286 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 348 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
287 audio_parameters_, handle, length, callback_)); 349 audio_parameters_, handle, length, callback_));
288 audio_thread_.Start( 350 audio_thread_.Start(audio_callback_.get(), socket_handle,
289 audio_callback_.get(), socket_handle, "AudioOutputDevice", true); 351 "AudioOutputDevice", true);
290 state_ = PAUSED; 352 state_ = PAUSED;
291 353
292 // We handle the case where Play() and/or Pause() may have been called 354 // We handle the case where Play() and/or Pause() may have been called
293 // multiple times before OnStreamCreated() gets called. 355 // multiple times before OnStreamCreated() gets called.
294 if (play_on_start_) 356 if (play_on_start_)
295 PlayOnIOThread(); 357 PlayOnIOThread();
296 } 358 }
297 359
298 void AudioOutputDevice::SetCurrentSwitchRequest( 360 if (switch_output_device_on_start_) {
DaleCurtis 2015/09/09 01:31:57 Hmm, at this point the stream needs to be shutdown
Guido Urdaneta 2015/09/09 16:22:23 Why does the stream need to be shutdown and restar
299 const SwitchOutputDeviceCB& callback) { 361 ipc_->SwitchOutputDevice(current_switch_device_id_,
300 DCHECK(task_runner()->BelongsToCurrentThread()); 362 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 } 363 }
307 current_switch_callback_ = callback;
308 current_switch_request_id_++;
309 } 364 }
310 365
311 void AudioOutputDevice::OnOutputDeviceSwitched( 366 void AudioOutputDevice::OnOutputDeviceSwitched(
312 int request_id, 367 SwitchOutputDeviceResult result,
313 SwitchOutputDeviceResult result) { 368 const media::AudioParameters& output_params) {
314 DCHECK(task_runner()->BelongsToCurrentThread()); 369 DCHECK(task_runner()->BelongsToCurrentThread());
315 DCHECK(request_id <= current_switch_request_id_); 370 if (result == SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS) {
316 DVLOG(1) << __FUNCTION__ 371 session_id_ = 0; // Output device is no longer attached to an input device
317 << "(" << request_id << ", " << result << ")"; 372 device_id_ = current_switch_device_id_;
DaleCurtis 2015/09/09 01:31:57 Clear switch ids?
Guido Urdaneta 2015/09/09 16:22:23 We can clear them, but would there be an advantage
318 if (request_id != current_switch_request_id_) { 373 security_origin_ = current_switch_security_origin_;
319 return;
320 } 374 }
375 DCHECK(!current_switch_callback_.is_null());
321 base::ResetAndReturn(&current_switch_callback_).Run(result); 376 base::ResetAndReturn(&current_switch_callback_).Run(result);
322 } 377 }
323 378
324 void AudioOutputDevice::OnIPCClosed() { 379 void AudioOutputDevice::OnIPCClosed() {
325 DCHECK(task_runner()->BelongsToCurrentThread()); 380 DCHECK(task_runner()->BelongsToCurrentThread());
326 state_ = IPC_CLOSED; 381 state_ = IPC_CLOSED;
327 ipc_.reset(); 382 ipc_.reset();
328 } 383 }
329 384
330 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 385 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
331 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 386 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
332 ShutDownOnIOThread(); 387 ShutDownOnIOThread();
333 } 388 }
334 389
390 void AudioOutputDevice::SetOutputParams(
391 const media::AudioParameters& output_params) {
392 DCHECK(task_runner()->BelongsToCurrentThread());
393 if (!did_set_output_params_.IsSignaled()) {
394 did_set_output_params_.Signal();
395 output_params_ = output_params;
396 }
397 }
398
335 // AudioOutputDevice::AudioThreadCallback 399 // AudioOutputDevice::AudioThreadCallback
336 400
337 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 401 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
338 const AudioParameters& audio_parameters, 402 const AudioParameters& audio_parameters,
339 base::SharedMemoryHandle memory, 403 base::SharedMemoryHandle memory,
340 int memory_length, 404 int memory_length,
341 AudioRendererSink::RenderCallback* render_callback) 405 AudioRendererSink::RenderCallback* render_callback)
342 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), 406 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
343 render_callback_(render_callback), 407 render_callback_(render_callback),
344 callback_num_(0) {} 408 callback_num_(0) {}
(...skipping 26 matching lines...) Expand all
371 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this); 435 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this);
372 } 436 }
373 437
374 // Update the audio-delay measurement then ask client to render audio. Since 438 // 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 439 // |output_bus_| is wrapping the shared memory the Render() call is writing
376 // directly into the shared memory. 440 // directly into the shared memory.
377 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds); 441 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds);
378 } 442 }
379 443
380 } // namespace media. 444 } // namespace media.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698