OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |