Adding codecs to the RtpParameters returned by an RtpSender.

Contains every field except for sdpFmtpLine.
Setting a reordered list of codecs is not yet supported.

R=glaznev@webrtc.org, pthatcher@webrtc.org, skvlad@webrtc.org, tkchin@webrtc.org

Review URL: https://codereview.webrtc.org/1885473004 .

Cr-Original-Commit-Position: refs/heads/master@{#12453}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 0cd086b70ec939cad25768d5e17a61da23613281
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 9bc4c27..6503953 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -61,6 +61,9 @@
       #"objc/RTCPeerConnectionFactory+Private.h",
       #"objc/RTCPeerConnectionFactory.h",
       #"objc/RTCPeerConnectionFactory.mm",
+      #"objc/RTCRtpCodecParameters+Private.h",
+      #"objc/RTCRtpCodecParameters.h",
+      #"objc/RTCRtpCodecParameters.mm",
       #"objc/RTCRtpEncodingParameters+Private.h",
       #"objc/RTCRtpEncodingParameters.h",
       #"objc/RTCRtpEncodingParameters.mm",
diff --git a/api/api.gyp b/api/api.gyp
index cfa8d9b..3d47053 100644
--- a/api/api.gyp
+++ b/api/api.gyp
@@ -172,6 +172,9 @@
             'objc/RTCPeerConnectionFactory+Private.h',
             'objc/RTCPeerConnectionFactory.h',
             'objc/RTCPeerConnectionFactory.mm',
+            'objc/RTCRtpCodecParameters+Private.h',
+            'objc/RTCRtpCodecParameters.h',
+            'objc/RTCRtpCodecParameters.mm',
             'objc/RTCRtpEncodingParameters+Private.h',
             'objc/RTCRtpEncodingParameters.h',
             'objc/RTCRtpEncodingParameters.mm',
diff --git a/api/java/jni/peerconnection_jni.cc b/api/java/jni/peerconnection_jni.cc
index cbdcbe0..fdd2d44 100644
--- a/api/java/jni/peerconnection_jni.cc
+++ b/api/java/jni/peerconnection_jni.cc
@@ -2058,6 +2058,29 @@
   return true;
 }
 
+static bool JavaCodecToJsepRtpCodecParameters(
+    JNIEnv* jni,
+    jobject j_codecs,
+    std::vector<webrtc::RtpCodecParameters>* codecs) {
+  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");
+
+  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);
+    codecs->push_back(codec);
+  }
+  return true;
+}
+
 JOW(jboolean, RtpSender_nativeSetParameters)
 (JNIEnv* jni, jclass, jlong j_rtp_sender_pointer, jobject j_parameters) {
   if (IsNull(jni, j_parameters)) {
@@ -2067,11 +2090,15 @@
   jclass encoding_class = jni->FindClass("org/webrtc/RtpParameters$Encoding");
   jfieldID encodings_id =
       GetFieldID(jni, parameters_class, "encodings", "Ljava/util/LinkedList;");
+  jfieldID codecs_id =
+      GetFieldID(jni, parameters_class, "codecs", "Ljava/util/LinkedList;");
 
   jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id);
+  jobject j_codecs = GetObjectField(jni, j_parameters, codecs_id);
   webrtc::RtpParameters parameters;
   JavaEncodingToJsepRtpEncodingParameters(jni, j_encodings,
                                           &parameters.encodings);
+  JavaCodecToJsepRtpCodecParameters(jni, j_codecs, &parameters.codecs);
   return reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)
       ->SetParameters(parameters);
 }
@@ -2093,8 +2120,8 @@
   jfieldID encodings_id =
       GetFieldID(jni, parameters_class, "encodings", "Ljava/util/LinkedList;");
   jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id);
