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

Side by Side Diff: chrome/renderer/media/cast_rtp_stream.cc

Issue 759383003: [Cast] CastAudioSink audio reference_time adjustment and fixes/clean-up. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Naming tweak. Created 6 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
« no previous file with comments | « no previous file | 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/renderer/media/cast_rtp_stream.h" 5 #include "chrome/renderer/media/cast_rtp_stream.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/weak_ptr.h" 11 #include "base/memory/weak_ptr.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "base/sys_info.h" 13 #include "base/sys_info.h"
14 #include "chrome/common/chrome_switches.h" 14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/renderer/media/cast_session.h" 15 #include "chrome/renderer/media/cast_session.h"
16 #include "chrome/renderer/media/cast_udp_transport.h" 16 #include "chrome/renderer/media/cast_udp_transport.h"
17 #include "content/public/renderer/media_stream_audio_sink.h" 17 #include "content/public/renderer/media_stream_audio_sink.h"
18 #include "content/public/renderer/media_stream_video_sink.h" 18 #include "content/public/renderer/media_stream_video_sink.h"
19 #include "content/public/renderer/render_thread.h" 19 #include "content/public/renderer/render_thread.h"
20 #include "content/public/renderer/video_encode_accelerator.h" 20 #include "content/public/renderer/video_encode_accelerator.h"
21 #include "media/audio/audio_parameters.h" 21 #include "media/audio/audio_parameters.h"
22 #include "media/base/audio_bus.h" 22 #include "media/base/audio_bus.h"
23 #include "media/base/audio_converter.h"
23 #include "media/base/audio_fifo.h" 24 #include "media/base/audio_fifo.h"
24 #include "media/base/bind_to_current_loop.h" 25 #include "media/base/bind_to_current_loop.h"
25 #include "media/base/multi_channel_resampler.h"
26 #include "media/base/video_frame.h" 26 #include "media/base/video_frame.h"
27 #include "media/cast/cast_config.h" 27 #include "media/cast/cast_config.h"
28 #include "media/cast/cast_defines.h" 28 #include "media/cast/cast_defines.h"
29 #include "media/cast/cast_sender.h" 29 #include "media/cast/cast_sender.h"
30 #include "media/cast/net/cast_transport_config.h" 30 #include "media/cast/net/cast_transport_config.h"
31 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 31 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
32 #include "ui/gfx/geometry/size.h" 32 #include "ui/gfx/geometry/size.h"
33 33
34 using media::cast::AudioSenderConfig; 34 using media::cast::AudioSenderConfig;
35 using media::cast::VideoSenderConfig; 35 using media::cast::VideoSenderConfig;
36 36
37 namespace { 37 namespace {
38 38
39 const char kCodecNameOpus[] = "OPUS"; 39 const char kCodecNameOpus[] = "OPUS";
40 const char kCodecNameVp8[] = "VP8"; 40 const char kCodecNameVp8[] = "VP8";
41 const char kCodecNameH264[] = "H264"; 41 const char kCodecNameH264[] = "H264";
42 42
43 // To convert from kilobits per second to bits to per second. 43 // To convert from kilobits per second to bits to per second.
44 const int kBitrateMultiplier = 1000; 44 const int kBitrateMultiplier = 1000;
45 45
46 // This constant defines the number of sets of audio data to buffer
47 // in the FIFO. If input audio and output data have different resampling
48 // rates then buffer is necessary to avoid audio glitches.
49 // See CastAudioSink::ResampleData() and CastAudioSink::OnSetFormat()
50 // for more defaults.
51 const int kBufferAudioData = 2;
52
53 CastRtpPayloadParams DefaultOpusPayload() { 46 CastRtpPayloadParams DefaultOpusPayload() {
54 CastRtpPayloadParams payload; 47 CastRtpPayloadParams payload;
55 payload.payload_type = 127; 48 payload.payload_type = 127;
56 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; 49 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
57 payload.ssrc = 1; 50 payload.ssrc = 1;
58 payload.feedback_ssrc = 2; 51 payload.feedback_ssrc = 2;
59 payload.clock_rate = media::cast::kDefaultAudioSamplingRate; 52 payload.clock_rate = media::cast::kDefaultAudioSamplingRate;
60 // The value is 0 which means VBR. 53 // The value is 0 which means VBR.
61 payload.min_bitrate = payload.max_bitrate = 54 payload.min_bitrate = payload.max_bitrate =
62 media::cast::kDefaultAudioEncoderBitrate; 55 media::cast::kDefaultAudioEncoderBitrate;
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 DISALLOW_COPY_AND_ASSIGN(CastVideoSink); 333 DISALLOW_COPY_AND_ASSIGN(CastVideoSink);
341 }; 334 };
342 335
343 // Receives audio data from a MediaStreamTrack. Data is submitted to 336 // Receives audio data from a MediaStreamTrack. Data is submitted to
344 // media::cast::FrameInput. 337 // media::cast::FrameInput.
345 // 338 //
346 // Threading: Audio frames are received on the real-time audio thread. 339 // Threading: Audio frames are received on the real-time audio thread.
347 // Note that RemoveFromAudioTrack() is synchronous and we have 340 // Note that RemoveFromAudioTrack() is synchronous and we have
348 // gurantee that there will be no more audio data after calling it. 341 // gurantee that there will be no more audio data after calling it.
349 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, 342 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>,
350 public content::MediaStreamAudioSink { 343 public content::MediaStreamAudioSink,
344 public media::AudioConverter::InputCallback {
351 public: 345 public:
352 // |track| provides data for this sink. 346 // |track| provides data for this sink.
353 // |error_callback| is called if audio formats don't match. 347 // |error_callback| is called if audio formats don't match.
354 CastAudioSink(const blink::WebMediaStreamTrack& track, 348 CastAudioSink(const blink::WebMediaStreamTrack& track,
355 const CastRtpStream::ErrorCallback& error_callback,
356 int output_channels, 349 int output_channels,
357 int output_sample_rate) 350 int output_sample_rate)
358 : track_(track), 351 : track_(track),
359 sink_added_(false),
360 error_callback_(error_callback),
361 weak_factory_(this),
362 output_channels_(output_channels), 352 output_channels_(output_channels),
363 output_sample_rate_(output_sample_rate), 353 output_sample_rate_(output_sample_rate),
364 input_preroll_(0) {} 354 sample_frames_in_(0),
355 sample_frames_out_(0) {}
365 356
366 ~CastAudioSink() override { 357 ~CastAudioSink() override {
367 if (sink_added_) 358 if (frame_input_.get())
368 RemoveFromAudioTrack(this, track_); 359 RemoveFromAudioTrack(this, track_);
369 } 360 }
370 361
371 // Called on real-time audio thread.
372 // content::MediaStreamAudioSink implementation.
373 void OnData(const int16* audio_data,
374 int sample_rate,
375 int number_of_channels,
376 int number_of_frames) override {
377 scoped_ptr<media::AudioBus> input_bus;
378 if (resampler_) {
379 input_bus = ResampleData(
380 audio_data, sample_rate, number_of_channels, number_of_frames);
381 if (!input_bus)
382 return;
383 } else {
384 input_bus = media::AudioBus::Create(
385 number_of_channels, number_of_frames);
386 input_bus->FromInterleaved(
387 audio_data, number_of_frames, number_of_channels);
388 }
389
390 // TODO(hclam): Pass in the accurate capture time to have good
391 // audio / video sync.
392 frame_input_->InsertAudio(input_bus.Pass(), base::TimeTicks::Now());
393 }
394
395 // Return a resampled audio data from input. This is called when the
396 // input sample rate doesn't match the output.
397 // The flow of data is as follows:
398 // |audio_data| ->
399 // AudioFifo |fifo_| ->
400 // MultiChannelResampler |resampler|.
401 //
402 // The resampler pulls data out of the FIFO and resample the data in
403 // frequency domain. It might call |fifo_| for more than once. But no more
404 // than |kBufferAudioData| times. We preroll audio data into the FIFO to
405 // make sure there's enough data for resampling.
406 scoped_ptr<media::AudioBus> ResampleData(
407 const int16* audio_data,
408 int sample_rate,
409 int number_of_channels,
410 int number_of_frames) {
411 DCHECK_EQ(number_of_channels, output_channels_);
412 fifo_input_bus_->FromInterleaved(
413 audio_data, number_of_frames, number_of_channels);
414 fifo_->Push(fifo_input_bus_.get());
415
416 if (input_preroll_ < kBufferAudioData - 1) {
417 ++input_preroll_;
418 return scoped_ptr<media::AudioBus>();
419 }
420
421 scoped_ptr<media::AudioBus> output_bus(
422 media::AudioBus::Create(
423 output_channels_,
424 output_sample_rate_ * fifo_input_bus_->frames() / sample_rate));
425
426 // Resampler will then call ProvideData() below to fetch data from
427 // |input_data_|.
428 resampler_->Resample(output_bus->frames(), output_bus.get());
429 return output_bus.Pass();
430 }
431
432 // Called on real-time audio thread.
433 void OnSetFormat(const media::AudioParameters& params) override {
434 if (params.sample_rate() == output_sample_rate_)
435 return;
436 fifo_.reset(new media::AudioFifo(
437 output_channels_,
438 kBufferAudioData * params.frames_per_buffer()));
439 fifo_input_bus_ = media::AudioBus::Create(
440 params.channels(), params.frames_per_buffer());
441 resampler_.reset(new media::MultiChannelResampler(
442 output_channels_,
443 static_cast<double>(params.sample_rate()) / output_sample_rate_,
444 params.frames_per_buffer(),
445 base::Bind(&CastAudioSink::ProvideData, base::Unretained(this))));
446 }
447
448 // Add this sink to the track. Data received from the track will be 362 // Add this sink to the track. Data received from the track will be
449 // submitted to |frame_input|. 363 // submitted to |frame_input|.
450 void AddToTrack( 364 void AddToTrack(
451 const scoped_refptr<media::cast::AudioFrameInput>& frame_input) { 365 const scoped_refptr<media::cast::AudioFrameInput>& frame_input) {
452 DCHECK(!sink_added_); 366 DCHECK(frame_input.get());
453 sink_added_ = true; 367 DCHECK(!frame_input_.get());
454
455 // This member is written here and then accessed on the IO thread 368 // This member is written here and then accessed on the IO thread
456 // We will not get data until AddToAudioTrack is called so it is 369 // We will not get data until AddToAudioTrack is called so it is
457 // safe to access this member now. 370 // safe to access this member now.
458 frame_input_ = frame_input; 371 frame_input_ = frame_input;
459 AddToAudioTrack(this, track_); 372 AddToAudioTrack(this, track_);
460 } 373 }
461 374
462 void ProvideData(int frame_delay, media::AudioBus* output_bus) { 375 protected:
463 fifo_->Consume(output_bus, 0, output_bus->frames()); 376 // Called on real-time audio thread.
377 // TODO(miu): This interface is horrible: The first arg should be an AudioBus,
378 // while the remaining three are redundant as they are provided in the call to
379 // OnSetFormat(). http://crbug.com/437064
380 void OnData(const int16* audio_data,
381 int sample_rate,
382 int number_of_channels,
383 int number_of_sample_frames) override {
384 DCHECK(audio_data);
385 DCHECK_EQ(sample_rate, input_params_.sample_rate());
386 DCHECK_EQ(number_of_channels, input_params_.channels());
387 DCHECK_EQ(number_of_sample_frames, input_params_.frames_per_buffer());
388
389 // TODO(miu): Plumbing is needed to determine the actual reference timestamp
390 // of the audio for proper audio/video sync. http://crbug.com/335335
391 base::TimeTicks reference_time = base::TimeTicks::Now();
392
393 if (converter_) {
394 // Make an adjustment to the |reference_time| to account for the portion
395 // of the audio signal enqueued within |fifo_| and |converter_|.
396 const base::TimeDelta signal_duration_already_buffered =
397 (sample_frames_in_ * base::TimeDelta::FromSeconds(1) /
398 input_params_.sample_rate()) -
399 (sample_frames_out_ * base::TimeDelta::FromSeconds(1) /
400 output_sample_rate_);
401 DVLOG(2) << "Audio reference time adjustment: -("
402 << signal_duration_already_buffered.InMicroseconds() << " us)";
403 reference_time -= signal_duration_already_buffered;
404
405 // TODO(miu): Eliminate need for extra copying of samples to do
406 // resampling. This will require AudioConverter changes.
407 fifo_input_bus_->FromInterleaved(
408 audio_data, input_params_.frames_per_buffer(), sizeof(audio_data[0]));
409 const int fifo_frames_remaining = fifo_->max_frames() - fifo_->frames();
410 if (fifo_frames_remaining < input_params_.frames_per_buffer()) {
411 NOTREACHED()
412 << "Audio FIFO overrun: " << input_params_.frames_per_buffer()
413 << " > " << fifo_frames_remaining;
414 sample_frames_in_ -= fifo_->frames();
415 fifo_->Clear();
416 }
417 fifo_->Push(fifo_input_bus_.get());
418 sample_frames_in_ += input_params_.frames_per_buffer();
419 if (fifo_->frames() < converter_->ChunkSize())
420 return; // Insufficient data to convert one complete Cast audio frame.
421
422 const int sample_frames_to_convert =
423 output_sample_rate_ * input_params_.frames_per_buffer() /
424 input_params_.sample_rate();
425 while (true) {
426 scoped_ptr<media::AudioBus> audio_bus =
427 media::AudioBus::Create(output_channels_, sample_frames_to_convert);
428 // AudioConverter will call ProvideInput() to fetch data from |fifo_|.
429 converter_->Convert(audio_bus.get());
430 sample_frames_out_ += sample_frames_to_convert;
431
432 frame_input_->InsertAudio(audio_bus.Pass(), reference_time);
433
434 if (fifo_->frames() < converter_->ChunkSize())
hubbe 2014/12/02 00:45:02 It seems like you're making the loop more complica
miu 2014/12/02 02:36:18 Good point. Done.
435 break;
436 reference_time +=
437 sample_frames_to_convert * base::TimeDelta::FromSeconds(1) /
438 output_sample_rate_;
439 }
440 } else {
441 scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(
442 input_params_.channels(), input_params_.frames_per_buffer());
443 audio_bus->FromInterleaved(
444 audio_data, input_params_.frames_per_buffer(), sizeof(audio_data[0]));
445 frame_input_->InsertAudio(audio_bus.Pass(), reference_time);
446 }
447 }
448
449 // Called on real-time audio thread.
450 void OnSetFormat(const media::AudioParameters& params) override {
451 if (input_params_.Equals(params))
452 return;
453 input_params_ = params;
454
455 if (input_params_.channels() == output_channels_ &&
456 input_params_.sample_rate() == output_sample_rate_) {
457 DVLOG(1) << "No audio resampling is needed.";
458 converter_.reset();
459 fifo_input_bus_.reset();
460 fifo_.reset();
461 } else {
462 DVLOG(1) << "Setting up audio resampling: {"
463 << input_params_.channels() << " channels, "
464 << input_params_.sample_rate() << " Hz} --> {"
465 << output_channels_ << " channels, "
466 << output_sample_rate_ << " Hz}";
467 const media::AudioParameters output_params(
468 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
469 media::GuessChannelLayout(output_channels_),
470 output_sample_rate_, 32,
471 output_sample_rate_ * input_params_.frames_per_buffer() /
472 input_params_.sample_rate());
473 converter_.reset(
474 new media::AudioConverter(input_params_, output_params, false));
475 converter_->AddInput(this);
476 fifo_input_bus_ = media::AudioBus::Create(
477 input_params_.channels(), input_params_.frames_per_buffer());
478 fifo_.reset(new media::AudioFifo(
479 input_params_.channels(),
480 converter_->ChunkSize() + input_params_.frames_per_buffer()));
481 sample_frames_in_ = 0;
482 sample_frames_out_ = 0;
483 }
484 }
485
486 // Called on real-time audio thread.
487 double ProvideInput(media::AudioBus* audio_bus,
488 base::TimeDelta buffer_delay) override {
489 fifo_->Consume(audio_bus, 0, audio_bus->frames());
490 return 1.0;
464 } 491 }
465 492
466 private: 493 private:
467 blink::WebMediaStreamTrack track_; 494 const blink::WebMediaStreamTrack track_;
468 bool sink_added_;
469 CastRtpStream::ErrorCallback error_callback_;
470 base::WeakPtrFactory<CastAudioSink> weak_factory_;
471
472 const int output_channels_; 495 const int output_channels_;
473 const int output_sample_rate_; 496 const int output_sample_rate_;
474 497
475 // These member are accessed on the real-time audio time only. 498 // This must be set before the real-time audio thread starts calling OnData(),
499 // and remain unchanged until after the thread will stop calling OnData().
476 scoped_refptr<media::cast::AudioFrameInput> frame_input_; 500 scoped_refptr<media::cast::AudioFrameInput> frame_input_;
477 scoped_ptr<media::MultiChannelResampler> resampler_; 501
502 // These members are accessed on the real-time audio time only.
503 media::AudioParameters input_params_;
504 scoped_ptr<media::AudioConverter> converter_;
505 scoped_ptr<media::AudioBus> fifo_input_bus_;
478 scoped_ptr<media::AudioFifo> fifo_; 506 scoped_ptr<media::AudioFifo> fifo_;
479 scoped_ptr<media::AudioBus> fifo_input_bus_; 507 int64 sample_frames_in_;
480 int input_preroll_; 508 int64 sample_frames_out_;
481 509
482 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); 510 DISALLOW_COPY_AND_ASSIGN(CastAudioSink);
483 }; 511 };
484 512
485 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) 513 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params)
486 : payload(payload_params) {} 514 : payload(payload_params) {}
487 515
488 CastCodecSpecificParams::CastCodecSpecificParams() {} 516 CastCodecSpecificParams::CastCodecSpecificParams() {}
489 517
490 CastCodecSpecificParams::~CastCodecSpecificParams() {} 518 CastCodecSpecificParams::~CastCodecSpecificParams() {}
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 AudioSenderConfig config; 564 AudioSenderConfig config;
537 if (!ToAudioSenderConfig(params, &config)) { 565 if (!ToAudioSenderConfig(params, &config)) {
538 DidEncounterError("Invalid parameters for audio."); 566 DidEncounterError("Invalid parameters for audio.");
539 return; 567 return;
540 } 568 }
541 569
542 // In case of error we have to go through DidEncounterError() to stop 570 // In case of error we have to go through DidEncounterError() to stop
543 // the streaming after reporting the error. 571 // the streaming after reporting the error.
544 audio_sink_.reset(new CastAudioSink( 572 audio_sink_.reset(new CastAudioSink(
545 track_, 573 track_,
546 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError,
547 weak_factory_.GetWeakPtr())),
548 params.payload.channels, 574 params.payload.channels,
549 params.payload.clock_rate)); 575 params.payload.clock_rate));
550 cast_session_->StartAudio( 576 cast_session_->StartAudio(
551 config, 577 config,
552 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), 578 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()),
553 base::Bind(&CastRtpStream::DidEncounterError, 579 base::Bind(&CastRtpStream::DidEncounterError,
554 weak_factory_.GetWeakPtr())); 580 weak_factory_.GetWeakPtr()));
555 start_callback.Run(); 581 start_callback.Run();
556 } else { 582 } else {
557 VideoSenderConfig config; 583 VideoSenderConfig config;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 void CastRtpStream::DidEncounterError(const std::string& message) { 636 void CastRtpStream::DidEncounterError(const std::string& message) {
611 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " 637 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = "
612 << (IsAudio() ? "audio" : "video"); 638 << (IsAudio() ? "audio" : "video");
613 // Save the WeakPtr first because the error callback might delete this object. 639 // Save the WeakPtr first because the error callback might delete this object.
614 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); 640 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr();
615 error_callback_.Run(message); 641 error_callback_.Run(message);
616 content::RenderThread::Get()->GetMessageLoop()->PostTask( 642 content::RenderThread::Get()->GetMessageLoop()->PostTask(
617 FROM_HERE, 643 FROM_HERE,
618 base::Bind(&CastRtpStream::Stop, ptr)); 644 base::Bind(&CastRtpStream::Stop, ptr));
619 } 645 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698