Adding C++ versions of currently spec'd "RtpParameters" structs.

These structs will be used for ORTC objects (and their WebRTC
equivalents).

This CL also introduces some minor changes to the existing implemented
structs:

- max_bitrate_bps uses rtc::Optional instead of "-1 means unset"
- "mime_type" turned into "name"/"kind" (which can be used to form the
  MIME type string, if needed).
- clock_rate and channels changed to rtc::Optional, since they will
  need to be for RtpSender.send().
- Renamed "channels" to "num_channels" (the ORTC name, which I prefer).

BUG=webrtc:7013, webrtc:7112

Review-Url: https://codereview.webrtc.org/2651883010
Cr-Commit-Position: refs/heads/master@{#16437}
diff --git a/webrtc/api/rtpparameters.h b/webrtc/api/rtpparameters.h
index 13704dc..f506c40 100644
--- a/webrtc/api/rtpparameters.h
+++ b/webrtc/api/rtpparameters.h
@@ -12,22 +12,297 @@
 #define WEBRTC_API_RTPPARAMETERS_H_
 
 #include <string>
+#include <unordered_map>
 #include <vector>
 
+#include "webrtc/api/mediatypes.h"
 #include "webrtc/base/optional.h"
 
 namespace webrtc {
 
-// These structures are defined as part of the RtpSender interface.
-// See http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface for details.
-struct RtpEncodingParameters {
+// These structures are intended to mirror those defined by:
+// http://draft.ortc.org/#rtcrtpdictionaries*
+// Contains everything specified as of 2017 Jan 24.
+//
+// They are used when retrieving or modifying the parameters of an
+// RtpSender/RtpReceiver, or retrieving capabilities.
+//
+// Note on conventions: Where ORTC may use "octet", "short" and "unsigned"
+// types, we typically use "int", in keeping with our style guidelines. The
+// parameter's actual valid range will be enforced when the parameters are set,
+// rather than when the parameters struct is built. An exception is made for
+// SSRCs, since they use the full unsigned 32-bit range, and aren't expected to
+// be used for any numeric comparisons/operations.
+//
+// Additionally, where ORTC uses strings, we may use enums for things that have
+// a fixed number of supported values. However, for things that can be extended
+// (such as codecs, by providing an external encoder factory), a string
+// identifier is used.
+
+enum class FecMechanism {
+  RED,
+  RED_AND_ULPFEC,
+  FLEXFEC,
+};
+
+// Used in RtcpFeedback struct.
+enum class RtcpFeedbackType {
+  ACK,
+  CCM,
+  NACK,
+  REMB,  // "goog-remb"
+  TRANSPORT_CC,
+};
+
+// Used in RtcpFeedback struct when type is ACK, NACK or CCM.
+enum class RtcpFeedbackMessageType {
+  // Equivalent to {type: "nack", parameter: undefined} in ORTC.
+  GENERIC_NACK,
+  PLI,  // Usable with NACK.
+  FIR,  // Usable with CCM.
+};
+
+enum class DtxStatus {
+  DISABLED,
+  ENABLED,
+};
+
+enum class DegradationPreference {
+  MAINTAIN_FRAMERATE,
+  MAINTAIN_RESOLUTION,
+  BALANCED,
+};
+
+enum class PriorityType { VERY_LOW, LOW, MEDIUM, HIGH };
+
+struct RtcpFeedback {
+  RtcpFeedbackType type = RtcpFeedbackType::ACK;
+
+  // Equivalent to ORTC "parameter" field with slight differences:
+  // 1. It's an enum instead of a string.
+  // 2. Generic NACK feedback is represented by a GENERIC_NACK message type,
+  //    rather than an unset "parameter" value.
+  rtc::Optional<RtcpFeedbackMessageType> message_type;
+
+  bool operator==(const RtcpFeedback& o) const {
+    return type == o.type && message_type == o.message_type;
+  }
+  bool operator!=(const RtcpFeedback& o) const { return !(*this == o); }
+};
+
+// RtpCodecCapability is to RtpCodecParameters as RtpCapabilities is to
+// RtpParameters. This represents the static capabilities of an endpoint's
+// implementation of a codec.
+struct RtpCodecCapability {
+  // Build MIME "type/subtype" string from |name| and |kind|.
+  std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; }
+
+  // Used to identify the codec. Equivalent to MIME subtype.
+  std::string name;
+
+  // The media type of this codec. Equivalent to MIME top-level type.
+  cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO;
+
+  // Clock rate in Hertz. If unset, the codec is applicable to any clock rate.
+  rtc::Optional<int> clock_rate;
+
+  // Default payload type for this codec. Mainly needed for codecs that use
+  // that have statically assigned payload types.
+  rtc::Optional<int> preferred_payload_type;
+
+  // Maximum packetization time supported by an RtpReceiver for this codec.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> max_ptime;
+
+  // Preferred packetization time for an RtpReceiver or RtpSender of this
+  // codec.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> ptime;
+
+  // The number of audio channels supported. Unused for video codecs.
+  rtc::Optional<int> num_channels;
+
+  // Feedback mechanisms supported for this codec.
+  std::vector<RtcpFeedback> rtcp_feedback;
+
+  // Codec-specific parameters that must be signaled to the remote party.
+  // Corresponds to "a=fmtp" parameters in SDP.
+  std::unordered_map<std::string, std::string> parameters;
+
+  // Codec-specific parameters that may optionally be signaled to the remote
+  // party.
+  // TODO(deadbeef): Not implemented.
+  std::unordered_map<std::string, std::string> options;
+
+  // Maximum number of temporal layer extensions supported by this codec.
+  // For example, a value of 1 indicates that 2 total layers are supported.
+  // TODO(deadbeef): Not implemented.
+  int max_temporal_layer_extensions = 0;
+
+  // Maximum number of spatial layer extensions supported by this codec.
+  // For example, a value of 1 indicates that 2 total layers are supported.
+  // TODO(deadbeef): Not implemented.
+  int max_spatial_layer_extensions = 0;
+
+  // Whether the implementation can send/receive SVC layers with distinct
+  // SSRCs. Always false for audio codecs. True for video codecs that support
+  // scalable video coding with MRST.
+  // TODO(deadbeef): Not implemented.
+  bool svc_multi_stream_support = false;
+
+  bool operator==(const RtpCodecCapability& o) const {
+    return name == o.name && kind == o.kind && clock_rate == o.clock_rate &&
+           preferred_payload_type == o.preferred_payload_type &&
+           max_ptime == o.max_ptime && ptime == o.ptime &&
+           num_channels == o.num_channels && rtcp_feedback == o.rtcp_feedback &&
+           parameters == o.parameters && options == o.options &&
+           max_temporal_layer_extensions == o.max_temporal_layer_extensions &&
+           max_spatial_layer_extensions == o.max_spatial_layer_extensions &&
+           svc_multi_stream_support == o.svc_multi_stream_support;
+  }
+  bool operator!=(const RtpCodecCapability& o) const { return !(*this == o); }
+};
+
+// Used in RtpCapabilities; represents the capabilities/preferences of an
+// implementation for a header extension.
+//
+// Just called "RtpHeaderExtension" in ORTC, but the "Capability" suffix was
+// added here for consistency and to avoid confusion with
+// RtpHeaderExtensionParameters.
+//
+// Note that ORTC includes a "kind" field, but we omit this because it's
+// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)",
+// you know you're getting audio capabilities.
+struct RtpHeaderExtensionCapability {
+  // URI of this extension, as defined in RFC5285.
+  std::string uri;
+
+  // Preferred value of ID that goes in the packet.
+  rtc::Optional<int> preferred_id;
+
+  // If true, it's preferred that the value in the header is encrypted.
+  // TODO(deadbeef): Not implemented.
+  bool preferred_encrypt = false;
+
+  bool operator==(const RtpHeaderExtensionCapability& o) const {
+    return uri == o.uri && preferred_id == o.preferred_id &&
+           preferred_encrypt == o.preferred_encrypt;
+  }
+  bool operator!=(const RtpHeaderExtensionCapability& o) const {
+    return !(*this == o);
+  }
+};
+
+// Used in RtpParameters; represents a specific configuration of a header
+// extension.
+struct RtpHeaderExtensionParameters {
+  // URI of this extension, as defined in RFC5285.
+  std::string uri;
+
+  // ID value that goes in the packet.
+  int id = 0;
+
+  // If true, the value in the header is encrypted.
+  // TODO(deadbeef): Not implemented.
+  bool encrypt = false;
+
+  bool operator==(const RtpHeaderExtensionParameters& o) const {
+    return uri == o.uri && id == o.id && encrypt == o.encrypt;
+  }
+  bool operator!=(const RtpHeaderExtensionParameters& o) const {
+    return !(*this == o);
+  }
+};
+
+struct RtpFecParameters {
+  // If unset, a value is chosen by the implementation.
   rtc::Optional<uint32_t> ssrc;
+
+  FecMechanism mechanism = FecMechanism::RED;
+
+  bool operator==(const RtpFecParameters& o) const {
+    return ssrc == o.ssrc && mechanism == o.mechanism;
+  }
+  bool operator!=(const RtpFecParameters& o) const { return !(*this == o); }
+};
+
+struct RtpRtxParameters {
+  // If unset, a value is chosen by the implementation.
+  rtc::Optional<uint32_t> ssrc;
+
+  bool operator==(const RtpRtxParameters& o) const { return ssrc == o.ssrc; }
+  bool operator!=(const RtpRtxParameters& o) const { return !(*this == o); }
+};
+
+struct RtpEncodingParameters {
+  // If unset, a value is chosen by the implementation.
+  rtc::Optional<uint32_t> ssrc;
+
+  // Can be used to reference a codec in the |codecs| member of the
+  // RtpParameters that contains this RtpEncodingParameters. If unset, the
+  // implementation will choose the first possible codec.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> codec_payload_type;
+
+  // Specifies the FEC mechanism, if set.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<RtpFecParameters> fec;
+
+  // Specifies the RTX parameters, if set.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<RtpRtxParameters> rtx;
+
+  // Only used for audio. If set, determines whether or not discontinuous
+  // transmission will be used, if an available codec supports it. If not
+  // set, the implementation default setting will be used.
+  rtc::Optional<DtxStatus> dtx;
+
+  // The relative priority of this encoding.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<PriorityType> priority;
+
+  // If set, this represents the Transport Independent Application Specific
+  // maximum bandwidth defined in RFC3890. If unset, there is no maximum
+  // bitrate.
+  // Just called "maxBitrate" in ORTC spec.
+  rtc::Optional<int> max_bitrate_bps;
+
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> max_framerate;
+
+  // For video, scale the resolution down by this factor.
+  // TODO(deadbeef): Not implemented.
+  double scale_resolution_down_by = 1.0;
+
+  // Scale the framerate down by this factor.
+  // TODO(deadbeef): Not implemented.
+  double scale_framerate_down_by = 1.0;
+
+  // For an RtpSender, set to true to cause this encoding to be sent, and false
+  // for it not to be sent. For an RtpReceiver, set to true to cause the
+  // encoding to be decoded, and false for it to be ignored.
+  // TODO(deadbeef): RtpReceiver part is not implemented.
   bool active = true;
-  int max_bitrate_bps = -1;
+
+  // Value to use for RID RTP header extension.
+  // Called "encodingId" in ORTC.
+  // TODO(deadbeef): Not implemented.
+  std::string rid;
+
+  // RIDs of encodings on which this layer depends.
+  // Called "dependencyEncodingIds" in ORTC spec.
+  // TODO(deadbeef): Not implemented.
+  std::vector<std::string> dependency_rids;
 
   bool operator==(const RtpEncodingParameters& o) const {
-    return ssrc == o.ssrc && active == o.active &&
-           max_bitrate_bps == o.max_bitrate_bps;
+    return ssrc == o.ssrc && codec_payload_type == o.codec_payload_type &&
+           fec == o.fec && rtx == o.rtx && dtx == o.dtx &&
+           priority == o.priority && max_bitrate_bps == o.max_bitrate_bps &&
+           max_framerate == o.max_framerate &&
+           scale_resolution_down_by == o.scale_resolution_down_by &&
+           scale_framerate_down_by == o.scale_framerate_down_by &&
+           active == o.active && rid == o.rid &&
+           dependency_rids == o.dependency_rids;
   }
   bool operator!=(const RtpEncodingParameters& o) const {
     return !(*this == o);
@@ -35,25 +310,107 @@
 };
 
 struct RtpCodecParameters {
-  int payload_type;
-  std::string mime_type;
-  int clock_rate;
-  int channels = 1;
-  // TODO(deadbeef): Add sdpFmtpLine field.
+  // Build MIME "type/subtype" string from |name| and |kind|.
+  std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; }
+
+  // Used to identify the codec. Equivalent to MIME subtype.
+  std::string name;
+
+  // The media type of this codec. Equivalent to MIME top-level type.
+  cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO;
+
+  // Payload type used to identify this codec in RTP packets.
+  // This MUST always be present, and must be unique across all codecs using
+  // the same transport.
+  int payload_type = 0;
+
+  // If unset, the implementation default is used.
+  rtc::Optional<int> clock_rate;
+
+  // The number of audio channels used. Unset for video codecs. If unset for
+  // audio, the implementation default is used.
+  // TODO(deadbeef): The "implementation default" part is unimplemented.
+  rtc::Optional<int> num_channels;
+
+  // The maximum packetization time to be used by an RtpSender.
+  // If |ptime| is also set, this will be ignored.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> max_ptime;
+
+  // The packetization time to be used by an RtpSender.
+  // If unset, will use any time up to max_ptime.
+  // TODO(deadbeef): Not implemented.
+  rtc::Optional<int> ptime;
+
+  // Feedback mechanisms to be used for this codec.
+  // TODO(deadbeef): Not implemented.
+  std::vector<RtcpFeedback> rtcp_feedback;
+
+  // Codec-specific parameters that must be signaled to the remote party.
+  // Corresponds to "a=fmtp" parameters in SDP.
+  // TODO(deadbeef): Not implemented.
+  std::unordered_map<std::string, std::string> parameters;
 
   bool operator==(const RtpCodecParameters& o) const {
-    return payload_type == o.payload_type && mime_type == o.mime_type &&
-           clock_rate == o.clock_rate && channels == o.channels;
+    return name == o.name && kind == o.kind && payload_type == o.payload_type &&
+           clock_rate == o.clock_rate && num_channels == o.num_channels &&
+           max_ptime == o.max_ptime && ptime == o.ptime &&
+           rtcp_feedback == o.rtcp_feedback && parameters == o.parameters;
   }
   bool operator!=(const RtpCodecParameters& o) const { return !(*this == o); }
 };
 
+// RtpCapabilities is used to represent the static capabilities of an
+// endpoint. An application can use these capabilities to construct an
+// RtpParameters.
+struct RtpCapabilities {
+  // Supported codecs.
+  std::vector<RtpCodecCapability> codecs;
+
+  // Supported RTP header extensions.
+  std::vector<RtpHeaderExtensionCapability> header_extensions;
+
+  // Supported Forward Error Correction (FEC) mechanisms.
+  std::vector<FecMechanism> fec;
+
+  bool operator==(const RtpCapabilities& o) const {
+    return codecs == o.codecs && header_extensions == o.header_extensions &&
+           fec == o.fec;
+  }
+  bool operator!=(const RtpCapabilities& o) const { return !(*this == o); }
+};
+
+// Note that unlike in ORTC, an RtcpParameters is not included in
+// RtpParameters, because our API will include an additional "RtpTransport"
+// abstraction on which RTCP parameters are set.
 struct RtpParameters {
-  std::vector<RtpEncodingParameters> encodings;
+  // Used when calling getParameters/setParameters with a PeerConnection
+  // RtpSender, to ensure that outdated parameters are not unintentionally
+  // applied successfully.
+  // TODO(deadbeef): Not implemented.
+  std::string transaction_id;
+
+  // Value to use for MID RTP header extension.
+  // Called "muxId" in ORTC.
+  // TODO(deadbeef): Not implemented.
+  std::string mid;
+
   std::vector<RtpCodecParameters> codecs;
 
+  // TODO(deadbeef): Not implemented.
+  std::vector<RtpHeaderExtensionParameters> header_extensions;
+
+  std::vector<RtpEncodingParameters> encodings;
+
+  // TODO(deadbeef): Not implemented.
+  DegradationPreference degradation_preference =
+      DegradationPreference::BALANCED;
+
   bool operator==(const RtpParameters& o) const {
-    return encodings == o.encodings && codecs == o.codecs;
+    return mid == o.mid && codecs == o.codecs &&
+           header_extensions == o.header_extensions &&
+           encodings == o.encodings &&
+           degradation_preference == o.degradation_preference;
   }
   bool operator!=(const RtpParameters& o) const { return !(*this == o); }
 };
diff --git a/webrtc/media/base/codec.cc b/webrtc/media/base/codec.cc
index 75e5a7b..1e305a6 100644
--- a/webrtc/media/base/codec.cc
+++ b/webrtc/media/base/codec.cc
@@ -149,8 +149,8 @@
 webrtc::RtpCodecParameters Codec::ToCodecParameters() const {
   webrtc::RtpCodecParameters codec_params;
   codec_params.payload_type = id;
-  codec_params.mime_type = name;
-  codec_params.clock_rate = clockrate;
+  codec_params.name = name;
+  codec_params.clock_rate = rtc::Optional<int>(clockrate);
   return codec_params;
 }
 
@@ -190,12 +190,6 @@
       ((codec.channels < 2 && channels < 2) || channels == codec.channels);
 }
 
-webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const {
-  webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters();
-  codec_params.channels = static_cast<int>(channels);
-  return codec_params;
-}
-
 std::string AudioCodec::ToString() const {
   std::ostringstream os;
   os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
@@ -203,12 +197,25 @@
   return os.str();
 }
 
+webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const {
+  webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters();
+  codec_params.num_channels = rtc::Optional<int>(static_cast<int>(channels));
+  codec_params.kind = MEDIA_TYPE_AUDIO;
+  return codec_params;
+}
+
 std::string VideoCodec::ToString() const {
   std::ostringstream os;
   os << "VideoCodec[" << id << ":" << name << "]";
   return os.str();
 }
 
+webrtc::RtpCodecParameters VideoCodec::ToCodecParameters() const {
+  webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters();
+  codec_params.kind = MEDIA_TYPE_VIDEO;
+  return codec_params;
+}
+
 VideoCodec::VideoCodec(int id, const std::string& name)
     : Codec(id, name, kVideoCodecClockrate) {
   SetDefaultParameters();
diff --git a/webrtc/media/base/codec.h b/webrtc/media/base/codec.h
index ac85d1f..7dd8889 100644
--- a/webrtc/media/base/codec.h
+++ b/webrtc/media/base/codec.h
@@ -162,6 +162,8 @@
 
   std::string ToString() const;
 
+  webrtc::RtpCodecParameters ToCodecParameters() const override;
+
   VideoCodec& operator=(const VideoCodec& c);
   VideoCodec& operator=(VideoCodec&& c);
 
diff --git a/webrtc/media/base/codec_unittest.cc b/webrtc/media/base/codec_unittest.cc
index 77c1fd0..5a375fc 100644
--- a/webrtc/media/base/codec_unittest.cc
+++ b/webrtc/media/base/codec_unittest.cc
@@ -311,14 +311,17 @@
   const VideoCodec v(96, "V");
   webrtc::RtpCodecParameters codec_params_1 = v.ToCodecParameters();
   EXPECT_EQ(96, codec_params_1.payload_type);
-  EXPECT_EQ("V", codec_params_1.mime_type);
-  EXPECT_EQ(cricket::kVideoCodecClockrate, codec_params_1.clock_rate);
-  EXPECT_EQ(1, codec_params_1.channels);
+  EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, codec_params_1.kind);
+  EXPECT_EQ("V", codec_params_1.name);
+  EXPECT_EQ(rtc::Optional<int>(cricket::kVideoCodecClockrate),
+            codec_params_1.clock_rate);
+  EXPECT_EQ(rtc::Optional<int>(), codec_params_1.num_channels);
 
   const AudioCodec a(97, "A", 44100, 20000, 2);
   webrtc::RtpCodecParameters codec_params_2 = a.ToCodecParameters();
   EXPECT_EQ(97, codec_params_2.payload_type);
-  EXPECT_EQ("A", codec_params_2.mime_type);
-  EXPECT_EQ(44100, codec_params_2.clock_rate);
-  EXPECT_EQ(2, codec_params_2.channels);
+  EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, codec_params_2.kind);
+  EXPECT_EQ("A", codec_params_2.name);
+  EXPECT_EQ(rtc::Optional<int>(44100), codec_params_2.clock_rate);
+  EXPECT_EQ(rtc::Optional<int>(2), codec_params_2.num_channels);
 }
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index c6c522a..955560a 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -1861,9 +1861,12 @@
     encoder_config.number_of_streams = 1;
   }
 
-  int stream_max_bitrate =
-      MinPositive(rtp_parameters_.encodings[0].max_bitrate_bps,
-                  parameters_.max_bitrate_bps);
+  int stream_max_bitrate = parameters_.max_bitrate_bps;
+  if (rtp_parameters_.encodings[0].max_bitrate_bps) {
+    stream_max_bitrate =
+        MinPositive(*(rtp_parameters_.encodings[0].max_bitrate_bps),
+                    parameters_.max_bitrate_bps);
+  }
 
   int codec_max_bitrate_kbps;
   if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps)) {
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
index f7bfeb1..4b73faa 100644
--- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc
+++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -1177,12 +1177,13 @@
     webrtc::RtpParameters parameters =
         channel_->GetRtpSendParameters(last_ssrc_);
     EXPECT_EQ(1UL, parameters.encodings.size());
-    parameters.encodings[0].max_bitrate_bps = stream_max;
+    parameters.encodings[0].max_bitrate_bps = rtc::Optional<int>(stream_max);
     EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters));
     // Read back the parameteres and verify they have the correct value
     parameters = channel_->GetRtpSendParameters(last_ssrc_);
     EXPECT_EQ(1UL, parameters.encodings.size());
-    EXPECT_EQ(stream_max, parameters.encodings[0].max_bitrate_bps);
+    EXPECT_EQ(rtc::Optional<int>(stream_max),
+              parameters.encodings[0].max_bitrate_bps);
     // Verify that the new value propagated down to the encoder
     EXPECT_EQ(expected_encoder_bitrate, GetMaxEncoderBitrate());
   }
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc
index 65a238f..7029e5b 100644
--- a/webrtc/media/engine/webrtcvoiceengine.cc
+++ b/webrtc/media/engine/webrtcvoiceengine.cc
@@ -520,10 +520,16 @@
     {kDtmfCodecName, 8000, 1, 126, false, {}}
 };
 
+// |max_send_bitrate_bps| is the bitrate from "b=" in SDP.
+// |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters.
 rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps,
-                                      int rtp_max_bitrate_bps,
+                                      rtc::Optional<int> rtp_max_bitrate_bps,
                                       const webrtc::CodecInst& codec_inst) {
-  const int bps = MinPositive(max_send_bitrate_bps, rtp_max_bitrate_bps);
+  // If application-configured bitrate is set, take minimum of that and SDP
+  // bitrate.
+  const int bps = rtp_max_bitrate_bps
+                      ? MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps)
+                      : max_send_bitrate_bps;
   const int codec_rate = codec_inst.rate;
 
   if (bps <= 0) {
diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
index 526f7cc..a7ea8c2 100644
--- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc
+++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
@@ -289,7 +289,7 @@
     webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(ssrc);
     EXPECT_EQ(1UL, parameters.encodings.size());
 
-    parameters.encodings[0].max_bitrate_bps = bitrate;
+    parameters.encodings[0].max_bitrate_bps = rtc::Optional<int>(bitrate);
     return channel_->SetRtpSendParameters(ssrc, parameters);
   }
 
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index 57e7afb..a64fc34 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -1956,7 +1956,7 @@
     return channel1_->SetRemoteContent(&content, CA_OFFER, NULL);
   }
 