-  jmethodID add = GetMethodID(jni, GetObjectClass(jni, j_encodings), "add",
-                              "(Ljava/lang/Object;)Z");
+  jmethodID encodings_add = GetMethodID(jni, GetObjectClass(jni, j_encodings),
+                                        "add", "(Ljava/lang/Object;)Z");
   jfieldID active_id =
       GetFieldID(jni, encoding_class, "active", "Z");
   jfieldID bitrate_id =
@@ -2116,10 +2143,42 @@
       jni->SetObjectField(j_encoding_parameters, bitrate_id, j_bitrate_value);
       CHECK_EXCEPTION(jni) << "error during SetObjectField";
     }
-    jboolean added =
-        jni->CallBooleanMethod(j_encodings, add, j_encoding_parameters);
+    jboolean added = jni->CallBooleanMethod(j_encodings, encodings_add,
+                                            j_encoding_parameters);
     CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
+    RTC_CHECK(added);
   }
+
+  jclass codec_class = jni->FindClass("org/webrtc/RtpParameters$Codec");
+  jmethodID codec_ctor = GetMethodID(jni, codec_class, "<init>", "()V");
+  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");
+  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");
+
+  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));
+    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";
+    jboolean added = jni->CallBooleanMethod(j_codecs, codecs_add, j_codec);
+    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
+    RTC_CHECK(added);
+  }
+
   return j_parameters;
 }
 
diff --git a/api/java/src/org/webrtc/RtpParameters.java b/api/java/src/org/webrtc/RtpParameters.java
index d689517..4aa10fb 100644
--- a/api/java/src/org/webrtc/RtpParameters.java
+++ b/api/java/src/org/webrtc/RtpParameters.java
@@ -24,9 +24,18 @@
     public Integer maxBitrateBps;
   }
 
+  public static class Codec {
+    int payloadType;
+    String mimeType;
+    int clockRate;
+    int channels = 1;
+  }
+
   public final LinkedList<Encoding> encodings;
+  public final LinkedList<Codec> codecs;
 
   public RtpParameters() {
     encodings = new LinkedList<Encoding>();
+    codecs = new LinkedList<Codec>();
   }
 }
