Index: webrtc/media/engine/webrtcvoiceengine.cc |
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc |
index 2384ac28f173870959c97b6bc78224f931a03464..99ada087d422c920c7d103957388f325a68f838b 100644 |
--- a/webrtc/media/engine/webrtcvoiceengine.cc |
+++ b/webrtc/media/engine/webrtcvoiceengine.cc |
@@ -1515,20 +1515,10 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
RecreateAudioReceiveStream(); |
} |
- // Set a new payload type -> decoder map. The new map must be a superset of |
- // the old one. |
+ // Set a new payload type -> decoder map. |
void RecreateAudioReceiveStream( |
const std::map<int, webrtc::SdpAudioFormat>& decoder_map) { |
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
- RTC_DCHECK([&] { |
- for (const auto& item : config_.decoder_map) { |
- auto it = decoder_map.find(item.first); |
- if (it == decoder_map.end() || *it != item) { |
- return false; // The old map isn't a subset of the new map. |
- } |
- } |
- return true; |
- }()); |
config_.decoder_map = decoder_map; |
RecreateAudioReceiveStream(); |
} |
@@ -1851,44 +1841,51 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs( |
return false; |
} |
- std::vector<AudioCodec> new_codecs; |
- // Find all new codecs. We allow adding new codecs but don't allow changing |
- // the payload type of codecs that is already configured since we might |
- // already be receiving packets with that payload type. |
- for (const AudioCodec& codec : codecs) { |
- AudioCodec old_codec; |
- // TODO(solenberg): This isn't strictly correct. It should be possible to |
- // add an additional payload type for a codec. That would result in a new |
- // decoder object being allocated. What shouldn't work is to remove a PT |
- // mapping that was previously configured. |
- if (FindCodec(recv_codecs_, codec, &old_codec)) { |
- if (old_codec.id != codec.id) { |
- LOG(LS_ERROR) << codec.name << " payload type changed."; |
- return false; |
- } |
- } else { |
- new_codecs.push_back(codec); |
- } |
- } |
- if (new_codecs.empty()) { |
- // There are no new codecs to configure. Already configured codecs are |
- // never removed. |
- return true; |
- } |
- |
// Create a payload type -> SdpAudioFormat map with all the decoders. Fail |
// unless the factory claims to support all decoders. |
std::map<int, webrtc::SdpAudioFormat> decoder_map; |
for (const AudioCodec& codec : codecs) { |
+ // Log a warning if a codec's payload type is changing. This used to be |
+ // treated as an error. It's abnormal, but not really illegal. |
+ AudioCodec old_codec; |
+ if (FindCodec(recv_codecs_, codec, &old_codec) && |
+ old_codec.id != codec.id) { |
+ LOG(LS_WARNING) << codec.name << " mapped to a second payload type (" |
+ << codec.id << ", was already mapped to " << old_codec.id |
+ << ")"; |
+ } |
auto format = AudioCodecToSdpAudioFormat(codec); |
if (!IsCodec(codec, "cn") && !IsCodec(codec, "telephone-event") && |
!engine()->decoder_factory_->IsSupportedDecoder(format)) { |
LOG(LS_ERROR) << "Unsupported codec: " << format; |
return false; |
} |
+ // We allow adding new codecs but don't allow changing the payload type of |
+ // codecs that are already configured since we might already be receiving |
+ // packets with that payload type. See RFC3264, Section 8.3.2. |
+ // TODO(deadbeef): Also need to check for clashes with previously mapped |
+ // payload types, and not just currently mapped ones. For example, this |
+ // should be illegal: |
+ // 1. {100: opus/48000/2, 101: ISAC/16000} |
+ // 2. {100: opus/48000/2} |
+ // 3. {100: opus/48000/2, 101: ISAC/32000} |
+ // Though this check really should happen at a higher level, since this |
+ // conflict could happen between audio and video codecs. |
+ auto existing = decoder_map_.find(codec.id); |
+ if (existing != decoder_map_.end() && !existing->second.Matches(format)) { |
+ LOG(LS_ERROR) << "Attempting to use payload type " << codec.id << " for " |
+ << codec.name << ", but it is already used for " |
+ << existing->second.name; |
+ return false; |
+ } |
decoder_map.insert({codec.id, std::move(format)}); |
} |
+ if (decoder_map == decoder_map_) { |
+ // There's nothing new to configure. |
+ return true; |
+ } |
+ |
if (playout_) { |
// Receive codecs can not be changed while playing. So we temporarily |
// pause playout. |