-  webrtc::RtpParameters BitrateLimitedParameters(int limit) {
+  webrtc::RtpParameters BitrateLimitedParameters(rtc::Optional<int> limit) {
     webrtc::RtpParameters parameters;
     webrtc::RtpEncodingParameters encoding;
     encoding.max_bitrate_bps = limit;
@@ -1965,7 +1965,7 @@
   }
 
   void VerifyMaxBitrate(const webrtc::RtpParameters& parameters,
-                        int expected_bitrate) {
+                        rtc::Optional<int> expected_bitrate) {
     EXPECT_EQ(1UL, parameters.encodings.size());
     EXPECT_EQ(expected_bitrate, parameters.encodings[0].max_bitrate_bps);
   }
@@ -1975,7 +1975,8 @@
     EXPECT_TRUE(
         channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
     EXPECT_EQ(media_channel1_->max_bps(), -1);
-    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), -1);
+    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1),
+                     rtc::Optional<int>());
   }
 
   void CanChangeMaxBitrate() {
@@ -1984,15 +1985,19 @@
         channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
 
     EXPECT_TRUE(channel1_->SetRtpSendParameters(
-        kSsrc1, BitrateLimitedParameters(1000)));
-    VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), 1000);
-    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), 1000);
+        kSsrc1, BitrateLimitedParameters(rtc::Optional<int>(1000))));
+    VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1),
+                     rtc::Optional<int>(1000));
+    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1),
+                     rtc::Optional<int>(1000));
     EXPECT_EQ(-1, media_channel1_->max_bps());
 
-    EXPECT_TRUE(
-        channel1_->SetRtpSendParameters(kSsrc1, BitrateLimitedParameters(-1)));
-    VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), -1);
-    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), -1);
+    EXPECT_TRUE(channel1_->SetRtpSendParameters(
+        kSsrc1, BitrateLimitedParameters(rtc::Optional<int>())));
+    VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1),
+                     rtc::Optional<int>());
+    VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1),
+                     rtc::Optional<int>());
     EXPECT_EQ(-1, media_channel1_->max_bps());
   }
 
diff --git a/webrtc/pc/rtcstatscollector.cc b/webrtc/pc/rtcstatscollector.cc
index 6344d87..435cf8e 100644
--- a/webrtc/pc/rtcstatscollector.cc
+++ b/webrtc/pc/rtcstatscollector.cc
@@ -170,13 +170,16 @@
     const RtpCodecParameters& codec_params) {
   RTC_DCHECK_GE(codec_params.payload_type, 0);
   RTC_DCHECK_LE(codec_params.payload_type, 127);
+  RTC_DCHECK(codec_params.clock_rate);
   uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
   std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats(
       RTCCodecStatsIDFromDirectionMediaAndPayload(inbound, audio, payload_type),
       timestamp_us));
   codec_stats->payload_type = payload_type;
-  codec_stats->codec = (audio ? "audio/" : "video/") + codec_params.mime_type;
-  codec_stats->clock_rate = static_cast<uint32_t>(codec_params.clock_rate);
+  codec_stats->codec = codec_params.mime_type();
+  if (codec_params.clock_rate) {
+    codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
+  }
   return codec_stats;
 }
 
diff --git a/webrtc/pc/rtcstatscollector_unittest.cc b/webrtc/pc/rtcstatscollector_unittest.cc
index 6d1595e..178deee 100644
--- a/webrtc/pc/rtcstatscollector_unittest.cc
+++ b/webrtc/pc/rtcstatscollector_unittest.cc
@@ -765,15 +765,17 @@
 
   RtpCodecParameters inbound_audio_codec;
   inbound_audio_codec.payload_type = 1;