diff --git a/api/objc/RTCRtpCodecParameters+Private.h b/api/objc/RTCRtpCodecParameters+Private.h
new file mode 100644
index 0000000..aabbf7d
--- /dev/null
+++ b/api/objc/RTCRtpCodecParameters+Private.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "webrtc/api/objc/RTCRtpCodecParameters.h"
+
+#include "webrtc/api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtpCodecParameters ()
+
+/** Returns the equivalent native RtpCodecParameters structure. */
+@property(nonatomic, readonly) webrtc::RtpCodecParameters nativeParameters;
+
+/** Initialize the object with a native RtpCodecParameters structure. */
+- (instancetype)initWithNativeParameters:
+    (const webrtc::RtpCodecParameters &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/api/objc/RTCRtpCodecParameters.h b/api/objc/RTCRtpCodecParameters.h
new file mode 100644
index 0000000..ec0c647
--- /dev/null
+++ b/api/objc/RTCRtpCodecParameters.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+extern const NSString * const kRtxCodecMimeType;
+extern const NSString * const kRedCodecMimeType;
+extern const NSString * const kUlpfecCodecMimeType;
+extern const NSString * const kOpusCodecMimeType;
+extern const NSString * const kIsacCodecMimeType;
+extern const NSString * const kL16CodecMimeType;
+extern const NSString * const kG722CodecMimeType;
+extern const NSString * const kIlbcCodecMimeType;
+extern const NSString * const kPcmuCodecMimeType;
+extern const NSString * const kPcmaCodecMimeType;
+extern const NSString * const kDtmfCodecMimeType;
+extern const NSString * const kComfortNoiseCodecMimeType;
+extern const NSString * const kVp8CodecMimeType;
+extern const NSString * const kVp9CodecMimeType;
+extern const NSString * const kH264CodecMimeType;
+
+/** Defined in http://w3c.github.io/webrtc-pc/#idl-def-RTCRtpCodecParameters */
+@interface RTCRtpCodecParameters : NSObject
+
+/** The RTP payload type. */
+@property(nonatomic, assign) int payloadType;
+
+/**
+ * The codec MIME type. 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;
+
+/** The codec clock rate expressed in Hertz. */
+@property(nonatomic, assign) int clockRate;
+
+/** The number of channels (mono=1, stereo=2). */
+@property(nonatomic, assign) int channels;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/api/objc/RTCRtpCodecParameters.mm b/api/objc/RTCRtpCodecParameters.mm
new file mode 100644
index 0000000..8bc2204
--- /dev/null
+++ b/api/objc/RTCRtpCodecParameters.mm
@@ -0,0 +1,63 @@
+/*
+ *  Copyright 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCRtpCodecParameters+Private.h"
+
+#import "webrtc/base/objc/NSString+StdString.h"
+#import "webrtc/media/base/mediaconstants.h"
+
+const NSString * const kRtxCodecMimeType = @(cricket::kRtxCodecName);
+const NSString * const kRedCodecMimeType = @(cricket::kRedCodecName);
+const NSString * const kUlpfecCodecMimeType = @(cricket::kUlpfecCodecName);
+const NSString * const kOpusCodecMimeType = @(cricket::kOpusCodecName);
+const NSString * const kIsacCodecMimeType = @(cricket::kIsacCodecName);
+const NSString * const kL16CodecMimeType  = @(cricket::kL16CodecName);
+const NSString * const kG722CodecMimeType = @(cricket::kG722CodecName);
+const NSString * const kIlbcCodecMimeType = @(cricket::kIlbcCodecName);
+const NSString * const kPcmuCodecMimeType = @(cricket::kPcmuCodecName);
+const NSString * const kPcmaCodecMimeType = @(cricket::kPcmaCodecName);
+const NSString * const kDtmfCodecMimeType = @(cricket::kDtmfCodecName);
+const NSString * const kComfortNoiseCodecMimeType = @(cricket::kComfortNoiseCodecName);
+const NSString * const kVp8CodecMimeType = @(cricket::kVp8CodecName);
+const NSString * const kVp9CodecMimeType = @(cricket::kVp9CodecName);
+const NSString * const kH264CodecMimeType = @(cricket::kH264CodecName);
+
+@implementation RTCRtpCodecParameters
+
+@synthesize payloadType = _payloadType;
+@synthesize mimeType = _mimeType;
+@synthesize clockRate = _clockRate;
+@synthesize channels = _channels;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:
+    (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;
+  }
+  return self;
+}
+
+- (webrtc::RtpCodecParameters)nativeParameters {
+  webrtc::RtpCodecParameters parameters;
+  parameters.payload_type = _payloadType;
+  parameters.mime_type = [NSString stdStringForString:_mimeType];
+  parameters.clock_rate = _clockRate;
+  parameters.channels = _channels;
+  return parameters;
+}
+
+@end
diff --git a/api/objc/RTCRtpParameters.h b/api/objc/RTCRtpParameters.h
index 91d8108..7b66f37 100644
--- a/api/objc/RTCRtpParameters.h
+++ b/api/objc/RTCRtpParameters.h
@@ -10,6 +10,7 @@
 
 #import <Foundation/Foundation.h>
 
+#import "webrtc/api/objc/RTCRtpCodecParameters.h"
 #import "webrtc/api/objc/RTCRtpEncodingParameters.h"
 #import "webrtc/base/objc/RTCMacros.h"
 
@@ -21,6 +22,9 @@
 /** The currently active encodings in the order of preference. */
 @property(nonatomic, copy) NSArray<RTCRtpEncodingParameters *> *encodings;
 
+/** The negotiated set of send codecs in order of preference. */
+@property(nonatomic, copy) NSArray<RTCRtpCodecParameters *> *codecs;
+
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/api/objc/RTCRtpParameters.mm b/api/objc/RTCRtpParameters.mm
index e8c4a44..5e79106 100644
--- a/api/objc/RTCRtpParameters.mm
+++ b/api/objc/RTCRtpParameters.mm
@@ -9,11 +9,14 @@
  */
 
 #import "RTCRtpParameters+Private.h"
+
+#import "RTCRtpCodecParameters+Private.h"
 #import "RTCRtpEncodingParameters+Private.h"
 
 @implementation RTCRtpParameters
 
 @synthesize encodings = _encodings;
+@synthesize codecs = _codecs;
 
 - (instancetype)init {
   return [super init];
@@ -28,6 +31,13 @@
                                initWithNativeParameters:encoding]];
     }
     _encodings = encodings;
+
+    NSMutableArray *codecs = [[NSMutableArray alloc] init];
+    for (const auto &codec : nativeParameters.codecs) {
+      [codecs addObject:[[RTCRtpCodecParameters alloc]
+                            initWithNativeParameters:codec]];
+    }
+    _codecs = codecs;
   }
   return self;
 }
@@ -37,6 +47,9 @@
   for (RTCRtpEncodingParameters *encoding in _encodings) {
     parameters.encodings.push_back(encoding.nativeParameters);
   }
+  for (RTCRtpCodecParameters *codec in _codecs) {
+    parameters.codecs.push_back(codec.nativeParameters);
+  }
   return parameters;
 }
 
diff --git a/api/rtpparameters.h b/api/rtpparameters.h
index 2c29d98..729f841 100644
--- a/api/rtpparameters.h
+++ b/api/rtpparameters.h
@@ -11,6 +11,7 @@
 #ifndef WEBRTC_API_RTPPARAMETERS_H_
 #define WEBRTC_API_RTPPARAMETERS_H_
 
+#include <string>
 #include <vector>
 
 namespace webrtc {
@@ -20,10 +21,32 @@
 struct RtpEncodingParameters {
   bool active = true;
   int max_bitrate_bps = -1;
+
+  bool operator==(const RtpEncodingParameters& o) const {
+    return active == o.active && max_bitrate_bps == o.max_bitrate_bps;
+  }
+};
+
+struct RtpCodecParameters {
+  int payload_type;
+  std::string mime_type;
+  int clock_rate;
+  int channels = 1;
+  // TODO(deadbeef): Add sdpFmtpLine field.
+
+  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;
+  }
 };
 
 struct RtpParameters {
   std::vector<RtpEncodingParameters> encodings;
+  std::vector<RtpCodecParameters> codecs;
+
+  bool operator==(const RtpParameters& o) const {
+    return encodings == o.encodings && codecs == o.codecs;
+  }
 };
 
 }  // namespace webrtc
diff --git a/media/base/codec.cc b/media/base/codec.cc
index 9e54d29..01350f7 100644
--- a/media/base/codec.cc
+++ b/media/base/codec.cc
@@ -142,6 +142,14 @@
   feedback_params.Intersect(other.feedback_params);
 }
 
+webrtc::RtpCodecParameters Codec::ToCodecParameters() const {
+  webrtc::RtpCodecParameters codec_params;
+  codec_params.payload_type = id;
+  codec_params.mime_type = name;
+  codec_params.clock_rate = clockrate;
+  return codec_params;
+}
+
 AudioCodec::AudioCodec(int id,
                        const std::string& name,
                        int clockrate,
@@ -182,6 +190,12 @@
       ((codec.channels < 2 && channels < 2) || channels == codec.channels);
 }
 
+webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const {
+  webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters();
+  codec_params.channels = channels;
+  return codec_params;
+}
+
 std::string AudioCodec::ToString() const {
   std::ostringstream os;
   os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
diff --git a/media/base/codec.h b/media/base/codec.h
index c79a3fa..c16158f 100644
--- a/media/base/codec.h
+++ b/media/base/codec.h
@@ -16,6 +16,7 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/api/rtpparameters.h"
 #include "webrtc/media/base/mediaconstants.h"
 
 namespace cricket {
@@ -95,6 +96,8 @@
   // and |other| are kept.
   void IntersectFeedbackParams(const Codec& other);
 
+  virtual webrtc::RtpCodecParameters ToCodecParameters() const;
+
   Codec& operator=(const Codec& c);
 
   bool operator==(const Codec& c) const;
@@ -124,6 +127,8 @@
 
   std::string ToString() const;
 
+  webrtc::RtpCodecParameters ToCodecParameters() const override;
+
   AudioCodec& operator=(const AudioCodec& c);
 
   bool operator==(const AudioCodec& c) const;
diff --git a/media/engine/webrtcvideoengine2.cc b/media/engine/webrtcvideoengine2.cc
index 799596a..46b033e 100644
--- a/media/engine/webrtcvideoengine2.cc
+++ b/media/engine/webrtcvideoengine2.cc
@@ -864,6 +864,7 @@
   send_params_ = params;
   return true;
 }
+
 webrtc::RtpParameters WebRtcVideoChannel2::GetRtpParameters(
     uint32_t ssrc) const {
   rtc::CritScope stream_lock(&stream_crit_);
@@ -874,7 +875,13 @@
     return webrtc::RtpParameters();
   }
 
-  return it->second->GetRtpParameters();
+  webrtc::RtpParameters rtp_params = it->second->GetRtpParameters();
+  // Need to add the common list of codecs to the send stream-specific
+  // RTP parameters.
+  for (const VideoCodec& codec : send_params_.codecs) {
+    rtp_params.codecs.push_back(codec.ToCodecParameters());
+  }
+  return rtp_params;
 }
 
 bool WebRtcVideoChannel2::SetRtpParameters(
@@ -889,6 +896,8 @@
     return false;
   }
 
+  // TODO(deadbeef): Handle setting parameters with a list of codecs in a
+  // different order (which should change the send codec).
   return it->second->SetRtpParameters(parameters);
 }
 
@@ -1828,6 +1837,8 @@
     pending_encoder_reconfiguration_ = true;
   }
   rtp_parameters_ = new_parameters;
+  // Codecs are currently handled at the WebRtcVideoChannel2 level.
+  rtp_parameters_.codecs.clear();
   // Encoding may have been activated/deactivated.
   UpdateSendState();
   return true;
diff --git a/media/engine/webrtcvideoengine2.h b/media/engine/webrtcvideoengine2.h
index 014bd4d..5c84a79 100644
--- a/media/engine/webrtcvideoengine2.h
+++ b/media/engine/webrtcvideoengine2.h
@@ -380,6 +380,7 @@
     // entire channel.
     VideoSendStreamParameters parameters_ GUARDED_BY(lock_);
     // Contains settings that are unique for each stream, such as max_bitrate.
+    // Does *not* contain codecs, however.
     // TODO(skvlad): Move ssrcs_ and ssrc_groups_ into rtp_parameters_.
     // TODO(skvlad): Combine parameters_ and rtp_parameters_ once we have only
     // one stream per MediaChannel.
diff --git a/media/engine/webrtcvideoengine2_unittest.cc b/media/engine/webrtcvideoengine2_unittest.cc
index 5075aa2..b202207 100644
--- a/media/engine/webrtcvideoengine2_unittest.cc
+++ b/media/engine/webrtcvideoengine2_unittest.cc
@@ -3426,6 +3426,43 @@
   EXPECT_TRUE(stream->IsSending());
 }
 
