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; |
} |
} |