-  inbound_audio_codec.mime_type = "opus";
-  inbound_audio_codec.clock_rate = 1337;
+  inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
+  inbound_audio_codec.name = "opus";
+  inbound_audio_codec.clock_rate = rtc::Optional<int>(1337);
   voice_media_info.receive_codecs.insert(
       std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
 
   RtpCodecParameters outbound_audio_codec;
   outbound_audio_codec.payload_type = 2;
-  outbound_audio_codec.mime_type = "isac";
-  outbound_audio_codec.clock_rate = 1338;
+  outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
+  outbound_audio_codec.name = "isac";
+  outbound_audio_codec.clock_rate = rtc::Optional<int>(1338);
   voice_media_info.send_codecs.insert(
       std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
 
@@ -785,15 +787,17 @@
 
   RtpCodecParameters inbound_video_codec;
   inbound_video_codec.payload_type = 3;
-  inbound_video_codec.mime_type = "H264";
-  inbound_video_codec.clock_rate = 1339;
+  inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
+  inbound_video_codec.name = "H264";
+  inbound_video_codec.clock_rate = rtc::Optional<int>(1339);
   video_media_info.receive_codecs.insert(
       std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
 
   RtpCodecParameters outbound_video_codec;
   outbound_video_codec.payload_type = 4;
-  outbound_video_codec.mime_type = "VP8";
-  outbound_video_codec.clock_rate = 1340;
+  outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
+  outbound_video_codec.name = "VP8";
+  outbound_video_codec.clock_rate = rtc::Optional<int>(1340);
   video_media_info.send_codecs.insert(
       std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
 
@@ -1687,8 +1691,9 @@
 
   RtpCodecParameters codec_parameters;
   codec_parameters.payload_type = 42;
-  codec_parameters.mime_type = "dummy";
-  codec_parameters.clock_rate = 0;
+  codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  codec_parameters.name = "dummy";
+  codec_parameters.clock_rate = rtc::Optional<int>(0);
   voice_media_info.receive_codecs.insert(
       std::make_pair(codec_parameters.payload_type, codec_parameters));
 
@@ -1769,8 +1774,9 @@
 
   RtpCodecParameters codec_parameters;
   codec_parameters.payload_type = 42;
-  codec_parameters.mime_type = "dummy";
-  codec_parameters.clock_rate = 0;
+  codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  codec_parameters.name = "dummy";
+  codec_parameters.clock_rate = rtc::Optional<int>(0);
   video_media_info.receive_codecs.insert(
       std::make_pair(codec_parameters.payload_type, codec_parameters));
 
@@ -1848,8 +1854,9 @@
 
   RtpCodecParameters codec_parameters;
   codec_parameters.payload_type = 42;
-  codec_parameters.mime_type = "dummy";
-  codec_parameters.clock_rate = 0;
+  codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  codec_parameters.name = "dummy";
+  codec_parameters.clock_rate = rtc::Optional<int>(0);
   voice_media_info.send_codecs.insert(
       std::make_pair(codec_parameters.payload_type, codec_parameters));
 
@@ -1927,8 +1934,9 @@
 
   RtpCodecParameters codec_parameters;
   codec_parameters.payload_type = 42;
-  codec_parameters.mime_type = "dummy";
-  codec_parameters.clock_rate = 0;
+  codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  codec_parameters.name = "dummy";
+  codec_parameters.clock_rate = rtc::Optional<int>(0);
   video_media_info.send_codecs.insert(
       std::make_pair(codec_parameters.payload_type, codec_parameters));
 
diff --git a/webrtc/pc/rtpsenderreceiver_unittest.cc b/webrtc/pc/rtpsenderreceiver_unittest.cc
index 508a417..c02da58 100644
--- a/webrtc/pc/rtpsenderreceiver_unittest.cc
+++ b/webrtc/pc/rtpsenderreceiver_unittest.cc
@@ -575,19 +575,19 @@
   EXPECT_EQ(-1, voice_media_channel_->max_bps());
   webrtc::RtpParameters params = audio_rtp_sender_->GetParameters();
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(-1, params.encodings[0].max_bitrate_bps);
-  params.encodings[0].max_bitrate_bps = 1000;
+  EXPECT_FALSE(params.encodings[0].max_bitrate_bps);
+  params.encodings[0].max_bitrate_bps = rtc::Optional<int>(1000);
   EXPECT_TRUE(audio_rtp_sender_->SetParameters(params));
 
   // Read back the parameters and verify they have been changed.
   params = audio_rtp_sender_->GetParameters();
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
+  EXPECT_EQ(rtc::Optional<int>(1000), params.encodings[0].max_bitrate_bps);
 
   // Verify that the audio channel received the new parameters.
   params = voice_media_channel_->GetRtpSendParameters(kAudioSsrc);
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
+  EXPECT_EQ(rtc::Optional<int>(1000), params.encodings[0].max_bitrate_bps);
 
   // Verify that the global bitrate limit has not been changed.
   EXPECT_EQ(-1, voice_media_channel_->max_bps());
@@ -611,19 +611,19 @@
   EXPECT_EQ(-1, video_media_channel_->max_bps());
   webrtc::RtpParameters params = video_rtp_sender_->GetParameters();
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(-1, params.encodings[0].max_bitrate_bps);
-  params.encodings[0].max_bitrate_bps = 1000;
+  EXPECT_FALSE(params.encodings[0].max_bitrate_bps);
+  params.encodings[0].max_bitrate_bps = rtc::Optional<int>(1000);
   EXPECT_TRUE(video_rtp_sender_->SetParameters(params));
 
   // Read back the parameters and verify they have been changed.
   params = video_rtp_sender_->GetParameters();
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
+  EXPECT_EQ(rtc::Optional<int>(1000), params.encodings[0].max_bitrate_bps);
 
   // Verify that the video channel received the new parameters.
   params = video_media_channel_->GetRtpSendParameters(kVideoSsrc);
   EXPECT_EQ(1, params.encodings.size());
-  EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
+  EXPECT_EQ(rtc::Optional<int>(1000), params.encodings[0].max_bitrate_bps);
 
   // Verify that the global bitrate limit has not been changed.
   EXPECT_EQ(-1, video_media_channel_->max_bps());
diff --git a/webrtc/sdk/android/api/org/webrtc/RtpParameters.java b/webrtc/sdk/android/api/org/webrtc/RtpParameters.java
index a50cf55..fde2b35 100644
--- a/webrtc/sdk/android/api/org/webrtc/RtpParameters.java
+++ b/webrtc/sdk/android/api/org/webrtc/RtpParameters.java
@@ -15,23 +15,43 @@
 /**
  * The parameters for an {@code RtpSender}, as defined in
  * http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface.
+ *
+ * Note: These structures use nullable Integer/etc. types because in the
+ * future, they may be used to construct ORTC RtpSender/RtpReceivers, in
+ * which case "null" will be used to represent "choose the implementation
+ * default value".
  */
 public class RtpParameters {
   public static class Encoding {
+    // Set to true to cause this encoding to be sent, and false for it not to
+    // be sent.
     public boolean active = true;
-    // A null value means "no maximum bitrate".
+    // If non-null, this represents the Transport Independent Application
+    // Specific maximum bandwidth defined in RFC3890. If null, there is no
+    // maximum bitrate.
     public Integer maxBitrateBps;
+    // SSRC to be used by this encoding.
+    // Can't be changed between getParameters/setParameters.
     public Long ssrc;
   }
 
   public static class Codec {
-    int payloadType;
-    String mimeType;
-    int clockRate;
-    int channels = 1;
+    // Payload type used to identify this codec in RTP packets.
+    public int payloadType;
+    // Name used to identify the codec. Equivalent to MIME subtype.
+    public String name;
+    // The media type of this codec. Equivalent to MIME top-level type.
+    MediaStreamTrack.MediaType kind;
+    // Clock rate in Hertz.
+    public Integer clockRate;
+    // The number of audio channels used. Set to null for video codecs.
+    public Integer numChannels;
   }
 
   public final LinkedList<Encoding> encodings;
+  // Codec parameters can't currently be changed between getParameters and
+  // setParameters. Though in the future it will be possible to reorder them or
+  // remove them.
   public final LinkedList<Codec> codecs;
 
   public RtpParameters() {
diff --git a/webrtc/sdk/android/src/jni/peerconnection_jni.cc b/webrtc/sdk/android/src/jni/peerconnection_jni.cc
index 6a6ba25..d3f2344 100644
--- a/webrtc/sdk/android/src/jni/peerconnection_jni.cc
+++ b/webrtc/sdk/android/src/jni/peerconnection_jni.cc
@@ -158,6 +158,47 @@
   return init;
 }
 
+static cricket::MediaType JavaMediaTypeToJsepMediaType(JNIEnv* jni,
+                                                       jobject j_media_type) {
+  jclass j_media_type_class =
+      FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType");
+  jmethodID j_name_id =
+      GetMethodID(jni, j_media_type_class, "name", "()Ljava/lang/String;");
+  jstring j_type_string =
+      (jstring)jni->CallObjectMethod(j_media_type, j_name_id);
+  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
+  std::string type_string = JavaToStdString(jni, j_type_string);
+
+  RTC_DCHECK(type_string == "MEDIA_TYPE_AUDIO" ||
+             type_string == "MEDIA_TYPE_VIDEO")
+      << "Media type: " << type_string;
+  return type_string == "MEDIA_TYPE_AUDIO" ? cricket::MEDIA_TYPE_AUDIO
+                                           : cricket::MEDIA_TYPE_VIDEO;
+}
+
+static jobject JsepMediaTypeToJavaMediaType(JNIEnv* jni,
+                                            cricket::MediaType media_type) {
+  jclass j_media_type_class =
+      FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType");
+
+  const char* media_type_str = nullptr;
+  switch (media_type) {
+    case cricket::MEDIA_TYPE_AUDIO:
+      media_type_str = "MEDIA_TYPE_AUDIO";
+      break;
+    case cricket::MEDIA_TYPE_VIDEO:
+      media_type_str = "MEDIA_TYPE_VIDEO";
+      break;
+    case cricket::MEDIA_TYPE_DATA:
+      RTC_NOTREACHED();
+      break;
+  }
+  jfieldID j_media_type_fid =
+      GetStaticFieldID(jni, j_media_type_class, media_type_str,
+                       "Lorg/webrtc/MediaStreamTrack$MediaType;");
+  return GetStaticObjectField(jni, j_media_type_class, j_media_type_fid);
+}
+
 class ConstraintsWrapper;
 
 // Adapter between the C++ PeerConnectionObserver interface and the Java
@@ -917,20 +958,7 @@
         jni, GetObjectClass(jni, *j_observer_global_), "onFirstPacketReceived",
         "(Lorg/webrtc/MediaStreamTrack$MediaType;)V");
     // Get the Java version of media type.
-    jclass j_media_type_class =
-        FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType");
-
-    RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
-               media_type == cricket::MEDIA_TYPE_VIDEO)
-        << "Media type: " << media_type;
-    const char* media_type_str = media_type == cricket::MEDIA_TYPE_AUDIO
-                                     ? "MEDIA_TYPE_AUDIO"
-                                     : "MEDIA_TYPE_VIDEO";
-    jfieldID j_media_type_fid =
-        GetStaticFieldID(jni, j_media_type_class, media_type_str,
-                         "Lorg/webrtc/MediaStreamTrack$MediaType;");
-    jobject JavaMediaType =
-        GetStaticObjectField(jni, j_media_type_class, j_media_type_fid);
+    jobject JavaMediaType = JsepMediaTypeToJavaMediaType(jni, media_type);
     // Trigger the callback function.
     jni->CallVoidMethod(*j_observer_global_, j_on_first_packet_received_mid,
                         JavaMediaType);
@@ -2400,7 +2428,6 @@
 
   // Convert encodings.
   jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id);
-  const int kBitrateUnlimited = -1;
   jclass j_encoding_parameters_class =
       jni->FindClass("org/webrtc/RtpParameters$Encoding");
   jfieldID active_id =
@@ -2422,9 +2449,7 @@
     if (!IsNull(jni, j_bitrate)) {
       int bitrate_value = jni->CallIntMethod(j_bitrate, int_value_id);
       CHECK_EXCEPTION(jni) << "error during CallIntMethod";
-      encoding.max_bitrate_bps = bitrate_value;
-    } else {
-      encoding.max_bitrate_bps = kBitrateUnlimited;
+      encoding.max_bitrate_bps = rtc::Optional<int>(bitrate_value);
     }
     jobject j_ssrc =
         GetNullableObjectField(jni, j_encoding_parameters, ssrc_id);
@@ -2440,18 +2465,33 @@
   jobject j_codecs = GetObjectField(jni, j_parameters, codecs_id);
   jclass codec_class = jni->FindClass("org/webrtc/RtpParameters$Codec");
   jfieldID payload_type_id = GetFieldID(jni, codec_class, "payloadType", "I");
-  jfieldID mime_type_id =
-      GetFieldID(jni, codec_class, "mimeType", "Ljava/lang/String;");
-  jfieldID clock_rate_id = GetFieldID(jni, codec_class, "clockRate", "I");
-  jfieldID channels_id = GetFieldID(jni, codec_class, "channels", "I");
+  jfieldID name_id = GetFieldID(jni, codec_class, "name", "Ljava/lang/String;");
+  jfieldID kind_id = GetFieldID(jni, codec_class, "kind",
+                                "Lorg/webrtc/MediaStreamTrack$MediaType;");
+  jfieldID clock_rate_id =
+      GetFieldID(jni, codec_class, "clockRate", "Ljava/lang/Integer;");
+  jfieldID num_channels_id =
+      GetFieldID(jni, codec_class, "numChannels", "Ljava/lang/Integer;");
 
   for (jobject j_codec : Iterable(jni, j_codecs)) {
     webrtc::RtpCodecParameters codec;
     codec.payload_type = GetIntField(jni, j_codec, payload_type_id);
-    codec.mime_type =
-        JavaToStdString(jni, GetStringField(jni, j_codec, mime_type_id));
-    codec.clock_rate = GetIntField(jni, j_codec, clock_rate_id);
-    codec.channels = GetIntField(jni, j_codec, channels_id);
+    codec.name = JavaToStdString(jni, GetStringField(jni, j_codec, name_id));
+    codec.kind = JavaMediaTypeToJsepMediaType(
+        jni, GetObjectField(jni, j_codec, kind_id));
+    jobject j_clock_rate = GetNullableObjectField(jni, j_codec, clock_rate_id);
+    if (!IsNull(jni, j_clock_rate)) {
+      int clock_rate_value = jni->CallIntMethod(j_clock_rate, int_value_id);
+      CHECK_EXCEPTION(jni) << "error during CallIntMethod";
+      codec.clock_rate = rtc::Optional<int>(clock_rate_value);
+    }
+    jobject j_num_channels =
+        GetNullableObjectField(jni, j_codec, num_channels_id);
+    if (!IsNull(jni, j_num_channels)) {
+      int num_channels_value = jni->CallIntMethod(j_num_channels, int_value_id);
+      CHECK_EXCEPTION(jni) << "error during CallIntMethod";
+      codec.num_channels = rtc::Optional<int>(num_channels_value);
+    }
     parameters->codecs.push_back(codec);
   }
 }
@@ -2473,8 +2513,7 @@
   jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id);
   jmethodID encodings_add = GetMethodID(jni, GetObjectClass(jni, j_encodings),
                                         "add", "(Ljava/lang/Object;)Z");