+// Test that GetRtpParameters returns the currently configured codecs.
+TEST_F(WebRtcVideoChannel2Test, GetRtpParametersCodecs) {
+  AddSendStream();
+  cricket::VideoSendParameters parameters;
+  parameters.codecs.push_back(kVp8Codec);
+  parameters.codecs.push_back(kVp9Codec);
+  EXPECT_TRUE(channel_->SetSendParameters(parameters));
+
+  webrtc::RtpParameters rtp_parameters = channel_->GetRtpParameters(last_ssrc_);
+  ASSERT_EQ(2u, rtp_parameters.codecs.size());
+  EXPECT_EQ(kVp8Codec.id, rtp_parameters.codecs[0].payload_type);
+  EXPECT_EQ(kVp8Codec.name, rtp_parameters.codecs[0].mime_type);
+  EXPECT_EQ(kVp8Codec.clockrate, rtp_parameters.codecs[0].clock_rate);
+  EXPECT_EQ(1, rtp_parameters.codecs[0].channels);
+  EXPECT_EQ(kVp9Codec.id, rtp_parameters.codecs[1].payload_type);
+  EXPECT_EQ(kVp9Codec.name, rtp_parameters.codecs[1].mime_type);
+  EXPECT_EQ(kVp9Codec.clockrate, rtp_parameters.codecs[1].clock_rate);
+  EXPECT_EQ(1, rtp_parameters.codecs[1].channels);
+}
+
+// Test that if we set/get parameters multiple times, we get the same results.
+TEST_F(WebRtcVideoChannel2Test, SetAndGetRtpParameters) {
+  AddSendStream();
+  cricket::VideoSendParameters parameters;
+  parameters.codecs.push_back(kVp8Codec);
+  parameters.codecs.push_back(kVp9Codec);
+  EXPECT_TRUE(channel_->SetSendParameters(parameters));
+
+  webrtc::RtpParameters initial_params = channel_->GetRtpParameters(last_ssrc_);
+
+  // We should be able to set the params we just got.
+  EXPECT_TRUE(channel_->SetRtpParameters(last_ssrc_, initial_params));
+
+  // ... And this shouldn't change the params returned by GetRtpParameters.
+  EXPECT_EQ(initial_params, channel_->GetRtpParameters(last_ssrc_));
+}
+
 void WebRtcVideoChannel2Test::TestReceiverLocalSsrcConfiguration(
     bool receiver_first) {
   EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
diff --git a/media/engine/webrtcvoiceengine.cc b/media/engine/webrtcvoiceengine.cc
index c6cda5e..8561aa2 100644
--- a/media/engine/webrtcvoiceengine.cc
+++ b/media/engine/webrtcvoiceengine.cc
@@ -1411,7 +1411,13 @@
     return webrtc::RtpParameters();
   }
 
-  return it->second->rtp_parameters();
+  webrtc::RtpParameters rtp_params = it->second->rtp_parameters();
+  // Need to add the common list of codecs to the send stream-specific
+  // RTP parameters.
+  for (const AudioCodec& codec : send_codecs_) {
+    rtp_params.codecs.push_back(codec.ToCodecParameters());
+  }
+  return rtp_params;
 }
 
 bool WebRtcVoiceMediaChannel::SetRtpParameters(
@@ -1432,7 +1438,10 @@
     LOG(LS_WARNING) << "Failed to set RtpParameters.";
     return false;
   }
-  it->second->set_rtp_parameters(parameters);
+  // Codecs are handled at the WebRtcVoiceMediaChannel level.
+  webrtc::RtpParameters reduced_params = parameters;
+  reduced_params.codecs.clear();
+  it->second->set_rtp_parameters(reduced_params);
   return true;
 }
 
@@ -1663,6 +1672,7 @@
     }
   }
 
+  send_codecs_ = codecs;
   return true;
 }
 
