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

Side by Side Diff: content/renderer/media/track_audio_renderer.cc

Issue 1809093003: Moving SwitchOutputDevice out of OutputDevice interface, eliminating OutputDevice (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 8 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 "content/renderer/media/track_audio_renderer.h" 5 #include "content/renderer/media/track_audio_renderer.h"
6 6
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/synchronization/lock.h" 10 #include "base/synchronization/lock.h"
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 output_device_id_(device_id), 130 output_device_id_(device_id),
131 security_origin_(security_origin), 131 security_origin_(security_origin),
132 volume_(0.0), 132 volume_(0.0),
133 sink_started_(false) { 133 sink_started_(false) {
134 DCHECK(MediaStreamAudioTrack::From(audio_track_)); 134 DCHECK(MediaStreamAudioTrack::From(audio_track_));
135 DVLOG(1) << "TrackAudioRenderer::TrackAudioRenderer()"; 135 DVLOG(1) << "TrackAudioRenderer::TrackAudioRenderer()";
136 } 136 }
137 137
138 TrackAudioRenderer::~TrackAudioRenderer() { 138 TrackAudioRenderer::~TrackAudioRenderer() {
139 DCHECK(task_runner_->BelongsToCurrentThread()); 139 DCHECK(task_runner_->BelongsToCurrentThread());
140 DCHECK(!sink_.get()); 140 DCHECK(!sink_);
141 DVLOG(1) << "TrackAudioRenderer::~TrackAudioRenderer()"; 141 DVLOG(1) << "TrackAudioRenderer::~TrackAudioRenderer()";
142 } 142 }
143 143
144 void TrackAudioRenderer::Start() { 144 void TrackAudioRenderer::Start() {
145 DVLOG(1) << "TrackAudioRenderer::Start()"; 145 DVLOG(1) << "TrackAudioRenderer::Start()";
146 DCHECK(task_runner_->BelongsToCurrentThread()); 146 DCHECK(task_runner_->BelongsToCurrentThread());
147 DCHECK_EQ(playing_, false); 147 DCHECK_EQ(playing_, false);
148 148
149 // We get audio data from |audio_track_|... 149 // We get audio data from |audio_track_|...
150 MediaStreamAudioSink::AddToAudioTrack(this, audio_track_); 150 MediaStreamAudioSink::AddToAudioTrack(this, audio_track_);
151 // ...and |sink_| will get audio data from us. 151 // ...and |sink_| will get audio data from us.
152 DCHECK(!sink_.get()); 152 DCHECK(!sink_);
153 sink_ = AudioDeviceFactory::NewAudioRendererSink( 153 sink_ = AudioDeviceFactory::NewAudioRendererSink(
154 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_, 154 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_,
155 session_id_, output_device_id_, security_origin_); 155 session_id_, output_device_id_, security_origin_);
156 156
157 base::AutoLock auto_lock(thread_lock_); 157 base::AutoLock auto_lock(thread_lock_);
158 prior_elapsed_render_time_ = base::TimeDelta(); 158 prior_elapsed_render_time_ = base::TimeDelta();
159 num_samples_rendered_ = 0; 159 num_samples_rendered_ = 0;
160 } 160 }
161 161
162 void TrackAudioRenderer::Stop() { 162 void TrackAudioRenderer::Stop() {
163 DVLOG(1) << "TrackAudioRenderer::Stop()"; 163 DVLOG(1) << "TrackAudioRenderer::Stop()";
164 DCHECK(task_runner_->BelongsToCurrentThread()); 164 DCHECK(task_runner_->BelongsToCurrentThread());
165 165
166 Pause(); 166 Pause();
167 167
168 // Stop the output audio stream, i.e, stop asking for data to render. 168 // Stop the output audio stream, i.e, stop asking for data to render.
169 // It is safer to call Stop() on the |sink_| to clean up the resources even 169 // It is safer to call Stop() on the |sink_| to clean up the resources even
170 // when the |sink_| is never started. 170 // when the |sink_| is never started.
171 if (sink_.get()) { 171 if (sink_) {
172 sink_->Stop(); 172 sink_->Stop();
173 sink_ = NULL; 173 sink_ = NULL;
174 } 174 }
175 175
176 if (!sink_started_ && IsLocalRenderer()) { 176 if (!sink_started_ && IsLocalRenderer()) {
177 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", 177 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates",
178 kSinkNeverStarted, kSinkStatesMax); 178 kSinkNeverStarted, kSinkStatesMax);
179 } 179 }
180 sink_started_ = false; 180 sink_started_ = false;
181 181
182 // Ensure that the capturer stops feeding us with captured audio. 182 // Ensure that the capturer stops feeding us with captured audio.
183 MediaStreamAudioSink::RemoveFromAudioTrack(this, audio_track_); 183 MediaStreamAudioSink::RemoveFromAudioTrack(this, audio_track_);
184 } 184 }
185 185
186 void TrackAudioRenderer::Play() { 186 void TrackAudioRenderer::Play() {
187 DVLOG(1) << "TrackAudioRenderer::Play()"; 187 DVLOG(1) << "TrackAudioRenderer::Play()";
188 DCHECK(task_runner_->BelongsToCurrentThread()); 188 DCHECK(task_runner_->BelongsToCurrentThread());
189 189
190 if (!sink_.get()) 190 if (!sink_)
191 return; 191 return;
192 192
193 playing_ = true; 193 playing_ = true;
194 194
195 MaybeStartSink(); 195 MaybeStartSink();
196 } 196 }
197 197
198 void TrackAudioRenderer::Pause() { 198 void TrackAudioRenderer::Pause() {
199 DVLOG(1) << "TrackAudioRenderer::Pause()"; 199 DVLOG(1) << "TrackAudioRenderer::Pause()";
200 DCHECK(task_runner_->BelongsToCurrentThread()); 200 DCHECK(task_runner_->BelongsToCurrentThread());
201 201
202 if (!sink_.get()) 202 if (!sink_)
203 return; 203 return;
204 204
205 playing_ = false; 205 playing_ = false;
206 206
207 base::AutoLock auto_lock(thread_lock_); 207 base::AutoLock auto_lock(thread_lock_);
208 HaltAudioFlowWhileLockHeld(); 208 HaltAudioFlowWhileLockHeld();
209 } 209 }
210 210
211 void TrackAudioRenderer::SetVolume(float volume) { 211 void TrackAudioRenderer::SetVolume(float volume) {
212 DVLOG(1) << "TrackAudioRenderer::SetVolume(" << volume << ")"; 212 DVLOG(1) << "TrackAudioRenderer::SetVolume(" << volume << ")";
213 DCHECK(task_runner_->BelongsToCurrentThread()); 213 DCHECK(task_runner_->BelongsToCurrentThread());
214 214
215 // Cache the volume. Whenever |sink_| is re-created, call SetVolume() with 215 // Cache the volume. Whenever |sink_| is re-created, call SetVolume() with
216 // this cached volume. 216 // this cached volume.
217 volume_ = volume; 217 volume_ = volume;
218 if (sink_.get()) 218 if (sink_)
219 sink_->SetVolume(volume); 219 sink_->SetVolume(volume);
220 } 220 }
221 221
222 media::OutputDevice* TrackAudioRenderer::GetOutputDevice() { 222 media::OutputDeviceInfo TrackAudioRenderer::GetOutputDeviceInfo() {
223 DCHECK(task_runner_->BelongsToCurrentThread()); 223 DCHECK(task_runner_->BelongsToCurrentThread());
224 return this; 224 return sink_ ? sink_->GetOutputDeviceInfo() : media::OutputDeviceInfo();
225 } 225 }
226 226
227 base::TimeDelta TrackAudioRenderer::GetCurrentRenderTime() const { 227 base::TimeDelta TrackAudioRenderer::GetCurrentRenderTime() const {
228 DCHECK(task_runner_->BelongsToCurrentThread()); 228 DCHECK(task_runner_->BelongsToCurrentThread());
229 base::AutoLock auto_lock(thread_lock_); 229 base::AutoLock auto_lock(thread_lock_);
230 if (source_params_.IsValid()) { 230 if (source_params_.IsValid()) {
231 return ComputeTotalElapsedRenderTime(prior_elapsed_render_time_, 231 return ComputeTotalElapsedRenderTime(prior_elapsed_render_time_,
232 num_samples_rendered_, 232 num_samples_rendered_,
233 source_params_.sample_rate()); 233 source_params_.sample_rate());
234 } 234 }
235 return prior_elapsed_render_time_; 235 return prior_elapsed_render_time_;
236 } 236 }
237 237
238 bool TrackAudioRenderer::IsLocalRenderer() const { 238 bool TrackAudioRenderer::IsLocalRenderer() const {
239 DCHECK(task_runner_->BelongsToCurrentThread()); 239 DCHECK(task_runner_->BelongsToCurrentThread());
240 return MediaStreamAudioTrack::From(audio_track_)->is_local_track(); 240 return MediaStreamAudioTrack::From(audio_track_)->is_local_track();
241 } 241 }
242 242
243 void TrackAudioRenderer::SwitchOutputDevice( 243 void TrackAudioRenderer::SwitchOutputDevice(
244 const std::string& device_id, 244 const std::string& device_id,
245 const url::Origin& security_origin, 245 const url::Origin& security_origin,
246 const media::SwitchOutputDeviceCB& callback) { 246 const media::OutputDeviceStatusCB& callback) {
247 DVLOG(1) << "TrackAudioRenderer::SwitchOutputDevice()"; 247 DVLOG(1) << "TrackAudioRenderer::SwitchOutputDevice()";
248 DCHECK(task_runner_->BelongsToCurrentThread()); 248 DCHECK(task_runner_->BelongsToCurrentThread());
249 249
250 { 250 {
251 base::AutoLock auto_lock(thread_lock_); 251 base::AutoLock auto_lock(thread_lock_);
252 HaltAudioFlowWhileLockHeld(); 252 HaltAudioFlowWhileLockHeld();
253 } 253 }
254 254
255 scoped_refptr<media::AudioRendererSink> new_sink = 255 scoped_refptr<media::AudioRendererSink> new_sink =
256 AudioDeviceFactory::NewAudioRendererSink( 256 AudioDeviceFactory::NewAudioRendererSink(
257 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_, 257 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_,
258 session_id_, device_id, security_origin); 258 session_id_, device_id, security_origin);
259
259 media::OutputDeviceStatus new_sink_status = 260 media::OutputDeviceStatus new_sink_status =
260 new_sink->GetOutputDevice()->GetDeviceStatus(); 261 new_sink->GetOutputDeviceInfo().device_status();
261 if (new_sink_status != media::OUTPUT_DEVICE_STATUS_OK) { 262 if (new_sink_status != media::OUTPUT_DEVICE_STATUS_OK) {
262 callback.Run(new_sink_status); 263 callback.Run(new_sink_status);
263 return; 264 return;
264 } 265 }
265 266
266 output_device_id_ = device_id; 267 output_device_id_ = device_id;
267 security_origin_ = security_origin; 268 security_origin_ = security_origin;
268 bool was_sink_started = sink_started_; 269 bool was_sink_started = sink_started_;
269 270
270 if (sink_.get()) 271 if (sink_)
271 sink_->Stop(); 272 sink_->Stop();
272 273
273 sink_started_ = false; 274 sink_started_ = false;
274 sink_ = new_sink; 275 sink_ = new_sink;
275 if (was_sink_started) 276 if (was_sink_started)
276 MaybeStartSink(); 277 MaybeStartSink();
277 278
278 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); 279 callback.Run(media::OUTPUT_DEVICE_STATUS_OK);
279 } 280 }
280 281
281 media::AudioParameters TrackAudioRenderer::GetOutputParameters() {
282 DCHECK(task_runner_->BelongsToCurrentThread());
283 if (!sink_ || !source_params_.IsValid())
284 return media::AudioParameters();
285
286 // Output parameters consist of the same channel layout and sample rate as the
287 // source, but having the buffer duration preferred by the hardware.
288 const media::AudioParameters& preferred_params =
289 sink_->GetOutputDevice()->GetOutputParameters();
290 return media::AudioParameters(
291 preferred_params.format(), source_params_.channel_layout(),
292 source_params_.sample_rate(), source_params_.bits_per_sample(),
293 preferred_params.frames_per_buffer() * source_params_.sample_rate() /
294 preferred_params.sample_rate());
295 }
296
297 media::OutputDeviceStatus TrackAudioRenderer::GetDeviceStatus() {
298 DCHECK(task_runner_->BelongsToCurrentThread());
299 if (!sink_.get())
300 return media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL;
301
302 return sink_->GetOutputDevice()->GetDeviceStatus();
303 }
304
305 void TrackAudioRenderer::MaybeStartSink() { 282 void TrackAudioRenderer::MaybeStartSink() {
306 DCHECK(task_runner_->BelongsToCurrentThread()); 283 DCHECK(task_runner_->BelongsToCurrentThread());
307 DVLOG(1) << "TrackAudioRenderer::MaybeStartSink()"; 284 DVLOG(1) << "TrackAudioRenderer::MaybeStartSink()";
308 285
309 if (!sink_.get() || !source_params_.IsValid() || !playing_) 286 if (!sink_ || !source_params_.IsValid() || !playing_)
310 return; 287 return;
311 288
312 // Re-create the AudioShifter to drop old audio data and reset to a starting 289 // Re-create the AudioShifter to drop old audio data and reset to a starting
313 // state. MaybeStartSink() is always called in a situation where either the 290 // state. MaybeStartSink() is always called in a situation where either the
314 // source or sink has changed somehow and so all of AudioShifter's internal 291 // source or sink has changed somehow and so all of AudioShifter's internal
315 // time-sync state is invalid. 292 // time-sync state is invalid.
316 CreateAudioShifter(); 293 CreateAudioShifter();
317 294
318 if (sink_started_ || 295 if (sink_started_)
319 sink_->GetOutputDevice()->GetDeviceStatus() !=
320 media::OUTPUT_DEVICE_STATUS_OK) {
321 return; 296 return;
322 }
323 297
298 const media::OutputDeviceInfo& device_info = sink_->GetOutputDeviceInfo();
299 if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK)
300 return;
301
302 // Output parameters consist of the same channel layout and sample rate as the
303 // source, but having the buffer duration preferred by the hardware.
304 const media::AudioParameters& hardware_params = device_info.output_params();
305 media::AudioParameters sink_params(
306 hardware_params.format(), source_params_.channel_layout(),
307 source_params_.sample_rate(), source_params_.bits_per_sample(),
308 hardware_params.frames_per_buffer() * source_params_.sample_rate() /
309 hardware_params.sample_rate());
324 DVLOG(1) << ("TrackAudioRenderer::MaybeStartSink() -- Starting sink. " 310 DVLOG(1) << ("TrackAudioRenderer::MaybeStartSink() -- Starting sink. "
325 "source_params_={") 311 "source_params_={")
326 << source_params_.AsHumanReadableString() << "}, sink parameters={" 312 << source_params_.AsHumanReadableString() << "}, sink parameters={"
327 << GetOutputParameters().AsHumanReadableString() << '}'; 313 << sink_params.AsHumanReadableString() << '}';
328 sink_->Initialize(GetOutputParameters(), this); 314 sink_->Initialize(sink_params, this);
329 sink_->Start(); 315 sink_->Start();
330 sink_->SetVolume(volume_); 316 sink_->SetVolume(volume_);
331 sink_->Play(); // Not all the sinks play on start. 317 sink_->Play(); // Not all the sinks play on start.
332 sink_started_ = true; 318 sink_started_ = true;
333 if (IsLocalRenderer()) { 319 if (IsLocalRenderer()) {
334 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", kSinkStarted, 320 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", kSinkStarted,
335 kSinkStatesMax); 321 kSinkStatesMax);
336 } 322 }
337 } 323 }
338 324
339 void TrackAudioRenderer::ReconfigureSink(const media::AudioParameters& params) { 325 void TrackAudioRenderer::ReconfigureSink(const media::AudioParameters& params) {
340 DCHECK(task_runner_->BelongsToCurrentThread()); 326 DCHECK(task_runner_->BelongsToCurrentThread());
341 327
342 DVLOG(1) << "TrackAudioRenderer::ReconfigureSink()"; 328 DVLOG(1) << "TrackAudioRenderer::ReconfigureSink()";
343 329
344 if (source_params_.Equals(params)) 330 if (source_params_.Equals(params))
345 return; 331 return;
346 source_params_ = params; 332 source_params_ = params;
347 333
348 if (!sink_.get()) 334 if (!sink_)
349 return; // TrackAudioRenderer has not yet been started. 335 return; // TrackAudioRenderer has not yet been started.
350 336
351 // Stop |sink_| and re-create a new one to be initialized with different audio 337 // Stop |sink_| and re-create a new one to be initialized with different audio
352 // parameters. Then, invoke MaybeStartSink() to restart everything again. 338 // parameters. Then, invoke MaybeStartSink() to restart everything again.
353 sink_->Stop(); 339 sink_->Stop();
354 sink_started_ = false; 340 sink_started_ = false;
355 sink_ = AudioDeviceFactory::NewAudioRendererSink( 341 sink_ = AudioDeviceFactory::NewAudioRendererSink(
356 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_, 342 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_,
357 session_id_, output_device_id_, security_origin_); 343 session_id_, output_device_id_, security_origin_);
358 MaybeStartSink(); 344 MaybeStartSink();
(...skipping 29 matching lines...) Expand all
388 if (source_params_.IsValid()) { 374 if (source_params_.IsValid()) {
389 prior_elapsed_render_time_ = 375 prior_elapsed_render_time_ =
390 ComputeTotalElapsedRenderTime(prior_elapsed_render_time_, 376 ComputeTotalElapsedRenderTime(prior_elapsed_render_time_,
391 num_samples_rendered_, 377 num_samples_rendered_,
392 source_params_.sample_rate()); 378 source_params_.sample_rate());
393 num_samples_rendered_ = 0; 379 num_samples_rendered_ = 0;
394 } 380 }
395 } 381 }
396 382
397 } // namespace content 383 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/track_audio_renderer.h ('k') | content/renderer/media/webmediaplayer_ms.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698