Chromium Code Reviews| Index: talk/media/webrtc/webrtcvoiceengine.cc |
| diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc |
| index 05b98ec154402c2de2d94c8716def60bb0692e8d..8607a7324347b19f78a455c0cf4376b8a759e8c8 100644 |
| --- a/talk/media/webrtc/webrtcvoiceengine.cc |
| +++ b/talk/media/webrtc/webrtcvoiceengine.cc |
| @@ -148,6 +148,18 @@ const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; |
| const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; |
| #endif |
| +bool ValidateStreamParams(const StreamParams& sp) { |
|
pthatcher1
2015/10/06 18:19:52
To go along with VerifyUniquePayloadTypes, you mig
the sun
2015/10/07 10:50:25
That may not be the only thing it checks, going fo
|
| + if (sp.ssrcs.empty()) { |
| + LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); |
| + return false; |
| + } |
| + if (sp.ssrcs.size() > 1) { |
| + LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| // Dumps an AudioCodec in RFC 2327-ish format. |
| std::string ToString(const AudioCodec& codec) { |
| std::stringstream ss; |
| @@ -221,6 +233,19 @@ bool FindCodec(const std::vector<AudioCodec>& codecs, |
| return false; |
| } |
| +bool VerifyUniquePayloadTypes(const std::vector<AudioCodec>& codecs) { |
| + if (codecs.empty()) { |
| + return true; |
| + } |
| + std::vector<int> payload_types; |
| + for (const AudioCodec& codec : codecs) { |
| + payload_types.push_back(codec.id); |
| + } |
| + std::sort(payload_types.begin(), payload_types.end()); |
| + auto it = std::unique(payload_types.begin(), payload_types.end()); |
| + return it == payload_types.end(); |
| +} |
| + |
| bool IsNackEnabled(const AudioCodec& codec) { |
| return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack, |
| kParamValueEmpty)); |
| @@ -1461,14 +1486,39 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { |
| } |
| } |
| + if (!SetRecvOptions(voe_channel(), options)) { |
| + return false; |
| + } |
| + for (const auto& ch : receive_channels_) { |
| + if (!SetRecvOptions(ch.second->channel(), options)) { |
| + return false; |
| + } |
| + } |
| + if (dscp_option_changed) { |
| + rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT; |
| + if (options_.dscp.GetWithDefaultIfUnset(false)) |
| + dscp = kAudioDscpValue; |
| + if (MediaChannel::SetDscp(dscp) != 0) { |
| + LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; |
| + } |
| + } |
| + RecreateAudioReceiveStreams(); |
| + LOG(LS_INFO) << "Set voice channel options. Current options: " |
| + << options_.ToString(); |
| + return true; |
| +} |
| + |
| +bool WebRtcVoiceMediaChannel::SetRecvOptions(int channel_id, |
| + const AudioOptions& options) { |
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| // Receiver-side auto gain control happens per channel, so set it here from |
| - // options. Note that, like conference mode, setting it on the engine won't |
| - // have the desired effect, since voice channels don't inherit options from |
| - // the media engine when those options are applied per-channel. |
| + // options. Note that voice channels don't inherit options from the media |
| + // engine when those options are applied per-channel. |
| bool rx_auto_gain_control; |
| if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) { |
| if (engine()->voe()->processing()->SetRxAgcStatus( |
| - voe_channel(), rx_auto_gain_control, |
| + channel_id, rx_auto_gain_control, |
| webrtc::kAgcFixedDigital) == -1) { |
| LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control); |
| return false; |
| @@ -1487,9 +1537,9 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { |
| !options.rx_agc_digital_compression_gain.IsSet() || |
| !options.rx_agc_limiter.IsSet()) { |
| if (engine()->voe()->processing()->GetRxAgcConfig( |
| - voe_channel(), config) != 0) { |
| + channel_id, config) != 0) { |
| LOG(LS_ERROR) << "Failed to get default rx agc configuration for " |
| - << "channel " << voe_channel() << ". Since not all rx " |
| + << "channel " << channel_id << ". Since not all rx " |
| << "agc options are specified, unable to safely set rx " |
| << "agc options."; |
| return false; |
| @@ -1504,33 +1554,25 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { |
| config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset( |
| config.limiterEnable); |
| if (engine()->voe()->processing()->SetRxAgcConfig( |
| - voe_channel(), config) == -1) { |
| - LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv, |
| + channel_id, config) == -1) { |
| + LOG_RTCERR4(SetRxAgcConfig, channel_id, config.targetLeveldBOv, |
| config.digitalCompressionGaindB, config.limiterEnable); |
| return false; |
| } |
| } |
| - if (dscp_option_changed) { |
| - rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT; |
| - if (options_.dscp.GetWithDefaultIfUnset(false)) |
| - dscp = kAudioDscpValue; |
| - if (MediaChannel::SetDscp(dscp) != 0) { |
| - LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; |
| - } |
| - } |
| - |
| - RecreateAudioReceiveStreams(); |
| - |
| - LOG(LS_INFO) << "Set voice channel options. Current options: " |
| - << options_.ToString(); |
| return true; |
| } |
| bool WebRtcVoiceMediaChannel::SetRecvCodecs( |
| const std::vector<AudioCodec>& codecs) { |
| - RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| // Set the payload types to be used for incoming media. |
| - LOG(LS_INFO) << "Setting receive voice codecs:"; |
| + LOG(LS_INFO) << "Setting receive voice codecs."; |
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + if (!VerifyUniquePayloadTypes(codecs)) { |
| + LOG(LS_ERROR) << "Codec payload types overlap."; |
| + return false; |
| + } |
|
pthatcher1
2015/10/06 18:19:52
Can we add a unit test for this?
the sun
2015/10/07 10:50:25
There is one already: WebRtcVoiceEngineTestFake.Se
|
| std::vector<AudioCodec> new_codecs; |
| // Find all new codecs. We allow adding new codecs but don't allow changing |
| @@ -2228,17 +2270,18 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| LOG(LS_INFO) << "AddRecvStream: " << sp.ToString(); |
| - rtc::CritScope lock(&receive_channels_cs_); |
| - |
| - if (!VERIFY(sp.ssrcs.size() == 1)) |
| + if (!ValidateStreamParams(sp)) { |
| return false; |
| - uint32 ssrc = sp.first_ssrc(); |
| + } |
| + uint32 ssrc = sp.first_ssrc(); |
| if (ssrc == 0) { |
| - LOG(LS_WARNING) << "AddRecvStream with 0 ssrc is not supported."; |
| + LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported."; |
| return false; |
| } |
| + rtc::CritScope lock(&receive_channels_cs_); |
| + |
| if (receive_channels_.find(ssrc) != receive_channels_.end()) { |
| LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc; |
| return false; |
| @@ -2294,6 +2337,10 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { |
| return false; |
| } |
| + if (!SetRecvOptions(channel, options_)) { |
| + return false; |
| + } |
|
pthatcher1
2015/10/06 18:19:52
Can we add a unit test to cover that we are settin
|
| + |
| // Use the same SSRC as our default channel (so the RTCP reports are correct). |
| unsigned int send_ssrc = 0; |
| webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp(); |
| @@ -2663,16 +2710,19 @@ void WebRtcVoiceMediaChannel::OnRtcpReceived( |
| return; |
| } |
| - // If it is a sender report, find the channel that is listening. |
| + // If it is a sender report, find the receive channel that is listening. |
| bool has_sent_to_default_channel = false; |
| if (type == kRtcpTypeSR) { |
| - int which_channel = |
| - GetReceiveChannelId(ParseSsrc(packet->data(), packet->size(), true)); |
| - if (which_channel != -1) { |
| + uint32 ssrc = 0; |
| + if (!GetRtcpSsrc(packet->data(), packet->size(), &ssrc)) { |
| + return; |
| + } |
| + int recv_channel_id = GetReceiveChannelId(ssrc); |
| + if (recv_channel_id != -1) { |
| engine()->voe()->network()->ReceivedRTCPPacket( |
| - which_channel, packet->data(), packet->size()); |
| + recv_channel_id, packet->data(), packet->size()); |
| - if (IsDefaultChannel(which_channel)) |
| + if (IsDefaultChannel(recv_channel_id)) |
| has_sent_to_default_channel = true; |
| } |
| } |