Chromium Code Reviews| Index: media/cast/net/cast_transport_impl.cc |
| diff --git a/media/cast/net/cast_transport_impl.cc b/media/cast/net/cast_transport_impl.cc |
| index 5ace37f1914fc439619810f052e1d0bf3d3eb1cd..f0a6e04b0f30649aca2156a24bd23fd0a1f64058 100644 |
| --- a/media/cast/net/cast_transport_impl.cc |
| +++ b/media/cast/net/cast_transport_impl.cc |
| @@ -91,6 +91,27 @@ class CastTransportImpl::RtcpClient : public RtcpObserver { |
| DISALLOW_COPY_AND_ASSIGN(RtcpClient); |
| }; |
| +struct CastTransportImpl::RtpStreamSession { |
| + explicit RtpStreamSession(bool is_audio_stream) : is_audio(is_audio_stream) {} |
| + |
| + // Packetizer for audio and video frames. |
| + std::unique_ptr<RtpSender> rtp_sender; |
| + |
| + // Maintains RTCP session for audio and video. |
| + std::unique_ptr<SenderRtcpSession> rtcp_session; |
| + |
| + // RTCP observer for SenderRtcpSession. |
| + std::unique_ptr<RtcpObserver> rtcp_observer; |
| + |
| + // Encrypts data in EncodedFrames before they are sent. Note that it's |
| + // important for the encryption to happen here, in code that would execute in |
| + // the main browser process, for security reasons. This helps to mitigate |
| + // the damage that could be caused by a compromised renderer process. |
| + TransportEncryptionHandler encryptor; |
| + |
| + bool is_audio; |
|
miu
2016/07/06 21:45:42
const please ;)
xjz
2016/07/13 20:31:17
Done.
|
| +}; |
| + |
| CastTransportImpl::CastTransportImpl( |
| base::TickClock* clock, |
| base::TimeDelta logging_flush_interval, |
| @@ -129,63 +150,45 @@ CastTransportImpl::~CastTransportImpl() { |
| transport_->StopReceiving(); |
| } |
| -void CastTransportImpl::InitializeAudio( |
| +void CastTransportImpl::InitializeStream( |
| const CastTransportRtpConfig& config, |
| std::unique_ptr<RtcpObserver> rtcp_observer) { |
| - LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) |
| - << "Unsafe to send audio with encryption DISABLED."; |
| - if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) { |
| - transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED); |
| - return; |
| - } |
| + if (sessions_.find(config.ssrc) != sessions_.end()) |
| + DVLOG(1) << "Initialize an existing stream on RTP sender." << config.ssrc; |
| - audio_sender_.reset(new RtpSender(transport_task_runner_, &pacer_)); |
| - if (audio_sender_->Initialize(config)) { |
| - // Audio packets have a higher priority. |
| - pacer_.RegisterAudioSsrc(config.ssrc); |
| - pacer_.RegisterPrioritySsrc(config.ssrc); |
| - transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED); |
| - } else { |
| - audio_sender_.reset(); |
| - transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED); |
| - return; |
| - } |
| + LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) |
| + << "Unsafe to send stream with encryption DISABLED."; |
| - audio_rtcp_observer_.reset( |
| - new RtcpClient(std::move(rtcp_observer), config.ssrc, AUDIO_EVENT, this)); |
| - audio_rtcp_session_.reset( |
| - new SenderRtcpSession(clock_, &pacer_, audio_rtcp_observer_.get(), |
| - config.ssrc, config.feedback_ssrc)); |
| - pacer_.RegisterAudioSsrc(config.ssrc); |
| - valid_sender_ssrcs_.insert(config.feedback_ssrc); |
| - transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED); |
| -} |
| + bool is_audio = config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST; |
| + std::unique_ptr<RtpStreamSession> session(new RtpStreamSession(is_audio)); |
| -void CastTransportImpl::InitializeVideo( |
| - const CastTransportRtpConfig& config, |
| - std::unique_ptr<RtcpObserver> rtcp_observer) { |
| - LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) |
| - << "Unsafe to send video with encryption DISABLED."; |
| - if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) { |
| - transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED); |
| + if (!session->encryptor.Initialize(config.aes_key, config.aes_iv_mask)) { |
| + transport_client_->OnStatusChanged(TRANSPORT_STREAM_UNINITIALIZED); |
| return; |
| } |
| - video_sender_.reset(new RtpSender(transport_task_runner_, &pacer_)); |
| - if (!video_sender_->Initialize(config)) { |
| - video_sender_.reset(); |
| - transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED); |
| + session->rtp_sender.reset(new RtpSender(transport_task_runner_, &pacer_)); |
| + if (!session->rtp_sender->Initialize(config)) { |
| + session->rtp_sender.reset(); |
| + transport_client_->OnStatusChanged(TRANSPORT_STREAM_UNINITIALIZED); |
| return; |
| } |
| - video_rtcp_observer_.reset( |
| - new RtcpClient(std::move(rtcp_observer), config.ssrc, VIDEO_EVENT, this)); |
| - video_rtcp_session_.reset( |
| - new SenderRtcpSession(clock_, &pacer_, video_rtcp_observer_.get(), |
| + pacer_.RegisterSsrc(config.ssrc, is_audio); |
| + // Audio packets have a higher priority. |
| + if (is_audio) |
| + pacer_.RegisterPrioritySsrc(config.ssrc); |
| + |
| + session->rtcp_observer.reset( |
| + new RtcpClient(std::move(rtcp_observer), config.ssrc, |
| + is_audio ? AUDIO_EVENT : VIDEO_EVENT, this)); |
| + session->rtcp_session.reset( |
| + new SenderRtcpSession(clock_, &pacer_, session->rtcp_observer.get(), |
| config.ssrc, config.feedback_ssrc)); |
| - pacer_.RegisterVideoSsrc(config.ssrc); |
| + |
| valid_sender_ssrcs_.insert(config.feedback_ssrc); |
| - transport_client_->OnStatusChanged(TRANSPORT_VIDEO_INITIALIZED); |
| + transport_client_->OnStatusChanged(TRANSPORT_STREAM_INITIALIZED); |
| + sessions_[config.ssrc] = std::move(session); |
| } |
| namespace { |
| @@ -210,59 +213,56 @@ void EncryptAndSendFrame(const EncodedFrame& frame, |
| } // namespace |
| void CastTransportImpl::InsertFrame(uint32_t ssrc, const EncodedFrame& frame) { |
| - if (audio_sender_ && ssrc == audio_sender_->ssrc()) { |
| - audio_rtcp_session_->WillSendFrame(frame.frame_id); |
| - EncryptAndSendFrame(frame, &audio_encryptor_, audio_sender_.get()); |
| - } else if (video_sender_ && ssrc == video_sender_->ssrc()) { |
| - video_rtcp_session_->WillSendFrame(frame.frame_id); |
| - EncryptAndSendFrame(frame, &video_encryptor_, video_sender_.get()); |
| - } else { |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end()) { |
| NOTREACHED() << "Invalid InsertFrame call."; |
| + return; |
| } |
| + |
| + it->second->rtcp_session->WillSendFrame(frame.frame_id); |
| + EncryptAndSendFrame(frame, &it->second->encryptor, |
| + it->second->rtp_sender.get()); |
| } |
| void CastTransportImpl::SendSenderReport( |
| uint32_t ssrc, |
| base::TimeTicks current_time, |
| RtpTimeTicks current_time_as_rtp_timestamp) { |
| - if (audio_sender_ && ssrc == audio_sender_->ssrc()) { |
| - audio_rtcp_session_->SendRtcpReport( |
| - current_time, current_time_as_rtp_timestamp, |
| - audio_sender_->send_packet_count(), audio_sender_->send_octet_count()); |
| - } else if (video_sender_ && ssrc == video_sender_->ssrc()) { |
| - video_rtcp_session_->SendRtcpReport( |
| - current_time, current_time_as_rtp_timestamp, |
| - video_sender_->send_packet_count(), video_sender_->send_octet_count()); |
| - } else { |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end()) { |
| NOTREACHED() << "Invalid request for sending RTCP packet."; |
| + return; |
| } |
| + |
| + it->second->rtcp_session->SendRtcpReport( |
| + current_time, current_time_as_rtp_timestamp, |
| + it->second->rtp_sender->send_packet_count(), |
| + it->second->rtp_sender->send_octet_count()); |
| } |
| void CastTransportImpl::CancelSendingFrames( |
| uint32_t ssrc, |
| const std::vector<FrameId>& frame_ids) { |
| - if (audio_sender_ && ssrc == audio_sender_->ssrc()) { |
| - audio_sender_->CancelSendingFrames(frame_ids); |
| - } else if (video_sender_ && ssrc == video_sender_->ssrc()) { |
| - video_sender_->CancelSendingFrames(frame_ids); |
| - } else { |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end()) { |
| NOTREACHED() << "Invalid request for cancel sending."; |
| + return; |
| } |
| + |
| + it->second->rtp_sender->CancelSendingFrames(frame_ids); |
| } |
| void CastTransportImpl::ResendFrameForKickstart(uint32_t ssrc, |
| FrameId frame_id) { |
| - if (audio_sender_ && ssrc == audio_sender_->ssrc()) { |
| - DCHECK(audio_rtcp_session_); |
| - audio_sender_->ResendFrameForKickstart( |
| - frame_id, audio_rtcp_session_->current_round_trip_time()); |
| - } else if (video_sender_ && ssrc == video_sender_->ssrc()) { |
| - DCHECK(video_rtcp_session_); |
| - video_sender_->ResendFrameForKickstart( |
| - frame_id, video_rtcp_session_->current_round_trip_time()); |
| - } else { |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end()) { |
| NOTREACHED() << "Invalid request for kickstart."; |
| + return; |
| } |
| + |
| + DCHECK(it->second->rtcp_session); |
| + it->second->rtp_sender->ResendFrameForKickstart( |
| + frame_id, it->second->rtcp_session->current_round_trip_time()); |
| } |
| void CastTransportImpl::ResendPackets( |
| @@ -270,15 +270,14 @@ void CastTransportImpl::ResendPackets( |
| const MissingFramesAndPacketsMap& missing_packets, |
| bool cancel_rtx_if_not_in_list, |
| const DedupInfo& dedup_info) { |
| - if (audio_sender_ && ssrc == audio_sender_->ssrc()) { |
| - audio_sender_->ResendPackets(missing_packets, cancel_rtx_if_not_in_list, |
| - dedup_info); |
| - } else if (video_sender_ && ssrc == video_sender_->ssrc()) { |
| - video_sender_->ResendPackets(missing_packets, cancel_rtx_if_not_in_list, |
| - dedup_info); |
| - } else { |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end()) { |
| NOTREACHED() << "Invalid request for retransmission."; |
| + return; |
| } |
| + |
| + it->second->rtp_sender->ResendPackets(missing_packets, |
| + cancel_rtx_if_not_in_list, dedup_info); |
| } |
| PacketReceiverCallback CastTransportImpl::PacketReceiverForTesting() { |
| @@ -321,14 +320,12 @@ bool CastTransportImpl::OnReceivedPacket(std::unique_ptr<Packet> packet) { |
| return false; |
| } |
| - if (audio_rtcp_session_ && |
| - audio_rtcp_session_->IncomingRtcpPacket(data, length)) { |
| - return true; |
| - } |
| - if (video_rtcp_session_ && |
| - video_rtcp_session_->IncomingRtcpPacket(data, length)) { |
| - return true; |
| + for (auto it = sessions_.begin(); it != sessions_.end(); ++it) { |
|
miu
2016/07/06 21:45:42
nit: for (const auto& e : sessions_) { if (e.secon
xjz
2016/07/13 20:31:17
Done.
|
| + if (it->second->rtcp_session && |
|
miu
2016/07/06 21:45:42
IIUC, you don't need to null-check the rtcp_sessio
xjz
2016/07/13 20:31:17
Done.
|
| + it->second->rtcp_session->IncomingRtcpPacket(data, length)) |
| + return true; |
| } |
| + |
| transport_client_->ProcessRtpPacket(std::move(packet)); |
| return true; |
| } |
| @@ -381,16 +378,21 @@ void CastTransportImpl::OnReceivedCastMessage( |
| const RtcpCastMessage& cast_message) { |
| DedupInfo dedup_info; |
| - if (audio_sender_ && audio_sender_->ssrc() == ssrc) { |
| - const int64_t acked_bytes = |
| - audio_sender_->GetLastByteSentForFrame(cast_message.ack_frame_id); |
| + auto it = sessions_.find(ssrc); |
| + if (it == sessions_.end() || !it->second->rtp_sender) |
| + return; |
| + |
| + if (it->second->is_audio) { |
| + const int64_t acked_bytes = it->second->rtp_sender->GetLastByteSentForFrame( |
| + cast_message.ack_frame_id); |
| last_byte_acked_for_audio_ = |
| std::max(acked_bytes, last_byte_acked_for_audio_); |
| - } else if (video_sender_ && video_sender_->ssrc() == ssrc) { |
| - dedup_info.resend_interval = video_rtcp_session_->current_round_trip_time(); |
| + } else { |
| + dedup_info.resend_interval = |
| + it->second->rtcp_session->current_round_trip_time(); |
| // Only use audio stream to dedup if there is one. |
| - if (audio_sender_) { |
| + if (last_byte_acked_for_audio_) { |
| dedup_info.last_byte_acked_for_audio = last_byte_acked_for_audio_; |
| } |
| } |