Move codecs() to MediaContentDescription

allowing for a lot of de-templating

BUG=webrtc:15214

Change-Id: Ibe1a5f5d704564566f24c496822a4308ba23c4dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/319160
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40774}
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index ed2dfca..fe7093d 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -438,18 +438,9 @@
         continue;
       }
       const auto type = media_description->type();
-      if (type == cricket::MEDIA_TYPE_AUDIO) {
-        RTC_DCHECK(media_description->as_audio());
-        for (const auto& c : media_description->as_audio()->codecs()) {
-          auto error = FindDuplicateCodecParameters(
-              c.ToCodecParameters(), payload_to_codec_parameters);
-          if (!error.ok()) {
-            return error;
-          }
-        }
-      } else if (type == cricket::MEDIA_TYPE_VIDEO) {
-        RTC_DCHECK(media_description->as_video());
-        for (const auto& c : media_description->as_video()->codecs()) {
+      if (type == cricket::MEDIA_TYPE_AUDIO ||
+          type == cricket::MEDIA_TYPE_VIDEO) {
+        for (const auto& c : media_description->codecs()) {
           auto error = FindDuplicateCodecParameters(
               c.ToCodecParameters(), payload_to_codec_parameters);
           if (!error.ok()) {
diff --git a/pc/session_description.h b/pc/session_description.h
index 31992be..52e891e 100644
--- a/pc/session_description.h
+++ b/pc/session_description.h
@@ -83,8 +83,6 @@
     return nullptr;
   }
 
-  virtual bool has_codecs() const = 0;
-
   // Copy operator that returns an unique_ptr.
   // Not a virtual function.
   // If a type-specific variant of Clone() is desired, override it, or
@@ -234,54 +232,14 @@
     receive_rids_ = rids;
   }
 
- protected:
-  bool rtcp_mux_ = false;
-  bool rtcp_reduced_size_ = false;
-  bool remote_estimate_ = false;
-  int bandwidth_ = kAutoBandwidth;
-  std::string bandwidth_type_ = kApplicationSpecificBandwidth;
-  std::string protocol_;
-  std::vector<CryptoParams> cryptos_;
-  std::vector<webrtc::RtpExtension> rtp_header_extensions_;
-  bool rtp_header_extensions_set_ = false;
-  StreamParamsVec send_streams_;
-  bool conference_mode_ = false;
-  webrtc::RtpTransceiverDirection direction_ =
-      webrtc::RtpTransceiverDirection::kSendRecv;
-  rtc::SocketAddress connection_address_;
-  ExtmapAllowMixed extmap_allow_mixed_enum_ = kMedia;
-
-  SimulcastDescription simulcast_;
-  std::vector<RidDescription> receive_rids_;
-
- private:
-  // Copy function that returns a raw pointer. Caller will assert ownership.
-  // Should only be called by the Clone() function. Must be implemented
-  // by each final subclass.
-  virtual MediaContentDescription* CloneInternal() const = 0;
-};
-
-template <class C>
-class MediaContentDescriptionImpl : public MediaContentDescription {
- public:
-  void set_protocol(absl::string_view protocol) override {
-    RTC_DCHECK(IsRtpProtocol(protocol));
-    protocol_ = std::string(protocol);
-  }
-
   // Codecs should be in preference order (most preferred codec first).
   const std::vector<Codec>& codecs() const { return codecs_; }
   void set_codecs(const std::vector<Codec>& codecs) { codecs_ = codecs; }
-  bool has_codecs() const override { return !codecs_.empty(); }
+  virtual bool has_codecs() const { return !codecs_.empty(); }
   bool HasCodec(int id) {
-    bool found = false;
-    for (auto it = codecs_.begin(); it != codecs_.end(); ++it) {
-      if (it->id == id) {
-        found = true;
-        break;
-      }
-    }
-    return found;
+    return absl::c_find_if(codecs_, [id](const cricket::Codec codec) {
+             return codec.id == id;
+           }) != codecs_.end();
   }
   void AddCodec(const Codec& codec) { codecs_.push_back(codec); }
   void AddOrReplaceCodec(const Codec& codec) {
@@ -299,10 +257,48 @@
     }
   }
 
+ protected:
+  // TODO(bugs.webrtc.org/15214): move all RTP related things to a subclass that
+  // the SCTP content description does not inherit from.
+  std::string protocol_;
+
  private:
+  bool rtcp_mux_ = false;
+  bool rtcp_reduced_size_ = false;
+  bool remote_estimate_ = false;
+  int bandwidth_ = kAutoBandwidth;
+  std::string bandwidth_type_ = kApplicationSpecificBandwidth;
+
+  std::vector<CryptoParams> cryptos_;
+  std::vector<webrtc::RtpExtension> rtp_header_extensions_;
+  bool rtp_header_extensions_set_ = false;
+  StreamParamsVec send_streams_;
+  bool conference_mode_ = false;
+  webrtc::RtpTransceiverDirection direction_ =
+      webrtc::RtpTransceiverDirection::kSendRecv;
+  rtc::SocketAddress connection_address_;
+  ExtmapAllowMixed extmap_allow_mixed_enum_ = kMedia;
+
+  SimulcastDescription simulcast_;
+  std::vector<RidDescription> receive_rids_;
+
+  // Copy function that returns a raw pointer. Caller will assert ownership.
+  // Should only be called by the Clone() function. Must be implemented
+  // by each final subclass.
+  virtual MediaContentDescription* CloneInternal() const = 0;
+
   std::vector<Codec> codecs_;
 };
 
+template <class C>
+class MediaContentDescriptionImpl : public MediaContentDescription {
+ public:
+  void set_protocol(absl::string_view protocol) override {
+    RTC_DCHECK(IsRtpProtocol(protocol));
+    protocol_ = std::string(protocol);
+  }
+};
+
 class AudioContentDescription : public MediaContentDescriptionImpl<Codec> {
  public:
   AudioContentDescription() {}
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 9ed8ca6..80fef12 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -1438,17 +1438,11 @@
   // fmt is a list of payload type numbers that MAY be used in the session.
   std::string type;
   std::string fmt;
-  if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    type = kMediaTypeVideo;
-    const VideoContentDescription* video_desc = media_desc->as_video();
-    for (const cricket::VideoCodec& codec : video_desc->codecs()) {
-      fmt.append(" ");
-      fmt.append(rtc::ToString(codec.id));
-    }
-  } else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
-    type = kMediaTypeAudio;
-    const AudioContentDescription* audio_desc = media_desc->as_audio();
-    for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
+  if (media_type == cricket::MEDIA_TYPE_AUDIO ||
+      media_type == cricket::MEDIA_TYPE_VIDEO) {
+    type = media_type == cricket::MEDIA_TYPE_AUDIO ? kMediaTypeAudio
+                                                   : kMediaTypeVideo;
+    for (const cricket::VideoCodec& codec : media_desc->codecs()) {
       fmt.append(" ");
       fmt.append(rtc::ToString(codec.id));
     }
@@ -1867,8 +1861,7 @@
   return !empty;
 }
 
-template <class T>
-void AddFmtpLine(const T& codec, std::string* message) {
+void AddFmtpLine(const cricket::Codec& codec, std::string* message) {
   rtc::StringBuilder os;
   WriteFmtpHeader(codec.id, &os);
   os << kSdpDelimiterSpace;
@@ -1879,8 +1872,7 @@
   return;
 }
 
-template <class T>
-void AddPacketizationLine(const T& codec, std::string* message) {
+void AddPacketizationLine(const cricket::Codec& codec, std::string* message) {
   if (!codec.packetization) {
     return;
   }
@@ -1890,8 +1882,7 @@
   AddLine(os.str(), message);
 }
 
-template <class T>
-void AddRtcpFbLines(const T& codec, std::string* message) {
+void AddRtcpFbLines(const cricket::Codec& codec, std::string* message) {
   for (const cricket::FeedbackParam& param : codec.feedback_params.params()) {
     rtc::StringBuilder os;
     WriteRtcpFbHeader(codec.id, &os);
@@ -1932,7 +1923,7 @@
   RTC_DCHECK(media_desc != NULL);
   rtc::StringBuilder os;
   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    for (const cricket::VideoCodec& codec : media_desc->as_video()->codecs()) {
+    for (const cricket::Codec& codec : media_desc->codecs()) {
       // RFC 4566
       // a=rtpmap:<payload type> <encoding name>/<clock rate>
       // [/<encodingparameters>]
@@ -1950,7 +1941,7 @@
     std::vector<int> ptimes;
     std::vector<int> maxptimes;
     int max_minptime = 0;
-    for (const cricket::AudioCodec& codec : media_desc->as_audio()->codecs()) {
+    for (const cricket::Codec& codec : media_desc->codecs()) {
       RTC_DCHECK(!codec.name.empty());
       // RFC 4566
       // a=rtpmap:<payload type> <encoding name>/<clock rate>
@@ -2857,21 +2848,6 @@
   return true;
 }
 
-bool VerifyCodec(const cricket::Codec& codec) {
-  // Codec has not been populated correctly unless the name has been set. This
-  // can happen if an SDP has an fmtp or rtcp-fb with a payload type but doesn't
-  // have a corresponding "rtpmap" line.
-  return !codec.name.empty();
-}
-
-bool VerifyAudioCodecs(const AudioContentDescription* audio_desc) {
-  return absl::c_all_of(audio_desc->codecs(), &VerifyCodec);
-}
-
-bool VerifyVideoCodecs(const VideoContentDescription* video_desc) {
-  return absl::c_all_of(video_desc->codecs(), &VerifyCodec);
-}
-
 void AddParameters(const cricket::CodecParameterMap& parameters,
                    cricket::Codec* codec) {
   for (const auto& entry : parameters) {
@@ -2896,11 +2872,11 @@
 // Gets the current codec setting associated with `payload_type`. If there
 // is no Codec associated with that payload type it returns an empty codec
 // with that payload type.
-template <class T>
-T GetCodecWithPayloadType(cricket::MediaType type,
-                          const std::vector<T>& codecs,
-                          int payload_type) {
-  const T* codec = FindCodecById(codecs, payload_type);
+cricket::Codec GetCodecWithPayloadType(
+    cricket::MediaType type,
+    const std::vector<cricket::Codec>& codecs,
+    int payload_type) {
+  const cricket::Codec* codec = FindCodecById(codecs, payload_type);
   if (codec)
     return *codec;
   // Return empty codec with `payload_type`.
@@ -2912,12 +2888,11 @@
 }
 
 // Updates or creates a new codec entry in the media description.
-template <class T, class U>
-void AddOrReplaceCodec(MediaContentDescription* content_desc, const U& codec) {
-  T* desc = static_cast<T*>(content_desc);
-  std::vector<U> codecs = desc->codecs();
+void AddOrReplaceCodec(MediaContentDescription* content_desc,
+                       const cricket::Codec& codec) {
+  std::vector<cricket::Codec> codecs = content_desc->codecs();
   bool found = false;
-  for (U& existing_codec : codecs) {
+  for (cricket::Codec& existing_codec : codecs) {
     if (codec.id == existing_codec.id) {
       // Overwrite existing codec with the new codec.
       existing_codec = codec;
@@ -2926,38 +2901,34 @@
     }
   }
   if (!found) {
-    desc->AddCodec(codec);
+    content_desc->AddCodec(codec);
     return;
   }
-  desc->set_codecs(codecs);
+  content_desc->set_codecs(codecs);
 }
 
 // Adds or updates existing codec corresponding to `payload_type` according
 // to `parameters`.
-template <class T, class U>
 void UpdateCodec(MediaContentDescription* content_desc,
                  int payload_type,
                  const cricket::CodecParameterMap& parameters) {
   // Codec might already have been populated (from rtpmap).
-  U new_codec = GetCodecWithPayloadType(content_desc->type(),
-                                        static_cast<T*>(content_desc)->codecs(),
-                                        payload_type);
+  cricket::Codec new_codec = GetCodecWithPayloadType(
+      content_desc->type(), content_desc->codecs(), payload_type);
   AddParameters(parameters, &new_codec);
-  AddOrReplaceCodec<T, U>(content_desc, new_codec);
+  AddOrReplaceCodec(content_desc, new_codec);
 }
 
 // Adds or updates existing codec corresponding to `payload_type` according
 // to `feedback_param`.
-template <class T, class U>
 void UpdateCodec(MediaContentDescription* content_desc,
                  int payload_type,
                  const cricket::FeedbackParam& feedback_param) {
   // Codec might already have been populated (from rtpmap).
-  U new_codec = GetCodecWithPayloadType(content_desc->type(),
-                                        static_cast<T*>(content_desc)->codecs(),
-                                        payload_type);
+  cricket::Codec new_codec = GetCodecWithPayloadType(
+      content_desc->type(), content_desc->codecs(), payload_type);
   AddFeedbackParameter(feedback_param, &new_codec);
-  AddOrReplaceCodec<T, U>(content_desc, new_codec);
+  AddOrReplaceCodec(content_desc, new_codec);
 }
 
 // Adds or updates existing video codec corresponding to `payload_type`
@@ -2974,15 +2945,15 @@
   cricket::VideoCodec codec = GetCodecWithPayloadType(
       video_desc->type(), video_desc->codecs(), payload_type);
   codec.packetization = std::string(packetization);
-  AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc,
-                                                                  codec);
+  AddOrReplaceCodec(video_desc, codec);
 }
 
-template <class T>
-absl::optional<T> PopWildcardCodec(std::vector<T>* codecs) {
+absl::optional<cricket::Codec> PopWildcardCodec(
+    std::vector<cricket::Codec>* codecs) {
+  RTC_DCHECK(codecs);
   for (auto iter = codecs->begin(); iter != codecs->end(); ++iter) {
     if (iter->id == kWildcardPayloadType) {
-      T wildcard_codec = *iter;
+      cricket::Codec wildcard_codec = *iter;
       codecs->erase(iter);
       return wildcard_codec;
     }
@@ -2990,10 +2961,10 @@
   return absl::nullopt;
 }
 
-template <class T>
-void UpdateFromWildcardCodecs(cricket::MediaContentDescriptionImpl<T>* desc) {
+void UpdateFromWildcardCodecs(cricket::MediaContentDescription* desc) {
+  RTC_DCHECK(desc);
   auto codecs = desc->codecs();
-  absl::optional<T> wildcard_codec = PopWildcardCodec(&codecs);
+  absl::optional<cricket::Codec> wildcard_codec = PopWildcardCodec(&codecs);
   if (!wildcard_codec) {
     return;
   }
@@ -3006,6 +2977,7 @@
 void AddAudioAttribute(const std::string& name,
                        absl::string_view value,
                        AudioContentDescription* audio_desc) {
+  RTC_DCHECK(audio_desc);
   if (value.empty()) {
     return;
   }
@@ -3415,27 +3387,20 @@
     media_desc->AddStream(track);
   }
 
-  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
-    AudioContentDescription* audio_desc = media_desc->as_audio();
-    UpdateFromWildcardCodecs(audio_desc);
-
-    // Verify audio codec ensures that no audio codec has been populated with
-    // only fmtp.
-    if (!VerifyAudioCodecs(audio_desc)) {
-      return ParseFailed("Failed to parse audio codecs correctly.", error);
-    }
-    AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, audio_desc);
-    AddAudioAttribute(kCodecParamPTime, ptime_as_string, audio_desc);
+  UpdateFromWildcardCodecs(media_desc);
+  // Codec has not been populated correctly unless the name has been set. This
+  // can happen if an SDP has an fmtp or rtcp-fb with a payload type but doesn't
+  // have a corresponding "rtpmap" line. This should lead to a parse error.
+  if (!absl::c_all_of(media_desc->codecs(), [](const cricket::Codec codec) {
+        return !codec.name.empty();
+      })) {
+    return ParseFailed("Failed to parse codecs correctly.", error);
   }
-
-  if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    VideoContentDescription* video_desc = media_desc->as_video();
-    UpdateFromWildcardCodecs(video_desc);
-    // Verify video codec ensures that no video codec has been populated with
-    // only rtcp-fb.
-    if (!VerifyVideoCodecs(video_desc)) {
-      return ParseFailed("Failed to parse video codecs correctly.", error);
-    }
+  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+    AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string,
+                      media_desc->as_audio());
+    AddAudioAttribute(kCodecParamPTime, ptime_as_string,
+                      media_desc->as_audio());
   }
 
   // RFC 5245
@@ -3601,14 +3566,13 @@
                  AudioContentDescription* audio_desc) {
   // Codec may already be populated with (only) optional parameters
   // (from an fmtp).
-  cricket::AudioCodec codec = GetCodecWithPayloadType(
+  cricket::Codec codec = GetCodecWithPayloadType(
       audio_desc->type(), audio_desc->codecs(), payload_type);
   codec.name = std::string(name);
   codec.clockrate = clockrate;
   codec.bitrate = bitrate;
   codec.channels = channels;
-  AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc,
-                                                                  codec);
+  AddOrReplaceCodec(audio_desc, codec);
 }
 
 // Updates or creates a new codec entry in the video description according to
@@ -3618,11 +3582,10 @@
                  VideoContentDescription* video_desc) {
   // Codec may already be populated with (only) optional parameters
   // (from an fmtp).
-  cricket::VideoCodec codec = GetCodecWithPayloadType(
+  cricket::Codec codec = GetCodecWithPayloadType(
       video_desc->type(), video_desc->codecs(), payload_type);
   codec.name = std::string(name);
-  AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc,
-                                                                  codec);
+  AddOrReplaceCodec(video_desc, codec);
 }
 
 bool ParseRtpmapAttribute(absl::string_view line,
@@ -3671,8 +3634,7 @@
   }
 
   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    VideoContentDescription* video_desc = media_desc->as_video();
-    for (const cricket::VideoCodec& existing_codec : video_desc->codecs()) {
+    for (const cricket::VideoCodec& existing_codec : media_desc->codecs()) {
       if (!existing_codec.name.empty() && payload_type == existing_codec.id &&
           (!absl::EqualsIgnoreCase(encoding_name, existing_codec.name) ||
            clock_rate != existing_codec.clockrate)) {
@@ -3686,7 +3648,7 @@
         return ParseFailed(line, description.Release(), error);
       }
     }
-    UpdateCodec(payload_type, encoding_name, video_desc);
+    UpdateCodec(payload_type, encoding_name, media_desc->as_video());
   } else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
     // RFC 4566
     // For audio streams, <encoding parameters> indicates the number
@@ -3703,8 +3665,7 @@
       return ParseFailed(line, "At most 24 channels are supported.", error);
     }
 
-    AudioContentDescription* audio_desc = media_desc->as_audio();
-    for (const cricket::AudioCodec& existing_codec : audio_desc->codecs()) {
+    for (const cricket::AudioCodec& existing_codec : media_desc->codecs()) {
       // TODO(crbug.com/1338902) re-add checks for clockrate and number of
       // channels.
       if (!existing_codec.name.empty() && payload_type == existing_codec.id &&
@@ -3720,7 +3681,7 @@
       }
     }
     UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels,
-                audio_desc);
+                media_desc->as_audio());
   }
   return true;
 }
@@ -3791,12 +3752,9 @@
     codec_params[name] = value;
   }
 
-  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
-    UpdateCodec<AudioContentDescription, cricket::AudioCodec>(
-        media_desc, payload_type, codec_params);
-  } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    UpdateCodec<VideoContentDescription, cricket::VideoCodec>(
-        media_desc, payload_type, codec_params);
+  if (media_type == cricket::MEDIA_TYPE_AUDIO ||
+      media_type == cricket::MEDIA_TYPE_VIDEO) {
+    UpdateCodec(media_desc, payload_type, codec_params);
   }
   return true;
 }
@@ -3862,12 +3820,9 @@
   }
   const cricket::FeedbackParam feedback_param(id, param);
 
-  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
-    UpdateCodec<AudioContentDescription, cricket::AudioCodec>(
-        media_desc, payload_type, feedback_param);
-  } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-    UpdateCodec<VideoContentDescription, cricket::VideoCodec>(
-        media_desc, payload_type, feedback_param);
+  if (media_type == cricket::MEDIA_TYPE_AUDIO ||
+      media_type == cricket::MEDIA_TYPE_VIDEO) {
+    UpdateCodec(media_desc, payload_type, feedback_param);
   }
   return true;
 }