Chromium Code Reviews| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made. | 55 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made. |
| 56 const int kMaxConsecutiveRefreshFrames = 60; | 56 const int kMaxConsecutiveRefreshFrames = 60; |
| 57 | 57 |
| 58 FrameSenderConfig DefaultOpusConfig() { | 58 FrameSenderConfig DefaultOpusConfig() { |
| 59 FrameSenderConfig config; | 59 FrameSenderConfig config; |
| 60 config.rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; | 60 config.rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; |
| 61 config.sender_ssrc = 1; | 61 config.sender_ssrc = 1; |
| 62 config.receiver_ssrc = 2; | 62 config.receiver_ssrc = 2; |
| 63 config.rtp_timebase = media::cast::kDefaultAudioSamplingRate; | 63 config.rtp_timebase = media::cast::kDefaultAudioSamplingRate; |
| 64 config.channels = 2; | 64 config.channels = 2; |
| 65 // The value is 0 which means VBR. | |
| 66 config.min_bitrate = config.max_bitrate = config.start_bitrate = | 65 config.min_bitrate = config.max_bitrate = config.start_bitrate = |
| 67 media::cast::kDefaultAudioEncoderBitrate; | 66 media::cast::kDefaultAudioEncoderBitrate; |
| 68 config.max_frame_rate = 100; // 10 ms audio frames | 67 config.max_frame_rate = 100; // 10 ms audio frames |
| 69 config.codec = media::cast::CODEC_AUDIO_OPUS; | 68 config.codec = media::cast::CODEC_AUDIO_OPUS; |
| 70 return config; | 69 return config; |
| 71 } | 70 } |
| 72 | 71 |
| 73 FrameSenderConfig DefaultVp8Config() { | 72 FrameSenderConfig DefaultVp8Config() { |
| 74 FrameSenderConfig config; | 73 FrameSenderConfig config; |
| 75 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; | 74 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 91 config.receiver_ssrc = 12; | 90 config.receiver_ssrc = 12; |
| 92 config.rtp_timebase = media::cast::kVideoFrequency; | 91 config.rtp_timebase = media::cast::kVideoFrequency; |
| 93 config.channels = 1; | 92 config.channels = 1; |
| 94 config.max_bitrate = media::cast::kDefaultMaxVideoBitrate; | 93 config.max_bitrate = media::cast::kDefaultMaxVideoBitrate; |
| 95 config.min_bitrate = media::cast::kDefaultMinVideoBitrate; | 94 config.min_bitrate = media::cast::kDefaultMinVideoBitrate; |
| 96 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 95 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; |
| 97 config.codec = media::cast::CODEC_VIDEO_H264; | 96 config.codec = media::cast::CODEC_VIDEO_H264; |
| 98 return config; | 97 return config; |
| 99 } | 98 } |
| 100 | 99 |
| 101 std::vector<FrameSenderConfig> SupportedAudioConfigs() { | 100 FrameSenderConfig DefaultRemotingAudioConfig() { |
| 102 // TODO(hclam): Fill in more codecs here. | 101 FrameSenderConfig config; |
| 103 return std::vector<FrameSenderConfig>(1, DefaultOpusConfig()); | 102 config.rtp_payload_type = media::cast::RtpPayloadType::REMOTE_AUDIO; |
| 103 config.sender_ssrc = 3; | |
| 104 config.receiver_ssrc = 4; | |
| 105 config.codec = media::cast::CODEC_AUDIO_REMOTE; | |
| 106 config.rtp_timebase = media::cast::kRemotingRtpTimebase; | |
| 107 config.max_bitrate = 1000000; | |
| 108 config.min_bitrate = 0; | |
| 109 config.channels = 2; | |
| 110 config.max_frame_rate = 100; // 10 ms audio frames | |
| 111 | |
| 112 return config; | |
| 104 } | 113 } |
| 105 | 114 |
| 106 std::vector<FrameSenderConfig> SupportedVideoConfigs() { | 115 FrameSenderConfig DefaultRemotingVideoConfig() { |
| 116 FrameSenderConfig config; | |
| 117 config.rtp_payload_type = media::cast::RtpPayloadType::REMOTE_VIDEO; | |
| 118 config.sender_ssrc = 13; | |
| 119 config.receiver_ssrc = 14; | |
| 120 config.codec = media::cast::CODEC_VIDEO_REMOTE; | |
| 121 config.rtp_timebase = media::cast::kRemotingRtpTimebase; | |
| 122 config.max_bitrate = 10000000; | |
| 123 config.min_bitrate = 0; | |
| 124 config.channels = 1; | |
| 125 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; | |
| 126 return config; | |
| 127 } | |
| 128 | |
| 129 std::vector<FrameSenderConfig> SupportedAudioConfigs(bool for_remoting_stream) { | |
| 130 if (for_remoting_stream) | |
| 131 return std::vector<FrameSenderConfig>(1, DefaultRemotingAudioConfig()); | |
|
dcheng
2016/09/10 02:31:36
return {DefaultRemotingAudioConfig()}
should work
xjz
2016/09/12 18:22:06
Done.
| |
| 132 else | |
| 133 return std::vector<FrameSenderConfig>(1, DefaultOpusConfig()); | |
| 134 } | |
| 135 | |
| 136 std::vector<FrameSenderConfig> SupportedVideoConfigs(bool for_remoting_stream) { | |
| 137 if (for_remoting_stream) | |
| 138 return std::vector<FrameSenderConfig>(1, DefaultRemotingVideoConfig()); | |
| 139 | |
| 107 std::vector<FrameSenderConfig> supported_configs; | 140 std::vector<FrameSenderConfig> supported_configs; |
| 108 | |
| 109 // Prefer VP8 over H.264 for hardware encoder. | 141 // Prefer VP8 over H.264 for hardware encoder. |
| 110 if (CastRtpStream::IsHardwareVP8EncodingSupported()) | 142 if (CastRtpStream::IsHardwareVP8EncodingSupported()) |
| 111 supported_configs.push_back(DefaultVp8Config()); | 143 supported_configs.push_back(DefaultVp8Config()); |
| 112 if (CastRtpStream::IsHardwareH264EncodingSupported()) | 144 if (CastRtpStream::IsHardwareH264EncodingSupported()) |
| 113 supported_configs.push_back(DefaultH264Config()); | 145 supported_configs.push_back(DefaultH264Config()); |
| 114 | 146 |
| 115 // Propose the default software VP8 encoder, if no hardware encoders are | 147 // Propose the default software VP8 encoder, if no hardware encoders are |
| 116 // available. | 148 // available. |
| 117 if (supported_configs.empty()) | 149 if (supported_configs.empty()) |
| 118 supported_configs.push_back(DefaultVp8Config()); | 150 supported_configs.push_back(DefaultVp8Config()); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 vea_profile.profile <= media::H264PROFILE_MAX) { | 472 vea_profile.profile <= media::H264PROFILE_MAX) { |
| 441 return true; | 473 return true; |
| 442 } | 474 } |
| 443 } | 475 } |
| 444 #endif // !defined(OS_MACOSX) | 476 #endif // !defined(OS_MACOSX) |
| 445 return false; | 477 return false; |
| 446 } | 478 } |
| 447 | 479 |
| 448 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, | 480 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, |
| 449 const scoped_refptr<CastSession>& session) | 481 const scoped_refptr<CastSession>& session) |
| 450 : track_(track), cast_session_(session), weak_factory_(this) {} | 482 : track_(track), |
| 483 cast_session_(session), | |
| 484 is_audio_(track_.source().getType() == | |
| 485 blink::WebMediaStreamSource::TypeAudio), | |
| 486 weak_factory_(this) {} | |
| 487 | |
| 488 CastRtpStream::CastRtpStream(bool is_audio, | |
| 489 const scoped_refptr<CastSession>& session) | |
| 490 : cast_session_(session), is_audio_(is_audio), weak_factory_(this) {} | |
| 451 | 491 |
| 452 CastRtpStream::~CastRtpStream() { | 492 CastRtpStream::~CastRtpStream() { |
| 453 Stop(); | 493 Stop(); |
| 454 } | 494 } |
| 455 | 495 |
| 456 std::vector<FrameSenderConfig> CastRtpStream::GetSupportedConfigs() { | 496 std::vector<FrameSenderConfig> CastRtpStream::GetSupportedConfigs() { |
| 457 if (IsAudio()) | 497 if (is_audio_) |
| 458 return SupportedAudioConfigs(); | 498 return SupportedAudioConfigs(track_.isNull()); |
| 459 else | 499 else |
| 460 return SupportedVideoConfigs(); | 500 return SupportedVideoConfigs(track_.isNull()); |
| 461 } | 501 } |
| 462 | 502 |
| 463 void CastRtpStream::Start(const FrameSenderConfig& config, | 503 void CastRtpStream::Start(int32_t stream_id, |
| 504 const FrameSenderConfig& config, | |
| 464 const base::Closure& start_callback, | 505 const base::Closure& start_callback, |
| 465 const base::Closure& stop_callback, | 506 const base::Closure& stop_callback, |
| 466 const ErrorCallback& error_callback) { | 507 const ErrorCallback& error_callback) { |
| 467 DCHECK(!start_callback.is_null()); | 508 DCHECK(!start_callback.is_null()); |
| 468 DCHECK(!stop_callback.is_null()); | 509 DCHECK(!stop_callback.is_null()); |
| 469 DCHECK(!error_callback.is_null()); | 510 DCHECK(!error_callback.is_null()); |
| 470 | 511 |
| 471 DVLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video"); | 512 DVLOG(1) << "CastRtpStream::Start = " << (is_audio_ ? "audio" : "video"); |
| 472 stop_callback_ = stop_callback; | 513 stop_callback_ = stop_callback; |
| 473 error_callback_ = error_callback; | 514 error_callback_ = error_callback; |
| 474 | 515 |
| 475 if (IsAudio()) { | 516 if (track_.isNull()) { |
| 517 cast_session_->StartRemotingStream( | |
| 518 stream_id, config, base::Bind(&CastRtpStream::DidEncounterError, | |
| 519 weak_factory_.GetWeakPtr())); | |
| 520 } else if (is_audio_) { | |
| 476 // In case of error we have to go through DidEncounterError() to stop | 521 // In case of error we have to go through DidEncounterError() to stop |
| 477 // the streaming after reporting the error. | 522 // the streaming after reporting the error. |
| 478 audio_sink_.reset( | 523 audio_sink_.reset( |
| 479 new CastAudioSink(track_, config.channels, config.rtp_timebase)); | 524 new CastAudioSink(track_, config.channels, config.rtp_timebase)); |
| 480 cast_session_->StartAudio( | 525 cast_session_->StartAudio( |
| 481 config, | 526 config, |
| 482 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), | 527 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), |
| 483 base::Bind(&CastRtpStream::DidEncounterError, | 528 base::Bind(&CastRtpStream::DidEncounterError, |
| 484 weak_factory_.GetWeakPtr())); | 529 weak_factory_.GetWeakPtr())); |
| 485 start_callback.Run(); | |
| 486 } else { | 530 } else { |
| 487 // See the code for audio above for explanation of callbacks. | 531 // See the code for audio above for explanation of callbacks. |
| 488 video_sink_.reset(new CastVideoSink( | 532 video_sink_.reset(new CastVideoSink( |
| 489 track_, | 533 track_, |
| 490 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 534 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
| 491 weak_factory_.GetWeakPtr())))); | 535 weak_factory_.GetWeakPtr())))); |
| 492 cast_session_->StartVideo( | 536 cast_session_->StartVideo( |
| 493 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), | 537 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), |
| 494 !config.aes_key.empty()), | 538 !config.aes_key.empty()), |
| 495 base::Bind(&CastRtpStream::DidEncounterError, | 539 base::Bind(&CastRtpStream::DidEncounterError, |
| 496 weak_factory_.GetWeakPtr())); | 540 weak_factory_.GetWeakPtr())); |
| 497 start_callback.Run(); | |
| 498 } | 541 } |
| 542 start_callback.Run(); | |
| 499 } | 543 } |
| 500 | 544 |
| 501 void CastRtpStream::Stop() { | 545 void CastRtpStream::Stop() { |
| 502 DVLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video"); | 546 DVLOG(1) << "CastRtpStream::Stop = " << (is_audio_ ? "audio" : "video"); |
| 503 if (stop_callback_.is_null()) | 547 if (stop_callback_.is_null()) |
| 504 return; // Already stopped. | 548 return; // Already stopped. |
| 505 weak_factory_.InvalidateWeakPtrs(); | 549 weak_factory_.InvalidateWeakPtrs(); |
| 506 error_callback_.Reset(); | 550 error_callback_.Reset(); |
| 507 audio_sink_.reset(); | 551 audio_sink_.reset(); |
| 508 video_sink_.reset(); | 552 video_sink_.reset(); |
| 509 base::ResetAndReturn(&stop_callback_).Run(); | 553 base::ResetAndReturn(&stop_callback_).Run(); |
| 510 } | 554 } |
| 511 | 555 |
| 512 void CastRtpStream::ToggleLogging(bool enable) { | 556 void CastRtpStream::ToggleLogging(bool enable) { |
| 513 DVLOG(1) << "CastRtpStream::ToggleLogging(" << enable << ") = " | 557 DVLOG(1) << "CastRtpStream::ToggleLogging(" << enable |
| 514 << (IsAudio() ? "audio" : "video"); | 558 << ") = " << (is_audio_ ? "audio" : "video"); |
| 515 cast_session_->ToggleLogging(IsAudio(), enable); | 559 cast_session_->ToggleLogging(is_audio_, enable); |
| 516 } | 560 } |
| 517 | 561 |
| 518 void CastRtpStream::GetRawEvents( | 562 void CastRtpStream::GetRawEvents( |
| 519 const base::Callback<void(std::unique_ptr<base::BinaryValue>)>& callback, | 563 const base::Callback<void(std::unique_ptr<base::BinaryValue>)>& callback, |
| 520 const std::string& extra_data) { | 564 const std::string& extra_data) { |
| 521 DVLOG(1) << "CastRtpStream::GetRawEvents = " | 565 DVLOG(1) << "CastRtpStream::GetRawEvents = " |
| 522 << (IsAudio() ? "audio" : "video"); | 566 << (is_audio_ ? "audio" : "video"); |
| 523 cast_session_->GetEventLogsAndReset(IsAudio(), extra_data, callback); | 567 cast_session_->GetEventLogsAndReset(is_audio_, extra_data, callback); |
| 524 } | 568 } |
| 525 | 569 |
| 526 void CastRtpStream::GetStats( | 570 void CastRtpStream::GetStats( |
| 527 const base::Callback<void(std::unique_ptr<base::DictionaryValue>)>& | 571 const base::Callback<void(std::unique_ptr<base::DictionaryValue>)>& |
| 528 callback) { | 572 callback) { |
| 529 DVLOG(1) << "CastRtpStream::GetStats = " | 573 DVLOG(1) << "CastRtpStream::GetStats = " << (is_audio_ ? "audio" : "video"); |
| 530 << (IsAudio() ? "audio" : "video"); | 574 cast_session_->GetStatsAndReset(is_audio_, callback); |
| 531 cast_session_->GetStatsAndReset(IsAudio(), callback); | |
| 532 } | |
| 533 | |
| 534 bool CastRtpStream::IsAudio() const { | |
| 535 return track_.source().getType() == blink::WebMediaStreamSource::TypeAudio; | |
| 536 } | 575 } |
| 537 | 576 |
| 538 void CastRtpStream::DidEncounterError(const std::string& message) { | 577 void CastRtpStream::DidEncounterError(const std::string& message) { |
| 539 DCHECK(content::RenderThread::Get()); | 578 DCHECK(content::RenderThread::Get()); |
| 540 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " | 579 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message |
| 541 << (IsAudio() ? "audio" : "video"); | 580 << ") = " << (is_audio_ ? "audio" : "video"); |
| 542 // Save the WeakPtr first because the error callback might delete this object. | 581 // Save the WeakPtr first because the error callback might delete this object. |
| 543 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); | 582 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); |
| 544 error_callback_.Run(message); | 583 error_callback_.Run(message); |
| 545 base::ThreadTaskRunnerHandle::Get()->PostTask( | 584 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 546 FROM_HERE, | 585 FROM_HERE, |
| 547 base::Bind(&CastRtpStream::Stop, ptr)); | 586 base::Bind(&CastRtpStream::Stop, ptr)); |
| 548 } | 587 } |
| OLD | NEW |