@@ -2390,6 +2400,8 @@
     int channel,
     const webrtc::RtpParameters& parameters) {
   RTC_CHECK_EQ(1UL, parameters.encodings.size());
+  // TODO(deadbeef): Handle setting parameters with a list of codecs in a
+  // different order (which should change the send codec).
   return SetSendBitrate(
       channel,
       MinPositive(send_bitrate_bps_, parameters.encodings[0].max_bitrate_bps));
diff --git a/media/engine/webrtcvoiceengine.h b/media/engine/webrtcvoiceengine.h
index c59fcaa..4c53ad0 100644
--- a/media/engine/webrtcvoiceengine.h
+++ b/media/engine/webrtcvoiceengine.h
@@ -240,6 +240,7 @@
   rtc::ThreadChecker worker_thread_checker_;
 
   WebRtcVoiceEngine* const engine_ = nullptr;
+  std::vector<AudioCodec> send_codecs_;
   std::vector<AudioCodec> recv_codecs_;
   int send_bitrate_bps_ = 0;
   AudioOptions options_;
diff --git a/media/engine/webrtcvoiceengine_unittest.cc b/media/engine/webrtcvoiceengine_unittest.cc
index 60aa869..d343726 100644
--- a/media/engine/webrtcvoiceengine_unittest.cc
+++ b/media/engine/webrtcvoiceengine_unittest.cc
@@ -918,6 +918,44 @@
   EXPECT_EQ(64000, GetCodecBitrate(kSsrcs4[2]));
 }
 
+// Test that GetRtpParameters returns the currently configured codecs.
+TEST_F(WebRtcVoiceEngineTestFake, GetRtpParametersCodecs) {
+  EXPECT_TRUE(SetupSendStream());
+  cricket::AudioSendParameters parameters;
+  parameters.codecs.push_back(kIsacCodec);
+  parameters.codecs.push_back(kPcmuCodec);
+  EXPECT_TRUE(channel_->SetSendParameters(parameters));
+
+  webrtc::RtpParameters rtp_parameters = channel_->GetRtpParameters(kSsrc1);
+  ASSERT_EQ(2u, rtp_parameters.codecs.size());
+  EXPECT_EQ(kIsacCodec.id, rtp_parameters.codecs[0].payload_type);
+  EXPECT_EQ(kIsacCodec.name, rtp_parameters.codecs[0].mime_type);
+  EXPECT_EQ(kIsacCodec.clockrate, rtp_parameters.codecs[0].clock_rate);
+  EXPECT_EQ(kIsacCodec.channels, rtp_parameters.codecs[0].channels);
+  EXPECT_EQ(kPcmuCodec.id, rtp_parameters.codecs[1].payload_type);
+  EXPECT_EQ(kPcmuCodec.name, rtp_parameters.codecs[1].mime_type);
+  EXPECT_EQ(kPcmuCodec.clockrate, rtp_parameters.codecs[1].clock_rate);
+  EXPECT_EQ(kPcmuCodec.channels, rtp_parameters.codecs[1].channels);
+}
+
+// Test that if we set/get parameters multiple times, we get the same results.
+TEST_F(WebRtcVoiceEngineTestFake, SetAndGetRtpParameters) {
+  EXPECT_TRUE(SetupSendStream());
+  cricket::AudioSendParameters parameters;
+  parameters.codecs.push_back(kIsacCodec);
+  parameters.codecs.push_back(kPcmuCodec);
+  EXPECT_TRUE(channel_->SetSendParameters(parameters));
+
+  webrtc::RtpParameters initial_params = channel_->GetRtpParameters(kSsrc1);
+
+  // We should be able to set the params we just got.
+  EXPECT_TRUE(channel_->SetRtpParameters(kSsrc1, initial_params));
+
+  // ... And this shouldn't change the params returned by GetRtpParameters.
+  webrtc::RtpParameters new_params = channel_->GetRtpParameters(kSsrc1);
+  EXPECT_EQ(initial_params, channel_->GetRtpParameters(kSsrc1));
+}
+
 // Test that we apply codecs properly.
 TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) {
   EXPECT_TRUE(SetupSendStream());