Chromium Code Reviews| Index: talk/media/webrtc/webrtcvoiceengine.cc |
| diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc |
| index 6c07ff4154c62c9e2b495536e16f63daaefe043f..e55df96ae3e68024e6cb14231fb04e9c7200ce40 100644 |
| --- a/talk/media/webrtc/webrtcvoiceengine.cc |
| +++ b/talk/media/webrtc/webrtcvoiceengine.cc |
| @@ -194,11 +194,6 @@ bool VerifyUniquePayloadTypes(const std::vector<AudioCodec>& codecs) { |
| return it == payload_types.end(); |
| } |
| -bool IsNackEnabled(const AudioCodec& codec) { |
| - return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack, |
| - kParamValueEmpty)); |
| -} |
| - |
| // Return true if codec.params[feature] == "1", false otherwise. |
| bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) { |
| int value; |
| @@ -321,6 +316,8 @@ class WebRtcVoiceCodecs final { |
| rtc::ToString(kPreferredMaxPTime); |
| } |
| codec.SetParam(kCodecParamUseInbandFec, 1); |
| + codec.AddFeedbackParam( |
| + FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); |
| // TODO(hellner): Add ptime, sprop-stereo, and stereo |
| // when they can be set to values other than the default. |
| @@ -933,6 +930,12 @@ RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { |
| capabilities.header_extensions.push_back( |
| RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, |
| kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); |
| + if (webrtc::field_trial::FindFullName("WebRTC-Audio-SendSideBwe") == |
| + "Enabled") { |
| + capabilities.header_extensions.push_back(RtpHeaderExtension( |
| + kRtpTransportSequenceNumberHeaderExtension, |
| + kRtpTransportSequenceNumberHeaderExtensionDefaultId)); |
| + } |
| return capabilities; |
| } |
| @@ -1208,19 +1211,22 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream |
| class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| public: |
| - WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc, |
| - bool use_combined_bwe, const std::string& sync_group, |
| + WebRtcAudioReceiveStream(int ch, |
| + uint32_t remote_ssrc, |
| + uint32_t local_ssrc, |
| + bool use_combined_bwe, |
| + bool use_transport_cc, |
| + const std::string& sync_group, |
| const std::vector<webrtc::RtpExtension>& extensions, |
| webrtc::Call* call) |
| - : call_(call), |
| - config_() { |
| + : call_(call), config_() { |
| RTC_DCHECK_GE(ch, 0); |
| RTC_DCHECK(call); |
| config_.rtp.remote_ssrc = remote_ssrc; |
| config_.rtp.local_ssrc = local_ssrc; |
| config_.voe_channel_id = ch; |
| config_.sync_group = sync_group; |
| - RecreateAudioReceiveStream(use_combined_bwe, extensions); |
| + RecreateAudioReceiveStream(use_combined_bwe, use_transport_cc, extensions); |
| } |
| ~WebRtcAudioReceiveStream() { |
| @@ -1231,11 +1237,18 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| void RecreateAudioReceiveStream( |
| const std::vector<webrtc::RtpExtension>& extensions) { |
| RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| - RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions); |
| + RecreateAudioReceiveStream(config_.combined_audio_video_bwe, |
| + config_.rtp.transport_cc, extensions); |
| } |
| void RecreateAudioReceiveStream(bool use_combined_bwe) { |
| RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| - RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions); |
| + RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.transport_cc, |
| + config_.rtp.extensions); |
| + } |
| + void RecreateAudioReceiveStreamWithTransportCc(bool use_transport_cc) { |
| + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| + RecreateAudioReceiveStream(config_.combined_audio_video_bwe, |
| + use_transport_cc, config_.rtp.extensions); |
| } |
| webrtc::AudioReceiveStream::Stats GetStats() const { |
| @@ -1255,7 +1268,9 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| } |
| private: |
| - void RecreateAudioReceiveStream(bool use_combined_bwe, |
| + void RecreateAudioReceiveStream( |
| + bool use_combined_bwe, |
| + bool use_transport_cc, |
| const std::vector<webrtc::RtpExtension>& extensions) { |
| RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| if (stream_) { |
| @@ -1263,6 +1278,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| stream_ = nullptr; |
| } |
| config_.rtp.extensions = extensions; |
| + config_.rtp.transport_cc = use_transport_cc; |
| config_.combined_audio_video_bwe = use_combined_bwe; |
| RTC_DCHECK(!stream_); |
| stream_ = call_->CreateAudioReceiveStream(config_); |
| @@ -1359,7 +1375,6 @@ bool WebRtcVoiceMediaChannel::SetRecvParameters( |
| it.second->RecreateAudioReceiveStream(recv_rtp_extensions_); |
| } |
| } |
| - |
| return true; |
| } |
| @@ -1481,7 +1496,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| // Scan through the list to figure out the codec to use for sending, along |
| // with the proper configuration for VAD. |
| - bool found_send_codec = false; |
| webrtc::CodecInst send_codec; |
| memset(&send_codec, 0, sizeof(send_codec)); |
| @@ -1489,53 +1503,33 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| bool enable_codec_fec = false; |
| bool enable_opus_dtx = false; |
| int opus_max_playback_rate = 0; |
| + int red_payload_type = -1; |
| // Set send codec (the first non-telephone-event/CN codec) |
| - for (const AudioCodec& codec : codecs) { |
| - // Ignore codecs we don't know about. The negotiation step should prevent |
| - // this, but double-check to be sure. |
| - webrtc::CodecInst voe_codec; |
| - if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { |
| - LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
| - continue; |
| - } |
| - |
| - if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { |
| - // Skip telephone-event/CN codec, which will be handled later. |
| - continue; |
| - } |
| - |
| - // We'll use the first codec in the list to actually send audio data. |
| - // Be sure to use the payload type requested by the remote side. |
| - // "red", for RED audio, is a special case where the actual codec to be |
| - // used is specified in params. |
| - if (IsCodec(codec, kRedCodecName)) { |
| - // Parse out the RED parameters. If we fail, just ignore RED; |
| - // we don't support all possible params/usage scenarios. |
| - if (!GetRedSendCodec(codec, codecs, &send_codec)) { |
| - continue; |
| - } |
| - |
| + const AudioCodec* codec = |
| + GetPreferredCodec(codecs, &send_codec, &red_payload_type); |
| + if (codec) { |
| + if (red_payload_type != -1) { |
| // Enable redundant encoding of the specified codec. Treat any |
| // failure as a fatal internal error. |
| LOG(LS_INFO) << "Enabling RED on channel " << channel; |
| - if (engine()->voe()->rtp()->SetREDStatus(channel, true, codec.id) == -1) { |
| - LOG_RTCERR3(SetREDStatus, channel, true, codec.id); |
| + if (engine()->voe()->rtp()->SetREDStatus(channel, true, |
| + red_payload_type) == -1) { |
| + LOG_RTCERR3(SetREDStatus, channel, true, red_payload_type); |
| return false; |
| } |
| } else { |
| - send_codec = voe_codec; |
| - nack_enabled = IsNackEnabled(codec); |
| + nack_enabled = HasNack(*codec); |
| // For Opus as the send codec, we are to determine inband FEC, maximum |
| // playback rate, and opus internal dtx. |
| - if (IsCodec(codec, kOpusCodecName)) { |
| - GetOpusConfig(codec, &send_codec, &enable_codec_fec, |
| + if (IsCodec(*codec, kOpusCodecName)) { |
| + GetOpusConfig(*codec, &send_codec, &enable_codec_fec, |
| &opus_max_playback_rate, &enable_opus_dtx); |
| } |
| // Set packet size if the AudioCodec param kCodecParamPTime is set. |
| int ptime_ms = 0; |
| - if (codec.GetParam(kCodecParamPTime, &ptime_ms)) { |
| + if (codec->GetParam(kCodecParamPTime, &ptime_ms)) { |
| if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) { |
| LOG(LS_WARNING) << "Failed to set packet size for codec " |
| << send_codec.plname; |
| @@ -1543,16 +1537,13 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| } |
| } |
| } |
| - found_send_codec = true; |
| - break; |
| } |
| if (nack_enabled_ != nack_enabled) { |
| SetNack(channel, nack_enabled); |
| nack_enabled_ = nack_enabled; |
| } |
| - |
| - if (!found_send_codec) { |
| + if (!codec) { |
| LOG(LS_WARNING) << "Received empty list of codecs."; |
| return false; |
| } |
| @@ -1671,6 +1662,43 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| return true; |
| } |
| +const AudioCodec* WebRtcVoiceMediaChannel::GetPreferredCodec( |
| + const std::vector<AudioCodec>& codecs, |
| + webrtc::CodecInst* voe_codec, |
| + int* red_payload_type) const { |
| + // Set send codec (the first non-telephone-event/CN codec) |
| + for (const AudioCodec& codec : codecs) { |
| + *red_payload_type = -1; |
| + if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { |
| + // Skip telephone-event/CN codec, which will be handled later. |
| + continue; |
| + } |
| + |
| + // We'll use the first codec in the list to actually send audio data. |
| + // Be sure to use the payload type requested by the remote side. |
| + // "red", for RED audio, is a special case where the actual codec to be |
| + // used is specified in params. |
| + const AudioCodec* found_codec = &codec; |
| + if (IsCodec(*found_codec, kRedCodecName)) { |
| + // Parse out the RED parameters. If we fail, just ignore RED; |
| + // we don't support all possible params/usage scenarios. |
| + *red_payload_type = codec.id; |
| + found_codec = GetRedSendCodec(*found_codec, codecs); |
| + if (!found_codec) { |
| + continue; |
| + } |
| + } |
| + // Ignore codecs we don't know about. The negotiation step should prevent |
| + // this, but double-check to be sure. |
| + if (!WebRtcVoiceEngine::ToCodecInst(*found_codec, voe_codec)) { |
| + LOG(LS_WARNING) << "Unknown codec " << ToString(*found_codec); |
| + continue; |
| + } |
| + return found_codec; |
| + } |
| + return nullptr; |
| +} |
| + |
| bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| const std::vector<AudioCodec>& codecs) { |
| RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| @@ -1700,6 +1728,26 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| SetNack(ch.second->channel(), nack_enabled_); |
| } |
| + // Check if the transport cc feedback has changed on the preferred send codec, |
| + // and in that case reconfigure all receive streams. |
| + webrtc::CodecInst voe_codec; |
| + int red_payload_type; |
| + const AudioCodec* send_codec = |
| + GetPreferredCodec(send_codecs_, &voe_codec, &red_payload_type); |
| + if (send_codec) { |
| + bool transport_cc = HasTransportCc(*send_codec); |
| + if (transport_cc_enabled_ != transport_cc) { |
| + LOG(LS_INFO) << "Recreate all the receive streams because the send " |
| + "codec has changed."; |
| + transport_cc_enabled_ = transport_cc; |
| + for (auto& kv : recv_streams_) { |
| + RTC_DCHECK(kv.second != nullptr); |
| + kv.second->RecreateAudioReceiveStreamWithTransportCc( |
| + transport_cc_enabled_); |
| + } |
| + } |
| + } |
|
stefan-webrtc
2016/01/18 15:32:32
I think this should work, as it is what we are doi
|
| + |
| return true; |
| } |
| @@ -2006,10 +2054,15 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { |
| << " is associated with channel #" << send_channel << "."; |
| } |
| - recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream( |
| - channel, ssrc, receiver_reports_ssrc_, |
| - options_.combined_audio_video_bwe.value_or(false), sp.sync_label, |
| - recv_rtp_extensions_, call_))); |
| + transport_cc_enabled_ = |
| + !send_codecs_.empty() ? HasTransportCc(send_codecs_[0]) : false; |
| + |
| + recv_streams_.insert(std::make_pair( |
| + ssrc, |
| + new WebRtcAudioReceiveStream( |
| + channel, ssrc, receiver_reports_ssrc_, |
| + options_.combined_audio_video_bwe.value_or(false), |
| + transport_cc_enabled_, sp.sync_label, recv_rtp_extensions_, call_))); |
| SetNack(channel, nack_enabled_); |
| SetPlayout(channel, playout_); |
| @@ -2452,8 +2505,9 @@ int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const { |
| return -1; |
| } |
| -bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, |
| - const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) { |
| +const AudioCodec* WebRtcVoiceMediaChannel::GetRedSendCodec( |
| + const AudioCodec& red_codec, |
| + const std::vector<AudioCodec>& all_codecs) const { |
| // Get the RED encodings from the parameter with no name. This may |
| // change based on what is discussed on the Jingle list. |
| // The encoding parameter is of the form "a/b"; we only support where |
| @@ -2471,7 +2525,7 @@ bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, |
| red_pts[0] != red_pts[1] || |
| !rtc::FromString(red_pts[0], &red_pt)) { |
| LOG(LS_WARNING) << "RED params " << red_params << " not supported."; |
| - return false; |
| + return nullptr; |
| } |
| } else if (red_codec.params.empty()) { |
| LOG(LS_WARNING) << "RED params not present, using defaults"; |
| @@ -2483,17 +2537,11 @@ bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, |
| // Try to find red_pt in |codecs|. |
| for (const AudioCodec& codec : all_codecs) { |
| if (codec.id == red_pt) { |
| - // If we find the right codec, that will be the codec we pass to |
| - // SetSendCodec, with the desired payload type. |
| - if (WebRtcVoiceEngine::ToCodecInst(codec, send_codec)) { |
| - return true; |
| - } else { |
| - break; |
| - } |
| + return &codec; |
| } |
| } |
| LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; |
| - return false; |
| + return nullptr; |
| } |
| bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { |