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

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: Replace RestartableAudioRendererSink with SwitchableAudioRendererSink in webmediaplayer_impl unit t… Created 4 years, 9 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::OutputDevice* TrackAudioRenderer::GetOutputDevice() {
223 DCHECK(task_runner_->BelongsToCurrentThread()); 223 DCHECK(task_runner_->BelongsToCurrentThread());
224 return this; 224 return sink_ ? sink_->GetOutputDevice() : nullptr;
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 }
(...skipping 14 matching lines...) Expand all
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
260 media::OutputDevice* device = new_sink->GetOutputDevice();
259 media::OutputDeviceStatus new_sink_status = 261 media::OutputDeviceStatus new_sink_status =
260 new_sink->GetOutputDevice()->GetDeviceStatus(); 262 device ? device->GetDeviceStatus()
263 : media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL;
261 if (new_sink_status != media::OUTPUT_DEVICE_STATUS_OK) { 264 if (new_sink_status != media::OUTPUT_DEVICE_STATUS_OK) {
262 callback.Run(new_sink_status); 265 callback.Run(new_sink_status);
263 return; 266 return;
264 } 267 }
265 268
266 output_device_id_ = device_id; 269 output_device_id_ = device_id;
267 security_origin_ = security_origin; 270 security_origin_ = security_origin;
268 bool was_sink_started = sink_started_; 271 bool was_sink_started = sink_started_;
269 272
270 if (sink_.get()) 273 if (sink_)
271 sink_->Stop(); 274 sink_->Stop();
272 275
273 sink_started_ = false; 276 sink_started_ = false;
274 sink_ = new_sink; 277 sink_ = new_sink;
275 if (was_sink_started) 278 if (was_sink_started)
276 MaybeStartSink(); 279 MaybeStartSink();
277 280
278 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); 281 callback.Run(media::OUTPUT_DEVICE_STATUS_OK);
279 } 282 }
280 283
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() { 284 void TrackAudioRenderer::MaybeStartSink() {
306 DCHECK(task_runner_->BelongsToCurrentThread()); 285 DCHECK(task_runner_->BelongsToCurrentThread());
307 DVLOG(1) << "TrackAudioRenderer::MaybeStartSink()"; 286 DVLOG(1) << "TrackAudioRenderer::MaybeStartSink()";
308 287
309 if (!sink_.get() || !source_params_.IsValid() || !playing_) 288 if (!(sink_ && source_params_.IsValid() && playing_))
310 return; 289 return;
311 290
312 // Re-create the AudioShifter to drop old audio data and reset to a starting 291 // 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 292 // 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 293 // source or sink has changed somehow and so all of AudioShifter's internal
315 // time-sync state is invalid. 294 // time-sync state is invalid.
316 CreateAudioShifter(); 295 CreateAudioShifter();
317 296
318 if (sink_started_ || 297 media::OutputDevice* device = sink_->GetOutputDevice();
319 sink_->GetOutputDevice()->GetDeviceStatus() != 298 if (sink_started_ || !device ||
320 media::OUTPUT_DEVICE_STATUS_OK) { 299 device->GetDeviceStatus() != media::OUTPUT_DEVICE_STATUS_OK) {
321 return; 300 return;
322 } 301 }
323 302
303 // Output parameters consist of the same channel layout and sample rate as the
304 // source, but having the buffer duration preferred by the hardware.
305 const media::AudioParameters& preferred_params =
306 device->GetOutputParameters();
307 media::AudioParameters sink_params(
308 preferred_params.format(), source_params_.channel_layout(),
309 source_params_.sample_rate(), source_params_.bits_per_sample(),
310 preferred_params.frames_per_buffer() * source_params_.sample_rate() /
311 preferred_params.sample_rate());
324 DVLOG(1) << ("TrackAudioRenderer::MaybeStartSink() -- Starting sink. " 312 DVLOG(1) << ("TrackAudioRenderer::MaybeStartSink() -- Starting sink. "
325 "source_params_={") 313 "source_params_={")
326 << source_params_.AsHumanReadableString() << "}, sink parameters={" 314 << source_params_.AsHumanReadableString() << "}, sink parameters={"
327 << GetOutputParameters().AsHumanReadableString() << '}'; 315 << sink_params.AsHumanReadableString() << '}';
328 sink_->Initialize(GetOutputParameters(), this); 316 sink_->Initialize(sink_params, this);
329 sink_->Start(); 317 sink_->Start();
330 sink_->SetVolume(volume_); 318 sink_->SetVolume(volume_);
331 sink_->Play(); // Not all the sinks play on start. 319 sink_->Play(); // Not all the sinks play on start.
332 sink_started_ = true; 320 sink_started_ = true;
333 if (IsLocalRenderer()) { 321 if (IsLocalRenderer()) {
334 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", kSinkStarted, 322 UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", kSinkStarted,
335 kSinkStatesMax); 323 kSinkStatesMax);
336 } 324 }
337 } 325 }
338 326
339 void TrackAudioRenderer::ReconfigureSink(const media::AudioParameters& params) { 327 void TrackAudioRenderer::ReconfigureSink(const media::AudioParameters& params) {
340 DCHECK(task_runner_->BelongsToCurrentThread()); 328 DCHECK(task_runner_->BelongsToCurrentThread());
341 329
342 DVLOG(1) << "TrackAudioRenderer::ReconfigureSink()"; 330 DVLOG(1) << "TrackAudioRenderer::ReconfigureSink()";
343 331
344 if (source_params_.Equals(params)) 332 if (source_params_.Equals(params))
345 return; 333 return;
346 source_params_ = params; 334 source_params_ = params;
347 335
348 if (!sink_.get()) 336 if (!sink_)
349 return; // TrackAudioRenderer has not yet been started. 337 return; // TrackAudioRenderer has not yet been started.
350 338
351 // Stop |sink_| and re-create a new one to be initialized with different audio 339 // Stop |sink_| and re-create a new one to be initialized with different audio
352 // parameters. Then, invoke MaybeStartSink() to restart everything again. 340 // parameters. Then, invoke MaybeStartSink() to restart everything again.
353 sink_->Stop(); 341 sink_->Stop();
354 sink_started_ = false; 342 sink_started_ = false;
355 sink_ = AudioDeviceFactory::NewAudioRendererSink( 343 sink_ = AudioDeviceFactory::NewAudioRendererSink(
356 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_, 344 AudioDeviceFactory::kSourceNonRtcAudioTrack, playout_render_frame_id_,
357 session_id_, output_device_id_, security_origin_); 345 session_id_, output_device_id_, security_origin_);
358 MaybeStartSink(); 346 MaybeStartSink();
(...skipping 29 matching lines...) Expand all
388 if (source_params_.IsValid()) { 376 if (source_params_.IsValid()) {
389 prior_elapsed_render_time_ = 377 prior_elapsed_render_time_ =
390 ComputeTotalElapsedRenderTime(prior_elapsed_render_time_, 378 ComputeTotalElapsedRenderTime(prior_elapsed_render_time_,
391 num_samples_rendered_, 379 num_samples_rendered_,
392 source_params_.sample_rate()); 380 source_params_.sample_rate());
393 num_samples_rendered_ = 0; 381 num_samples_rendered_ = 0;
394 } 382 }
395 } 383 }
396 384
397 } // namespace content 385 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698