-  jfieldID active_id =
-      GetFieldID(jni, encoding_class, "active", "Z");
+  jfieldID active_id = GetFieldID(jni, encoding_class, "active", "Z");
   jfieldID bitrate_id =
       GetFieldID(jni, encoding_class, "maxBitrateBps", "Ljava/lang/Integer;");
   jfieldID ssrc_id =
@@ -2491,9 +2530,9 @@
     CHECK_EXCEPTION(jni) << "error during NewObject";
     jni->SetBooleanField(j_encoding_parameters, active_id, encoding.active);
     CHECK_EXCEPTION(jni) << "error during SetBooleanField";
-    if (encoding.max_bitrate_bps > 0) {
-      jobject j_bitrate_value =
-          jni->NewObject(integer_class, integer_ctor, encoding.max_bitrate_bps);
+    if (encoding.max_bitrate_bps) {
+      jobject j_bitrate_value = jni->NewObject(integer_class, integer_ctor,
+                                               *(encoding.max_bitrate_bps));
       CHECK_EXCEPTION(jni) << "error during NewObject";
       jni->SetObjectField(j_encoding_parameters, bitrate_id, j_bitrate_value);
       CHECK_EXCEPTION(jni) << "error during SetObjectField";
@@ -2517,26 +2556,42 @@
   jfieldID codecs_id =
       GetFieldID(jni, parameters_class, "codecs", "Ljava/util/LinkedList;");
   jobject j_codecs = GetObjectField(jni, j_parameters, codecs_id);
-  jmethodID codecs_add = GetMethodID(jni, GetObjectClass(jni, j_codecs),
-                                     "add", "(Ljava/lang/Object;)Z");
+  jmethodID codecs_add = GetMethodID(jni, GetObjectClass(jni, j_codecs), "add",
+                                     "(Ljava/lang/Object;)Z");
   jfieldID payload_type_id = GetFieldID(jni, codec_class, "payloadType", "I");
-  jfieldID mime_type_id =
-      GetFieldID(jni, codec_class, "mimeType", "Ljava/lang/String;");
-  jfieldID clock_rate_id = GetFieldID(jni, codec_class, "clockRate", "I");
-  jfieldID channels_id = GetFieldID(jni, codec_class, "channels", "I");
+  jfieldID name_id = GetFieldID(jni, codec_class, "name", "Ljava/lang/String;");
+  jfieldID kind_id = GetFieldID(jni, codec_class, "kind",
+                                "Lorg/webrtc/MediaStreamTrack$MediaType;");
+  jfieldID clock_rate_id =
+      GetFieldID(jni, codec_class, "clockRate", "Ljava/lang/Integer;");
+  jfieldID num_channels_id =
+      GetFieldID(jni, codec_class, "numChannels", "Ljava/lang/Integer;");
 
   for (const webrtc::RtpCodecParameters& codec : parameters.codecs) {
     jobject j_codec = jni->NewObject(codec_class, codec_ctor);
     CHECK_EXCEPTION(jni) << "error during NewObject";
     jni->SetIntField(j_codec, payload_type_id, codec.payload_type);
     CHECK_EXCEPTION(jni) << "error during SetIntField";
-    jni->SetObjectField(j_codec, mime_type_id,
-                        JavaStringFromStdString(jni, codec.mime_type));
+    jni->SetObjectField(j_codec, name_id,
+                        JavaStringFromStdString(jni, codec.name));
     CHECK_EXCEPTION(jni) << "error during SetObjectField";
-    jni->SetIntField(j_codec, clock_rate_id, codec.clock_rate);
-    CHECK_EXCEPTION(jni) << "error during SetIntField";
-    jni->SetIntField(j_codec, channels_id, codec.channels);
-    CHECK_EXCEPTION(jni) << "error during SetIntField";
+    jni->SetObjectField(j_codec, kind_id,
+                        JsepMediaTypeToJavaMediaType(jni, codec.kind));
+    CHECK_EXCEPTION(jni) << "error during SetObjectField";
+    if (codec.clock_rate) {
+      jobject j_clock_rate_value =
+          jni->NewObject(integer_class, integer_ctor, *(codec.clock_rate));
+      CHECK_EXCEPTION(jni) << "error during NewObject";
+      jni->SetObjectField(j_codec, clock_rate_id, j_clock_rate_value);
+      CHECK_EXCEPTION(jni) << "error during SetObjectField";
+    }
+    if (codec.num_channels) {
+      jobject j_num_channels_value =
+          jni->NewObject(integer_class, integer_ctor, *(codec.num_channels));
+      CHECK_EXCEPTION(jni) << "error during NewObject";
+      jni->SetObjectField(j_codec, num_channels_id, j_num_channels_value);
+      CHECK_EXCEPTION(jni) << "error during SetObjectField";
+    }
     jboolean added = jni->CallBooleanMethod(j_codecs, codecs_add, j_codec);
     CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
     RTC_CHECK(added);
diff --git a/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm b/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm
index 40f4f25..90529c8 100644
--- a/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm
+++ b/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm
@@ -11,33 +11,36 @@
 #import "RTCRtpCodecParameters+Private.h"
 
 #import "NSString+StdString.h"
+#import "WebRTC/RTCMediaStreamTrack.h"  // For "kind" strings.
 
+#include "webrtc/base/checks.h"
 #include "webrtc/media/base/mediaconstants.h"
 
-const NSString * const kRTCRtxCodecMimeType = @(cricket::kRtxCodecName);
-const NSString * const kRTCRedCodecMimeType = @(cricket::kRedCodecName);
-const NSString * const kRTCUlpfecCodecMimeType = @(cricket::kUlpfecCodecName);
-const NSString * const kRTCFlexfecCodecMimeType = @(cricket::kFlexfecCodecName);
-const NSString * const kRTCOpusCodecMimeType = @(cricket::kOpusCodecName);
-const NSString * const kRTCIsacCodecMimeType = @(cricket::kIsacCodecName);
-const NSString * const kRTCL16CodecMimeType  = @(cricket::kL16CodecName);
-const NSString * const kRTCG722CodecMimeType = @(cricket::kG722CodecName);
-const NSString * const kRTCIlbcCodecMimeType = @(cricket::kIlbcCodecName);
-const NSString * const kRTCPcmuCodecMimeType = @(cricket::kPcmuCodecName);
-const NSString * const kRTCPcmaCodecMimeType = @(cricket::kPcmaCodecName);
-const NSString * const kRTCDtmfCodecMimeType = @(cricket::kDtmfCodecName);
-const NSString * const kRTCComfortNoiseCodecMimeType =
+const NSString * const kRTCRtxCodecName = @(cricket::kRtxCodecName);
+const NSString * const kRTCRedCodecName = @(cricket::kRedCodecName);
+const NSString * const kRTCUlpfecCodecName = @(cricket::kUlpfecCodecName);
+const NSString * const kRTCFlexfecCodecName = @(cricket::kFlexfecCodecName);
+const NSString * const kRTCOpusCodecName = @(cricket::kOpusCodecName);
+const NSString * const kRTCIsacCodecName = @(cricket::kIsacCodecName);
+const NSString * const kRTCL16CodecName  = @(cricket::kL16CodecName);
+const NSString * const kRTCG722CodecName = @(cricket::kG722CodecName);
+const NSString * const kRTCIlbcCodecName = @(cricket::kIlbcCodecName);
+const NSString * const kRTCPcmuCodecName = @(cricket::kPcmuCodecName);
+const NSString * const kRTCPcmaCodecName = @(cricket::kPcmaCodecName);
+const NSString * const kRTCDtmfCodecName = @(cricket::kDtmfCodecName);
+const NSString * const kRTCComfortNoiseCodecName =
     @(cricket::kComfortNoiseCodecName);
-const NSString * const kVp8CodecMimeType = @(cricket::kVp8CodecName);
-const NSString * const kVp9CodecMimeType = @(cricket::kVp9CodecName);
-const NSString * const kH264CodecMimeType = @(cricket::kH264CodecName);
+const NSString * const kVp8CodecName = @(cricket::kVp8CodecName);
+const NSString * const kVp9CodecName = @(cricket::kVp9CodecName);
+const NSString * const kH264CodecName = @(cricket::kH264CodecName);
 
 @implementation RTCRtpCodecParameters
 
 @synthesize payloadType = _payloadType;
-@synthesize mimeType = _mimeType;
+@synthesize name = _name;
+@synthesize kind = _kind;
 @synthesize clockRate = _clockRate;
-@synthesize channels = _channels;
+@synthesize numChannels = _numChannels;
 
 - (instancetype)init {
   return [super init];
@@ -47,9 +50,24 @@
     (const webrtc::RtpCodecParameters &)nativeParameters {
   if (self = [self init]) {
     _payloadType = nativeParameters.payload_type;
-    _mimeType = [NSString stringForStdString:nativeParameters.mime_type];
-    _clockRate = nativeParameters.clock_rate;
-    _channels = nativeParameters.channels;
+    _name = [NSString stringForStdString:nativeParameters.name];
+    switch (nativeParameters.kind) {
+      case cricket::MEDIA_TYPE_AUDIO:
+        _kind = kRTCMediaStreamTrackKindAudio;
+        break;
+      case cricket::MEDIA_TYPE_VIDEO:
+        _kind = kRTCMediaStreamTrackKindVideo;
+        break;
+      case cricket::MEDIA_TYPE_DATA:
+        RTC_NOTREACHED();
+        break;
+    }
+    if (nativeParameters.clock_rate) {
+      _clockRate = [NSNumber numberWithInt:*nativeParameters.clock_rate];
+    }
+    if (nativeParameters.num_channels) {
+      _numChannels = [NSNumber numberWithInt:*nativeParameters.num_channels];
+    }
   }
   return self;
 }
@@ -57,9 +75,22 @@
 - (webrtc::RtpCodecParameters)nativeParameters {
   webrtc::RtpCodecParameters parameters;
   parameters.payload_type = _payloadType;
-  parameters.mime_type = [NSString stdStringForString:_mimeType];
-  parameters.clock_rate = _clockRate;
-  parameters.channels = _channels;
+  parameters.name = [NSString stdStringForString:_name];
+  // NSString pointer comparison is safe here since "kind" is readonly and only
+  // populated above.
+  if (_kind == kRTCMediaStreamTrackKindAudio) {
+    parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  } else if (_kind == kRTCMediaStreamTrackKindVideo) {
+    parameters.kind = cricket::MEDIA_TYPE_VIDEO;
+  } else {
+    RTC_NOTREACHED();
+  }
+  if (_clockRate != nil) {
+    parameters.clock_rate = rtc::Optional<int>(_clockRate.intValue);
+  }
+  if (_numChannels != nil) {
+    parameters.num_channels = rtc::Optional<int>(_numChannels.intValue);
+  }
   return parameters;
 }
 
diff --git a/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm b/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm
index be47894..8e72d18 100644
--- a/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm
+++ b/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm
@@ -16,8 +16,6 @@
 @synthesize maxBitrateBps = _maxBitrateBps;
 @synthesize ssrc = _ssrc;
 
-static const int kBitrateUnlimited = -1;
-
 - (instancetype)init {
   return [super init];
 }
@@ -26,10 +24,9 @@
     (const webrtc::RtpEncodingParameters &)nativeParameters {
   if (self = [self init]) {
     _isActive = nativeParameters.active;
-    // TODO(skvlad): Replace with rtc::Optional once the C++ code is updated.
-    if (nativeParameters.max_bitrate_bps != kBitrateUnlimited) {
+    if (nativeParameters.max_bitrate_bps) {
       _maxBitrateBps =
-          [NSNumber numberWithInt:nativeParameters.max_bitrate_bps];
+          [NSNumber numberWithInt:*nativeParameters.max_bitrate_bps];
     }
     if (nativeParameters.ssrc) {
       _ssrc = [NSNumber numberWithUnsignedLong:*nativeParameters.ssrc];
@@ -42,7 +39,7 @@
   webrtc::RtpEncodingParameters parameters;
   parameters.active = _isActive;
   if (_maxBitrateBps != nil) {
-    parameters.max_bitrate_bps = _maxBitrateBps.intValue;
+    parameters.max_bitrate_bps = rtc::Optional<int>(_maxBitrateBps.intValue);
   }
   if (_ssrc != nil) {
     parameters.ssrc = rtc::Optional<uint32_t>(_ssrc.unsignedLongValue);
diff --git a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h
index a3156bb..c7ca2f5 100644
--- a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h
+++ b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h
@@ -14,22 +14,22 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-RTC_EXTERN const NSString * const kRTCRtxCodecMimeType;
-RTC_EXTERN const NSString * const kRTCRedCodecMimeType;
-RTC_EXTERN const NSString * const kRTCUlpfecCodecMimeType;
-RTC_EXTERN const NSString * const kRTCFlexfecCodecMimeType;
-RTC_EXTERN const NSString * const kRTCOpusCodecMimeType;
-RTC_EXTERN const NSString * const kRTCIsacCodecMimeType;
-RTC_EXTERN const NSString * const kRTCL16CodecMimeType;
-RTC_EXTERN const NSString * const kRTCG722CodecMimeType;
-RTC_EXTERN const NSString * const kRTCIlbcCodecMimeType;
-RTC_EXTERN const NSString * const kRTCPcmuCodecMimeType;
-RTC_EXTERN const NSString * const kRTCPcmaCodecMimeType;
-RTC_EXTERN const NSString * const kRTCDtmfCodecMimeType;
-RTC_EXTERN const NSString * const kRTCComfortNoiseCodecMimeType;
-RTC_EXTERN const NSString * const kRTCVp8CodecMimeType;
-RTC_EXTERN const NSString * const kRTCVp9CodecMimeType;
-RTC_EXTERN const NSString * const kRTCH264CodecMimeType;
+RTC_EXTERN const NSString * const kRTCRtxCodecName;
+RTC_EXTERN const NSString * const kRTCRedCodecName;
+RTC_EXTERN const NSString * const kRTCUlpfecCodecName;
+RTC_EXTERN const NSString * const kRTCFlexfecCodecName;
+RTC_EXTERN const NSString * const kRTCOpusCodecName;
+RTC_EXTERN const NSString * const kRTCIsacCodecName;
+RTC_EXTERN const NSString * const kRTCL16CodecName;
+RTC_EXTERN const NSString * const kRTCG722CodecName;
+RTC_EXTERN const NSString * const kRTCIlbcCodecName;
+RTC_EXTERN const NSString * const kRTCPcmuCodecName;
+RTC_EXTERN const NSString * const kRTCPcmaCodecName;
+RTC_EXTERN const NSString * const kRTCDtmfCodecName;
+RTC_EXTERN const NSString * const kRTCComfortNoiseCodecName;
+RTC_EXTERN const NSString * const kRTCVp8CodecName;
+RTC_EXTERN const NSString * const kRTCVp9CodecName;
+RTC_EXTERN const NSString * const kRTCH264CodecName;
 
 /** Defined in http://w3c.github.io/webrtc-pc/#idl-def-RTCRtpCodecParameters */
 RTC_EXPORT
@@ -39,18 +39,29 @@
 @property(nonatomic, assign) int payloadType;
 
 /**
- * The codec MIME type. Valid types are listed in:
+ * The codec MIME subtype. Valid types are listed in:
  * http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-2
  *
  * Several supported types are represented by the constants above.
  */
-@property(nonatomic, nonnull) NSString *mimeType;
+@property(nonatomic, readonly, nonnull) NSString *name;
+
+/**
+ * The media type of this codec. Equivalent to MIME top-level type.
+ *
+ * Valid values are kRTCMediaStreamTrackKindAudio and
+ * kRTCMediaStreamTrackKindVideo.
+ */
+@property(nonatomic, readonly, nonnull) NSString *kind;
 
 /** The codec clock rate expressed in Hertz. */
-@property(nonatomic, assign) int clockRate;
+@property(nonatomic, readonly, nullable) NSNumber *clockRate;
 
-/** The number of channels (mono=1, stereo=2). */
-@property(nonatomic, assign) int channels;
+/**
+ * The number of channels (mono=1, stereo=2).
+ * Set to null for video codecs.
+ **/
+@property(nonatomic, readonly, nullable) NSNumber *numChannels;
 
 - (instancetype)init NS_DESIGNATED_INITIALIZER;