diff --git a/api/rtpparameters.cc b/api/rtpparameters.cc index 79fd3a93f9..cb9c1cf21c 100644 --- a/api/rtpparameters.cc +++ b/api/rtpparameters.cc @@ -114,6 +114,9 @@ const char RtpExtension::kVideoTimingUri[] = "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"; const int RtpExtension::kVideoTimingDefaultId = 8; +const char RtpExtension::kMidUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid"; +const int RtpExtension::kMidDefaultId = 9; + const char RtpExtension::kEncryptHeaderExtensionsUri[] = "urn:ietf:params:rtp-hdrext:encrypt"; @@ -122,7 +125,8 @@ const int RtpExtension::kMaxId = 14; bool RtpExtension::IsSupportedForAudio(const std::string& uri) { return uri == webrtc::RtpExtension::kAudioLevelUri || - uri == webrtc::RtpExtension::kTransportSequenceNumberUri; + uri == webrtc::RtpExtension::kTransportSequenceNumberUri || + uri == webrtc::RtpExtension::kMidUri; } bool RtpExtension::IsSupportedForVideo(const std::string& uri) { @@ -132,7 +136,8 @@ bool RtpExtension::IsSupportedForVideo(const std::string& uri) { uri == webrtc::RtpExtension::kTransportSequenceNumberUri || uri == webrtc::RtpExtension::kPlayoutDelayUri || uri == webrtc::RtpExtension::kVideoContentTypeUri || - uri == webrtc::RtpExtension::kVideoTimingUri; + uri == webrtc::RtpExtension::kVideoTimingUri || + uri == webrtc::RtpExtension::kMidUri; } bool RtpExtension::IsEncryptionSupported(const std::string& uri) { @@ -149,7 +154,8 @@ bool RtpExtension::IsEncryptionSupported(const std::string& uri) { uri == webrtc::RtpExtension::kVideoRotationUri || uri == webrtc::RtpExtension::kTransportSequenceNumberUri || uri == webrtc::RtpExtension::kPlayoutDelayUri || - uri == webrtc::RtpExtension::kVideoContentTypeUri; + uri == webrtc::RtpExtension::kVideoContentTypeUri || + uri == webrtc::RtpExtension::kMidUri; } const RtpExtension* RtpExtension::FindHeaderExtensionByUri( diff --git a/api/rtpparameters.h b/api/rtpparameters.h index d9ac1b6238..12e041939f 100644 --- a/api/rtpparameters.h +++ b/api/rtpparameters.h @@ -276,6 +276,11 @@ struct RtpExtension { static const char kPlayoutDelayUri[]; static const int kPlayoutDelayDefaultId; + // Header extension for identifying media section within a transport. + // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-49#section-15 + static const char kMidUri[]; + static const int kMidDefaultId; + // Encryption of Header Extensions, see RFC 6904 for details: // https://tools.ietf.org/html/rfc6904 static const char kEncryptHeaderExtensionsUri[]; diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc index 9cf73459ea..4417af3e3b 100644 --- a/audio/audio_send_stream.cc +++ b/audio/audio_send_stream.cc @@ -184,6 +184,8 @@ AudioSendStream::ExtensionIds AudioSendStream::FindExtensionIds( ids.audio_level = extension.id; } else if (extension.uri == RtpExtension::kTransportSequenceNumberUri) { ids.transport_sequence_number = extension.id; + } else if (extension.uri == RtpExtension::kMidUri) { + ids.mid = extension.id; } } return ids; @@ -260,6 +262,12 @@ void AudioSendStream::ConfigureStream( bandwidth_observer); } + // MID RTP header extension. + if ((first_time || new_ids.mid != old_ids.mid) && new_ids.mid != 0 && + !new_config.rtp.mid.empty()) { + channel_proxy->SetMid(new_config.rtp.mid, new_ids.mid); + } + if (!ReconfigureSendCodec(stream, new_config)) { RTC_LOG(LS_ERROR) << "Failed to set up send codec state."; } diff --git a/audio/audio_send_stream.h b/audio/audio_send_stream.h index 8a4528b446..c51c7a3b2f 100644 --- a/audio/audio_send_stream.h +++ b/audio/audio_send_stream.h @@ -158,6 +158,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, struct ExtensionIds { int audio_level = 0; int transport_sequence_number = 0; + int mid = 0; }; static ExtensionIds FindExtensionIds( const std::vector& extensions); diff --git a/audio/channel.cc b/audio/channel.cc index 8dbe12ed04..7dd04d696e 100644 --- a/audio/channel.cc +++ b/audio/channel.cc @@ -1042,6 +1042,12 @@ int Channel::SetLocalSSRC(unsigned int ssrc) { return 0; } +void Channel::SetMid(const std::string& mid, int extension_id) { + int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id); + RTC_DCHECK_EQ(0, ret); + _rtpRtcpModule->SetMid(mid); +} + int Channel::GetRemoteSSRC(unsigned int& ssrc) { ssrc = rtp_receiver_->SSRC(); return 0; diff --git a/audio/channel.h b/audio/channel.h index 532ad156ed..dbb670aa85 100644 --- a/audio/channel.h +++ b/audio/channel.h @@ -219,6 +219,7 @@ class Channel // RTP+RTCP int SetLocalSSRC(unsigned int ssrc); + void SetMid(const std::string& mid, int extension_id); int SetSendAudioLevelIndicationStatus(bool enable, unsigned char id); void EnableSendTransportSequenceNumber(int id); diff --git a/audio/channel_proxy.cc b/audio/channel_proxy.cc index f2575159d7..b8d520d531 100644 --- a/audio/channel_proxy.cc +++ b/audio/channel_proxy.cc @@ -53,6 +53,11 @@ void ChannelProxy::SetLocalSSRC(uint32_t ssrc) { RTC_DCHECK_EQ(0, error); } +void ChannelProxy::SetMid(const std::string& mid, int extension_id) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + channel_->SetMid(mid, extension_id); +} + void ChannelProxy::SetRTCP_CNAME(const std::string& c_name) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Note: VoERTP_RTCP::SetRTCP_CNAME() accepts a char[256] array. diff --git a/audio/channel_proxy.h b/audio/channel_proxy.h index 65f244d754..eadd686303 100644 --- a/audio/channel_proxy.h +++ b/audio/channel_proxy.h @@ -62,6 +62,7 @@ class ChannelProxy : public RtpPacketSinkInterface { virtual void SetRTCPStatus(bool enable); virtual void SetLocalSSRC(uint32_t ssrc); + virtual void SetMid(const std::string& mid, int extension_id); virtual void SetRTCP_CNAME(const std::string& c_name); virtual void SetNACKStatus(bool enable, int max_packets); virtual void SetSendAudioLevelIndicationStatus(bool enable, int id); diff --git a/call/audio_send_stream.h b/call/audio_send_stream.h index f84c6cb90b..3bfff120f1 100644 --- a/call/audio_send_stream.h +++ b/call/audio_send_stream.h @@ -74,6 +74,10 @@ class AudioSendStream { // Sender SSRC. uint32_t ssrc = 0; + // The value to send in the MID RTP header extension if the extension is + // included in the list of extensions. + std::string mid; + // RTP header extensions used for the sent stream. std::vector extensions; diff --git a/call/video_send_stream.h b/call/video_send_stream.h index b4fac51a04..34bb5aea96 100644 --- a/call/video_send_stream.h +++ b/call/video_send_stream.h @@ -142,6 +142,10 @@ class VideoSendStream { std::vector ssrcs; + // The value to send in the MID RTP header extension if the extension is + // included in the list of extensions. + std::string mid; + // See RtcpMode for description. RtcpMode rtcp_mode = RtcpMode::kCompound; diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h index 90fa40cff8..0b37e5d293 100644 --- a/media/base/mediachannel.h +++ b/media/base/mediachannel.h @@ -615,11 +615,15 @@ struct RtpSendParameters : RtpParameters { ost << "codecs: " << VectorToString(this->codecs) << ", "; ost << "extensions: " << VectorToString(this->extensions) << ", "; ost << "max_bandwidth_bps: " << max_bandwidth_bps << ", "; + ost << "mid: " << (mid.empty() ? "" : mid) << ", "; ost << "}"; return ost.str(); } int max_bandwidth_bps = -1; + // This is the value to be sent in the MID RTP header extension (if the header + // extension in included in the list of extensions). + std::string mid; }; struct AudioSendParameters : RtpSendParameters { diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc index 6442c44337..df0b33d322 100644 --- a/media/engine/webrtcvideoengine.cc +++ b/media/engine/webrtcvideoengine.cc @@ -596,6 +596,10 @@ RtpCapabilities WebRtcVideoEngine::GetCapabilities() const { capabilities.header_extensions.push_back( webrtc::RtpExtension(webrtc::RtpExtension::kVideoTimingUri, webrtc::RtpExtension::kVideoTimingDefaultId)); + // TODO(bugs.webrtc.org/4050): Add MID header extension as capability once MID + // demuxing is completed. + // capabilities.header_extensions.push_back(webrtc::RtpExtension( + // webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId)); return capabilities; } @@ -715,6 +719,10 @@ bool WebRtcVideoChannel::GetChangedSendParameters( rtc::Optional>(filtered_extensions); } + if (params.mid != send_params_.mid) { + changed_params->mid = params.mid; + } + // Handle max bitrate. if (params.max_bandwidth_bps != send_params_.max_bandwidth_bps && params.max_bandwidth_bps >= -1) { @@ -1632,6 +1640,8 @@ WebRtcVideoChannel::WebRtcVideoSendStream::WebRtcVideoSendStream( parameters_.config.rtp.rtcp_mode = send_params.rtcp.reduced_size ? webrtc::RtcpMode::kReducedSize : webrtc::RtcpMode::kCompound; + parameters_.config.rtp.mid = send_params.mid; + if (codec_settings) { SetCodec(*codec_settings); } @@ -1776,6 +1786,10 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters( parameters_.config.rtp.extensions = *params.rtp_header_extensions; recreate_stream = true; } + if (params.mid) { + parameters_.config.rtp.mid = *params.mid; + recreate_stream = true; + } if (params.max_bandwidth_bps) { parameters_.max_bitrate_bps = *params.max_bandwidth_bps; ReconfigureEncoder(); diff --git a/media/engine/webrtcvideoengine.h b/media/engine/webrtcvideoengine.h index 04096e66c7..07e6c70e93 100644 --- a/media/engine/webrtcvideoengine.h +++ b/media/engine/webrtcvideoengine.h @@ -213,6 +213,7 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport { // These optionals are unset if not changed. rtc::Optional codec; rtc::Optional> rtp_header_extensions; + rtc::Optional mid; rtc::Optional max_bandwidth_bps; rtc::Optional conference_mode; rtc::Optional rtcp_mode; diff --git a/media/engine/webrtcvoiceengine.cc b/media/engine/webrtcvoiceengine.cc index 04f299779b..d6ec44b58b 100644 --- a/media/engine/webrtcvoiceengine.cc +++ b/media/engine/webrtcvoiceengine.cc @@ -600,6 +600,10 @@ RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { webrtc::RtpExtension::kTransportSequenceNumberUri, webrtc::RtpExtension::kTransportSequenceNumberDefaultId)); } + // TODO(bugs.webrtc.org/4050): Add MID header extension as capability once MID + // demuxing is completed. + // capabilities.header_extensions.push_back(webrtc::RtpExtension( + // webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId)); return capabilities; } @@ -742,6 +746,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream public: WebRtcAudioSendStream( uint32_t ssrc, + const std::string& mid, const std::string& c_name, const std::string track_id, const rtc::Optional& @@ -762,6 +767,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream RTC_DCHECK(call); RTC_DCHECK(encoder_factory); config_.rtp.ssrc = ssrc; + config_.rtp.mid = mid; config_.rtp.c_name = c_name; config_.rtp.extensions = extensions; config_.audio_network_adaptor_config = audio_network_adaptor_config; @@ -795,6 +801,15 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream ReconfigureAudioSendStream(); } + void SetMid(const std::string& mid) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + if (config_.rtp.mid == mid) { + return; + } + config_.rtp.mid = mid; + ReconfigureAudioSendStream(); + } + void SetAudioNetworkAdaptorConfig( const rtc::Optional& audio_network_adaptor_config) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); @@ -1302,6 +1317,12 @@ bool WebRtcVoiceMediaChannel::SetSendParameters( it.second->SetRtpExtensions(send_rtp_extensions_); } } + if (!params.mid.empty()) { + mid_ = params.mid; + for (auto& it : send_streams_) { + it.second->SetMid(params.mid); + } + } if (!SetMaxSendBitrate(params.max_bandwidth_bps)) { return false; @@ -1768,7 +1789,7 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { rtc::Optional audio_network_adaptor_config = GetAudioNetworkAdaptorConfig(options_); WebRtcAudioSendStream* stream = new WebRtcAudioSendStream( - ssrc, sp.cname, sp.id, send_codec_spec_, send_rtp_extensions_, + ssrc, mid_, sp.cname, sp.id, send_codec_spec_, send_rtp_extensions_, max_send_bitrate_bps_, audio_network_adaptor_config, call_, this, engine()->encoder_factory_, codec_pair_id_); send_streams_.insert(std::make_pair(ssrc, stream)); diff --git a/media/engine/webrtcvoiceengine.h b/media/engine/webrtcvoiceengine.h index 950b72b5f5..c66aa95a38 100644 --- a/media/engine/webrtcvoiceengine.h +++ b/media/engine/webrtcvoiceengine.h @@ -264,6 +264,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, class WebRtcAudioSendStream; std::map send_streams_; std::vector send_rtp_extensions_; + std::string mid_; class WebRtcAudioReceiveStream; std::map recv_streams_; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 27d39624f1..45983a0fd9 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -50,6 +50,8 @@ RTPExtensionType StringToRtpExtensionType(const std::string& extension) { return kRtpExtensionVideoContentType; if (extension == RtpExtension::kVideoTimingUri) return kRtpExtensionVideoTiming; + if (extension == RtpExtension::kMidUri) + return kRtpExtensionMid; RTC_NOTREACHED() << "Looking up unsupported RTP extension."; return kRtpExtensionNone; } diff --git a/pc/channel.cc b/pc/channel.cc index a7ec6680a4..358cb77e55 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -1265,6 +1265,7 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content, AudioSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(audio, rtp_header_extensions, &send_params); + send_params.mid = content_name(); bool parameters_applied = media_channel()->SetSendParameters(send_params); if (!parameters_applied) { @@ -1410,6 +1411,7 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content, if (video->conference_mode()) { send_params.conference_mode = true; } + send_params.mid = content_name(); bool parameters_applied = media_channel()->SetSendParameters(send_params); diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc index 172b4b73f4..7ca89612b4 100644 --- a/video/video_send_stream.cc +++ b/video/video_send_stream.cc @@ -147,12 +147,10 @@ std::unique_ptr MaybeCreateFlexfecSender( } RTC_DCHECK_EQ(1U, config.rtp.flexfec.protected_media_ssrcs.size()); - // TODO(bugs.webrtc.org/4050): Pass down MID value once it is exposed in the - // API. - return std::unique_ptr(new FlexfecSender( + return rtc::MakeUnique( config.rtp.flexfec.payload_type, config.rtp.flexfec.ssrc, config.rtp.flexfec.protected_media_ssrcs[0], config.rtp.extensions, - RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock())); + RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock()); } bool TransportSeqNumExtensionConfigured(const VideoSendStream::Config& config) { @@ -822,6 +820,12 @@ VideoSendStreamImpl::VideoSendStreamImpl( ConfigureProtection(); ConfigureSsrcs(); + if (!config_->rtp.mid.empty()) { + for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) { + rtp_rtcp->SetMid(config_->rtp.mid); + } + } + // TODO(pbos): Should we set CNAME on all RTP modules? rtp_rtcp_modules_.front()->SetCNAME(config_->rtp.c_name.c_str());