Android: Generate JNI code for RtpReceiver and PeerConnection.Observer

Bug: webrtc:8278
Change-Id: Ief62c37dd6820c2eb1ce94e37e0a61dd8726caae
Reviewed-on: https://webrtc-review.googlesource.com/28621
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21035}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index c7427da..cfaf0a4 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -298,9 +298,11 @@
     "api/org/webrtc/MediaStreamTrack.java",
     "api/org/webrtc/NetworkMonitor.java",
     "api/org/webrtc/NetworkMonitorAutoDetect.java",
+    "api/org/webrtc/PeerConnection.java",
     "api/org/webrtc/RTCStats.java",
     "api/org/webrtc/RTCStatsCollectorCallback.java",
     "api/org/webrtc/RTCStatsReport.java",
+    "api/org/webrtc/RtpReceiver.java",
     "api/org/webrtc/StatsObserver.java",
     "api/org/webrtc/StatsReport.java",
   ]
@@ -334,9 +336,8 @@
     "src/jni/pc/peerconnectionobserver_jni.h",
     "src/jni/pc/rtcstatscollectorcallbackwrapper.cc",
     "src/jni/pc/rtcstatscollectorcallbackwrapper.h",
-    "src/jni/pc/rtpreceiver_jni.cc",
-    "src/jni/pc/rtpreceiverobserver_jni.cc",
-    "src/jni/pc/rtpreceiverobserver_jni.h",
+    "src/jni/pc/rtpreceiver.cc",
+    "src/jni/pc/rtpreceiver.h",
     "src/jni/pc/rtpsender_jni.cc",
     "src/jni/pc/sdpobserver_jni.h",
     "src/jni/pc/statsobserver_jni.cc",
diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java
index 9bc4ebf..24425f0 100644
--- a/sdk/android/api/org/webrtc/PeerConnection.java
+++ b/sdk/android/api/org/webrtc/PeerConnection.java
@@ -22,7 +22,16 @@
  */
 public class PeerConnection {
   /** Tracks PeerConnectionInterface::IceGatheringState */
-  public enum IceGatheringState { NEW, GATHERING, COMPLETE }
+  public enum IceGatheringState {
+    NEW,
+    GATHERING,
+    COMPLETE;
+
+    @CalledByNative("IceGatheringState")
+    static IceGatheringState fromNativeIndex(int nativeIndex) {
+      return values()[nativeIndex];
+    }
+  }
 
   /** Tracks PeerConnectionInterface::IceConnectionState */
   public enum IceConnectionState {
@@ -32,7 +41,12 @@
     COMPLETED,
     FAILED,
     DISCONNECTED,
-    CLOSED
+    CLOSED;
+
+    @CalledByNative("IceConnectionState")
+    static IceConnectionState fromNativeIndex(int nativeIndex) {
+      return values()[nativeIndex];
+    }
   }
 
   /** Tracks PeerConnectionInterface::TlsCertPolicy */
@@ -48,46 +62,51 @@
     HAVE_LOCAL_PRANSWER,
     HAVE_REMOTE_OFFER,
     HAVE_REMOTE_PRANSWER,
-    CLOSED
+    CLOSED;
+
+    @CalledByNative("SignalingState")
+    static SignalingState fromNativeIndex(int nativeIndex) {
+      return values()[nativeIndex];
+    }
   }
 
   /** Java version of PeerConnectionObserver. */
   public static interface Observer {
     /** Triggered when the SignalingState changes. */
-    public void onSignalingChange(SignalingState newState);
+    @CalledByNative("Observer") void onSignalingChange(SignalingState newState);
 
     /** Triggered when the IceConnectionState changes. */
-    public void onIceConnectionChange(IceConnectionState newState);
+    @CalledByNative("Observer") void onIceConnectionChange(IceConnectionState newState);
 
     /** Triggered when the ICE connection receiving status changes. */
-    public void onIceConnectionReceivingChange(boolean receiving);
+    @CalledByNative("Observer") void onIceConnectionReceivingChange(boolean receiving);
 
     /** Triggered when the IceGatheringState changes. */
-    public void onIceGatheringChange(IceGatheringState newState);
+    @CalledByNative("Observer") void onIceGatheringChange(IceGatheringState newState);
 
     /** Triggered when a new ICE candidate has been found. */
-    public void onIceCandidate(IceCandidate candidate);
+    @CalledByNative("Observer") void onIceCandidate(IceCandidate candidate);
 
     /** Triggered when some ICE candidates have been removed. */
-    public void onIceCandidatesRemoved(IceCandidate[] candidates);
+    @CalledByNative("Observer") void onIceCandidatesRemoved(IceCandidate[] candidates);
 
     /** Triggered when media is received on a new stream from remote peer. */
-    public void onAddStream(MediaStream stream);
+    @CalledByNative("Observer") void onAddStream(MediaStream stream);
 
     /** Triggered when a remote peer close a stream. */
-    public void onRemoveStream(MediaStream stream);
+    @CalledByNative("Observer") void onRemoveStream(MediaStream stream);
 
     /** Triggered when a remote peer opens a DataChannel. */
-    public void onDataChannel(DataChannel dataChannel);
+    @CalledByNative("Observer") void onDataChannel(DataChannel dataChannel);
 
     /** Triggered when renegotiation is necessary. */
-    public void onRenegotiationNeeded();
+    @CalledByNative("Observer") void onRenegotiationNeeded();
 
     /**
      * Triggered when a new track is signaled by the remote peer, as a result of
      * setRemoteDescription.
      */
-    public void onAddTrack(RtpReceiver receiver, MediaStream[] mediaStreams);
+    @CalledByNative("Observer") void onAddTrack(RtpReceiver receiver, MediaStream[] mediaStreams);
   }
 
   /** Java version of PeerConnectionInterface.IceServer. */
@@ -369,19 +388,19 @@
   public native void setAudioRecording(boolean recording);
 
   public boolean setConfiguration(RTCConfiguration config) {
-    return nativeSetConfiguration(config, nativeObserver);
+    return setNativeConfiguration(config, nativeObserver);
   }
 
   public boolean addIceCandidate(IceCandidate candidate) {
-    return nativeAddIceCandidate(candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp);
+    return addNativeIceCandidate(candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp);
   }
 
   public boolean removeIceCandidates(final IceCandidate[] candidates) {
-    return nativeRemoveIceCandidates(candidates);
+    return removeNativeIceCandidates(candidates);
   }
 
   public boolean addStream(MediaStream stream) {
-    boolean ret = nativeAddLocalStream(stream.nativeStream);
+    boolean ret = addNativeLocalStream(stream.nativeStream);
     if (!ret) {
       return false;
     }
@@ -390,7 +409,7 @@
   }
 
   public void removeStream(MediaStream stream) {
-    nativeRemoveLocalStream(stream.nativeStream);
+    removeNativeLocalStream(stream.nativeStream);
     localStreams.remove(stream);
   }
 
@@ -432,7 +451,7 @@
    * @return          A new RtpSender object if successful, or null otherwise.
    */
   public RtpSender createSender(String kind, String stream_id) {
-    RtpSender new_sender = nativeCreateSender(kind, stream_id);
+    RtpSender new_sender = createNativeSender(kind, stream_id);
     if (new_sender != null) {
       senders.add(new_sender);
     }
@@ -445,7 +464,7 @@
     for (RtpSender sender : senders) {
       sender.dispose();
     }
-    senders = nativeGetSenders();
+    senders = getNativeSenders();
     return Collections.unmodifiableList(senders);
   }
 
@@ -453,20 +472,20 @@
     for (RtpReceiver receiver : receivers) {
       receiver.dispose();
     }
-    receivers = nativeGetReceivers();
+    receivers = getNativeReceivers();
     return Collections.unmodifiableList(receivers);
   }
 
   // Older, non-standard implementation of getStats.
   @Deprecated
   public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
-    return nativeOldGetStats(observer, (track == null) ? 0 : track.nativeTrack);
+    return oldGetNativeStats(observer, (track == null) ? 0 : track.nativeTrack);
   }
 
   // Gets stats using the new stats collection API, see webrtc/api/stats/. These
   // will replace old stats collection API when the new API has matured enough.
   public void getStats(RTCStatsCollectorCallback callback) {
-    nativeNewGetStats(callback);
+    newGetNativeStats(callback);
   }
 
   // Limits the bandwidth allocated for all RTP streams sent by this
@@ -479,13 +498,13 @@
   // continue until the stopRtcEventLog function is called. The max_size_bytes
   // argument is ignored, it is added for future use.
   public boolean startRtcEventLog(int file_descriptor, int max_size_bytes) {
-    return nativeStartRtcEventLog(file_descriptor, max_size_bytes);
+    return startNativeRtcEventLog(file_descriptor, max_size_bytes);
   }
 
   // Stops recording an RTC event log. If no RTC event log is currently being
   // recorded, this call will have no effect.
   public void stopRtcEventLog() {
-    nativeStopRtcEventLog();
+    stopNativeRtcEventLog();
   }
 
   // TODO(fischman): add support for DTMF-related methods once that API
@@ -517,7 +536,7 @@
   public void dispose() {
     close();
     for (MediaStream stream : localStreams) {
-      nativeRemoveLocalStream(stream.nativeStream);
+      removeNativeLocalStream(stream.nativeStream);
       stream.dispose();
     }
     localStreams.clear();
@@ -535,28 +554,28 @@
 
   private static native void freeObserver(long nativeObserver);
 
-  public native boolean nativeSetConfiguration(RTCConfiguration config, long nativeObserver);
+  private native boolean setNativeConfiguration(RTCConfiguration config, long nativeObserver);
 
-  private native boolean nativeAddIceCandidate(
+  private native boolean addNativeIceCandidate(
       String sdpMid, int sdpMLineIndex, String iceCandidateSdp);
 
-  private native boolean nativeRemoveIceCandidates(final IceCandidate[] candidates);
+  private native boolean removeNativeIceCandidates(final IceCandidate[] candidates);
 
-  private native boolean nativeAddLocalStream(long nativeStream);
+  private native boolean addNativeLocalStream(long nativeStream);
 
-  private native void nativeRemoveLocalStream(long nativeStream);
+  private native void removeNativeLocalStream(long nativeStream);
 
-  private native boolean nativeOldGetStats(StatsObserver observer, long nativeTrack);
+  private native boolean oldGetNativeStats(StatsObserver observer, long nativeTrack);
 
-  private native void nativeNewGetStats(RTCStatsCollectorCallback callback);
+  private native void newGetNativeStats(RTCStatsCollectorCallback callback);
 
-  private native RtpSender nativeCreateSender(String kind, String stream_id);
+  private native RtpSender createNativeSender(String kind, String stream_id);
 
-  private native List<RtpSender> nativeGetSenders();
+  private native List<RtpSender> getNativeSenders();
 
-  private native List<RtpReceiver> nativeGetReceivers();
+  private native List<RtpReceiver> getNativeReceivers();
 
-  private native boolean nativeStartRtcEventLog(int file_descriptor, int max_size_bytes);
+  private native boolean startNativeRtcEventLog(int file_descriptor, int max_size_bytes);
 
-  private native void nativeStopRtcEventLog();
+  private native void stopNativeRtcEventLog();
 }
diff --git a/sdk/android/api/org/webrtc/RtpReceiver.java b/sdk/android/api/org/webrtc/RtpReceiver.java
index 69dfd92..ac29695 100644
--- a/sdk/android/api/org/webrtc/RtpReceiver.java
+++ b/sdk/android/api/org/webrtc/RtpReceiver.java
@@ -10,11 +10,14 @@
 
 package org.webrtc;
 
+import org.webrtc.MediaStreamTrack;
+
 /** Java wrapper for a C++ RtpReceiverInterface. */
 public class RtpReceiver {
   /** Java wrapper for a C++ RtpReceiverObserverInterface*/
   public static interface Observer {
     // Called when the first audio or video packet is received.
+    @CalledByNative("Observer")
     public void onFirstPacketReceived(MediaStreamTrack.MediaType media_type);
   }
 
@@ -23,9 +26,10 @@
 
   private MediaStreamTrack cachedTrack;
 
+  @CalledByNative
   public RtpReceiver(long nativeRtpReceiver) {
     this.nativeRtpReceiver = nativeRtpReceiver;
-    long track = nativeGetTrack(nativeRtpReceiver);
+    long track = getNativeTrack(nativeRtpReceiver);
     // We can assume that an RtpReceiver always has an associated track.
     cachedTrack = new MediaStreamTrack(track);
   }
@@ -35,21 +39,22 @@
   }
 
   public boolean setParameters(RtpParameters parameters) {
-    return nativeSetParameters(nativeRtpReceiver, parameters);
+    return parameters == null ? false : setNativeParameters(nativeRtpReceiver, parameters);
   }
 
   public RtpParameters getParameters() {
-    return nativeGetParameters(nativeRtpReceiver);
+    return getNativeParameters(nativeRtpReceiver);
   }
 
   public String id() {
-    return nativeId(nativeRtpReceiver);
+    return getNativeId(nativeRtpReceiver);
   }
 
+  @CalledByNative
   public void dispose() {
     cachedTrack.dispose();
     if (nativeObserver != 0) {
-      nativeUnsetObserver(nativeRtpReceiver, nativeObserver);
+      unsetNativeObserver(nativeRtpReceiver, nativeObserver);
       nativeObserver = 0;
     }
     JniCommon.nativeReleaseRef(nativeRtpReceiver);
@@ -58,23 +63,23 @@
   public void SetObserver(Observer observer) {
     // Unset the existing one before setting a new one.
     if (nativeObserver != 0) {
-      nativeUnsetObserver(nativeRtpReceiver, nativeObserver);
+      unsetNativeObserver(nativeRtpReceiver, nativeObserver);
     }
-    nativeObserver = nativeSetObserver(nativeRtpReceiver, observer);
+    nativeObserver = setNativeObserver(nativeRtpReceiver, observer);
   }
 
   // This should increment the reference count of the track.
   // Will be released in dispose().
-  private static native long nativeGetTrack(long nativeRtpReceiver);
+  private static native long getNativeTrack(long nativeRtpReceiver);
 
-  private static native boolean nativeSetParameters(
+  private static native boolean setNativeParameters(
       long nativeRtpReceiver, RtpParameters parameters);
 
-  private static native RtpParameters nativeGetParameters(long nativeRtpReceiver);
+  private static native RtpParameters getNativeParameters(long nativeRtpReceiver);
 
-  private static native String nativeId(long nativeRtpReceiver);
+  private static native String getNativeId(long nativeRtpReceiver);
 
-  private static native long nativeSetObserver(long nativeRtpReceiver, Observer observer);
+  private static native long setNativeObserver(long nativeRtpReceiver, Observer observer);
 
-  private static native long nativeUnsetObserver(long nativeRtpReceiver, long nativeObserver);
+  private static native void unsetNativeObserver(long nativeRtpReceiver, long nativeObserver);
 };
diff --git a/sdk/android/src/jni/jni_helpers.h b/sdk/android/src/jni/jni_helpers.h
index bfef3a8..c0982df 100644
--- a/sdk/android/src/jni/jni_helpers.h
+++ b/sdk/android/src/jni/jni_helpers.h
@@ -155,14 +155,22 @@
  public:
   ScopedGlobalRef(JNIEnv* jni, T obj)
       : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
+
+  ScopedGlobalRef(ScopedGlobalRef&& other) : obj_(other.obj_) {
+    other.obj_ = nullptr;
+  }
+
   ~ScopedGlobalRef() {
-    DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
+    if (obj_) {
+      DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
+    }
   }
   T operator*() const {
     return obj_;
   }
  private:
   T obj_;
+  RTC_DISALLOW_COPY_AND_ASSIGN(ScopedGlobalRef);
 };
 
 // Provides a convenient way to iterate over a Java Iterable using the
diff --git a/sdk/android/src/jni/pc/java_native_conversion.cc b/sdk/android/src/jni/pc/java_native_conversion.cc
index db4f785..f8f0763 100644
--- a/sdk/android/src/jni/pc/java_native_conversion.cc
+++ b/sdk/android/src/jni/pc/java_native_conversion.cc
@@ -471,10 +471,8 @@
   }
 }
 
-void JavaToNativeRtpParameters(JNIEnv* jni,
-                               jobject j_parameters,
-                               RtpParameters* parameters) {
-  RTC_CHECK(parameters != nullptr);
+RtpParameters JavaToNativeRtpParameters(JNIEnv* jni, jobject j_parameters) {
+  RtpParameters parameters;
   jclass parameters_class = jni->FindClass("org/webrtc/RtpParameters");
   jfieldID encodings_id =
       GetFieldID(jni, parameters_class, "encodings", "Ljava/util/List;");
@@ -507,7 +505,7 @@
       CHECK_EXCEPTION(jni) << "error during CallLongMethod";
       encoding.ssrc = ssrc_value;
     }
-    parameters->encodings.push_back(encoding);
+    parameters.encodings.push_back(encoding);
   }
 
   // Convert codecs.
@@ -533,8 +531,9 @@
     jobject j_num_channels =
         GetNullableObjectField(jni, j_codec, num_channels_id);
     codec.num_channels = JavaToNativeOptionalInt(jni, j_num_channels);
-    parameters->codecs.push_back(codec);
+    parameters.codecs.push_back(codec);
   }
+  return parameters;
 }
 
 jobject NativeToJavaRtpParameters(JNIEnv* jni,
diff --git a/sdk/android/src/jni/pc/java_native_conversion.h b/sdk/android/src/jni/pc/java_native_conversion.h
index faa4084..ecdbf1b 100644
--- a/sdk/android/src/jni/pc/java_native_conversion.h
+++ b/sdk/android/src/jni/pc/java_native_conversion.h
@@ -98,9 +98,7 @@
 /*********************************************************
  * RtpParameters, used for RtpSender and RtpReceiver APIs.
  *********************************************************/
-void JavaToNativeRtpParameters(JNIEnv* jni,
-                               jobject j_parameters,
-                               RtpParameters* parameters);
+RtpParameters JavaToNativeRtpParameters(JNIEnv* jni, jobject j_parameters);
 
 jobject NativeToJavaRtpParameters(JNIEnv* jni, const RtpParameters& parameters);
 
diff --git a/sdk/android/src/jni/pc/peerconnection_jni.cc b/sdk/android/src/jni/pc/peerconnection_jni.cc
index c3f2d12..e1c90be 100644
--- a/sdk/android/src/jni/pc/peerconnection_jni.cc
+++ b/sdk/android/src/jni/pc/peerconnection_jni.cc
@@ -168,7 +168,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jboolean,
-                         PeerConnection_nativeSetConfiguration,
+                         PeerConnection_setNativeConfiguration,
                          JNIEnv* jni,
                          jobject j_pc,
                          jobject j_rtc_config,
@@ -185,7 +185,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jboolean,
-                         PeerConnection_nativeAddIceCandidate,
+                         PeerConnection_addNativeIceCandidate,
                          JNIEnv* jni,
                          jobject j_pc,
                          jstring j_sdp_mid,
@@ -199,7 +199,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jboolean,
-                         PeerConnection_nativeRemoveIceCandidates,
+                         PeerConnection_removeNativeIceCandidates,
                          JNIEnv* jni,
                          jobject j_pc,
                          jobjectArray j_candidates) {
@@ -213,7 +213,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jboolean,
-                         PeerConnection_nativeAddLocalStream,
+                         PeerConnection_addNativeLocalStream,
                          JNIEnv* jni,
                          jobject j_pc,
                          jlong native_stream) {
@@ -222,7 +222,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(void,
-                         PeerConnection_nativeRemoveLocalStream,
+                         PeerConnection_removeNativeLocalStream,
                          JNIEnv* jni,
                          jobject j_pc,
                          jlong native_stream) {
@@ -231,7 +231,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jobject,
-                         PeerConnection_nativeCreateSender,
+                         PeerConnection_createNativeSender,
                          JNIEnv* jni,
                          jobject j_pc,
                          jstring j_kind,
@@ -258,7 +258,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jobject,
-                         PeerConnection_nativeGetSenders,
+                         PeerConnection_getNativeSenders,
                          JNIEnv* jni,
                          jobject j_pc) {
   jclass j_array_list_class = FindClass(jni, "java/util/ArrayList");
@@ -289,7 +289,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(jobject,
-                         PeerConnection_nativeGetReceivers,
+                         PeerConnection_getNativeReceivers,
                          JNIEnv* jni,
                          jobject j_pc) {
   jclass j_array_list_class = FindClass(jni, "java/util/ArrayList");
@@ -300,18 +300,9 @@
   jobject j_receivers = jni->NewObject(j_array_list_class, j_array_list_ctor);
   CHECK_EXCEPTION(jni) << "error during NewObject";
 
-  jclass j_rtp_receiver_class = FindClass(jni, "org/webrtc/RtpReceiver");
-  jmethodID j_rtp_receiver_ctor =
-      GetMethodID(jni, j_rtp_receiver_class, "<init>", "(J)V");
-
   auto receivers = ExtractNativePC(jni, j_pc)->GetReceivers();
   for (const auto& receiver : receivers) {
-    jlong nativeReceiverPtr = jlongFromPointer(receiver.get());
-    jobject j_receiver = jni->NewObject(j_rtp_receiver_class,
-                                        j_rtp_receiver_ctor, nativeReceiverPtr);
-    CHECK_EXCEPTION(jni) << "error during NewObject";
-    // Receiver is now owned by Java object, and will be freed from there.
-    receiver->AddRef();
+    jobject j_receiver = NativeToJavaRtpReceiver(jni, receiver);
     jni->CallBooleanMethod(j_receivers, j_array_list_add, j_receiver);
     CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
   }
@@ -319,7 +310,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(bool,
-                         PeerConnection_nativeOldGetStats,
+                         PeerConnection_oldGetNativeStats,
                          JNIEnv* jni,
                          jobject j_pc,
                          jobject j_observer,
@@ -332,7 +323,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(void,
-                         PeerConnection_nativeNewGetStats,
+                         PeerConnection_newGetNativeStats,
                          JNIEnv* jni,
                          jobject j_pc,
                          jobject j_callback) {
@@ -357,7 +348,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(bool,
-                         PeerConnection_nativeStartRtcEventLog,
+                         PeerConnection_startNativeRtcEventLog,
                          JNIEnv* jni,
                          jobject j_pc,
                          int file_descriptor,
@@ -367,7 +358,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(void,
-                         PeerConnection_nativeStopRtcEventLog,
+                         PeerConnection_stopNativeRtcEventLog,
                          JNIEnv* jni,
                          jobject j_pc) {
   ExtractNativePC(jni, j_pc)->StopRtcEventLog();
diff --git a/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc b/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
index 4ad107e..db5b3dd 100644
--- a/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
+++ b/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
@@ -15,6 +15,7 @@
 
 #include "rtc_base/ptr_util.h"
 #include "sdk/android/generated_peerconnection_jni/jni/MediaStream_jni.h"
+#include "sdk/android/generated_peerconnection_jni/jni/PeerConnection_jni.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
 #include "sdk/android/src/jni/jni_helpers.h"
 #include "sdk/android/src/jni/pc/datachannel.h"
@@ -31,87 +32,68 @@
 
 PeerConnectionObserverJni::PeerConnectionObserverJni(JNIEnv* jni,
                                                      jobject j_observer)
-    : j_observer_global_(jni, j_observer),
-      j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
-      j_rtp_receiver_class_(jni, FindClass(jni, "org/webrtc/RtpReceiver")),
-      j_rtp_receiver_ctor_(
-          GetMethodID(jni, *j_rtp_receiver_class_, "<init>", "(J)V")) {}
+    : j_observer_global_(jni, j_observer) {}
 
 PeerConnectionObserverJni::~PeerConnectionObserverJni() {
   ScopedLocalRefFrame local_ref_frame(jni());
   while (!remote_streams_.empty())
     DisposeRemoteStream(remote_streams_.begin());
-  while (!rtp_receivers_.empty())
-    DisposeRtpReceiver(rtp_receivers_.begin());
 }
 
 void PeerConnectionObserverJni::OnIceCandidate(
     const IceCandidateInterface* candidate) {
   JNIEnv* env = AttachCurrentThreadIfNeeded();
   ScopedLocalRefFrame local_ref_frame(env);
-  jobject j_candidate = NativeToJavaIceCandidate(env, *candidate);
-
-  jmethodID m = GetMethodID(env, *j_observer_class_, "onIceCandidate",
-                            "(Lorg/webrtc/IceCandidate;)V");
-  env->CallVoidMethod(*j_observer_global_, m, j_candidate);
-  CHECK_EXCEPTION(env) << "error during CallVoidMethod";
+  Java_Observer_onIceCandidate(env, *j_observer_global_,
+                               NativeToJavaIceCandidate(env, *candidate));
 }
 
 void PeerConnectionObserverJni::OnIceCandidatesRemoved(
     const std::vector<cricket::Candidate>& candidates) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jobjectArray candidates_array = NativeToJavaCandidateArray(jni(), candidates);
-  jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidatesRemoved",
-                            "([Lorg/webrtc/IceCandidate;)V");
-  jni()->CallVoidMethod(*j_observer_global_, m, candidates_array);
-  CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onIceCandidatesRemoved(
+      env, *j_observer_global_, NativeToJavaCandidateArray(env, candidates));
 }
 
 void PeerConnectionObserverJni::OnSignalingChange(
     PeerConnectionInterface::SignalingState new_state) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSignalingChange",
-                            "(Lorg/webrtc/PeerConnection$SignalingState;)V");
-  jobject new_state_enum = JavaEnumFromIndexAndClassName(
-      jni(), "PeerConnection$SignalingState", new_state);
-  jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onSignalingChange(
+      env, *j_observer_global_,
+      Java_SignalingState_fromNativeIndex(env, new_state));
 }
 
 void PeerConnectionObserverJni::OnIceConnectionChange(
     PeerConnectionInterface::IceConnectionState new_state) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jmethodID m =
-      GetMethodID(jni(), *j_observer_class_, "onIceConnectionChange",
-                  "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
-  jobject new_state_enum = JavaEnumFromIndexAndClassName(
-      jni(), "PeerConnection$IceConnectionState", new_state);
-  jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onIceConnectionChange(
+      env, *j_observer_global_,
+      Java_IceConnectionState_fromNativeIndex(env, new_state));
 }
 
 void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jmethodID m = GetMethodID(jni(), *j_observer_class_,
-                            "onIceConnectionReceivingChange", "(Z)V");
-  jni()->CallVoidMethod(*j_observer_global_, m, receiving);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onIceConnectionReceivingChange(env, *j_observer_global_,
+                                               receiving);
 }
 
 void PeerConnectionObserverJni::OnIceGatheringChange(
     PeerConnectionInterface::IceGatheringState new_state) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceGatheringChange",
-                            "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
-  jobject new_state_enum = JavaEnumFromIndexAndClassName(
-      jni(), "PeerConnection$IceGatheringState", new_state);
-  jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onIceGatheringChange(
+      env, *j_observer_global_,
+      Java_IceGatheringState_fromNativeIndex(env, new_state));
 }
 
 void PeerConnectionObserverJni::OnAddStream(
     rtc::scoped_refptr<MediaStreamInterface> stream) {
-  ScopedLocalRefFrame local_ref_frame(jni());
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
   // The stream could be added into the remote_streams_ map when calling
   // OnAddTrack.
   jobject j_stream = GetOrCreateJavaStream(stream);
@@ -123,10 +105,7 @@
     AddNativeVideoTrackToJavaStream(track, j_stream);
   }
 
-  jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
-                            "(Lorg/webrtc/MediaStream;)V");
-  jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  Java_Observer_onAddStream(env, *j_observer_global_, j_stream);
 
   // Create an observer to update the Java stream when the native stream's set
   // of tracks changes.
@@ -194,15 +173,12 @@
 
 void PeerConnectionObserverJni::OnRemoveStream(
     rtc::scoped_refptr<MediaStreamInterface> stream) {
-  ScopedLocalRefFrame local_ref_frame(jni());
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
   NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
   RTC_CHECK(it != remote_streams_.end())
       << "unexpected stream: " << std::hex << stream;
-  jobject j_stream = it->second;
-  jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
-                            "(Lorg/webrtc/MediaStream;)V");
-  jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  Java_Observer_onRemoveStream(env, *j_observer_global_, it->second);
 
   // Release the refptr reference so that DisposeRemoteStream can assert
   // it removes the final reference.
@@ -214,38 +190,26 @@
     rtc::scoped_refptr<DataChannelInterface> channel) {
   JNIEnv* env = AttachCurrentThreadIfNeeded();
   ScopedLocalRefFrame local_ref_frame(env);
-  jobject j_channel = WrapNativeDataChannel(env, channel);
-  jmethodID m = GetMethodID(env, *j_observer_class_, "onDataChannel",
-                            "(Lorg/webrtc/DataChannel;)V");
-  env->CallVoidMethod(*j_observer_global_, m, j_channel);
-  CHECK_EXCEPTION(env) << "error during CallVoidMethod";
+  Java_Observer_onDataChannel(env, *j_observer_global_,
+                              WrapNativeDataChannel(env, channel));
 }
 
 void PeerConnectionObserverJni::OnRenegotiationNeeded() {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jmethodID m =
-      GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
-  jni()->CallVoidMethod(*j_observer_global_, m);
-  CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  Java_Observer_onRenegotiationNeeded(env, *j_observer_global_);
 }
 
 void PeerConnectionObserverJni::OnAddTrack(
     rtc::scoped_refptr<RtpReceiverInterface> receiver,
     const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {
-  ScopedLocalRefFrame local_ref_frame(jni());
-  jobject j_rtp_receiver =
-      jni()->NewObject(*j_rtp_receiver_class_, j_rtp_receiver_ctor_,
-                       jlongFromPointer(receiver.get()));
-  CHECK_EXCEPTION(jni()) << "error during NewObject";
-  receiver->AddRef();
-  rtp_receivers_[receiver] = NewGlobalRef(jni(), j_rtp_receiver);
+  JNIEnv* env = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(env);
+  jobject j_rtp_receiver = NativeToJavaRtpReceiver(env, receiver);
+  rtp_receivers_.emplace_back(env, j_rtp_receiver);
 
-  jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams);
-  jmethodID m =
-      GetMethodID(jni(), *j_observer_class_, "onAddTrack",
-                  "(Lorg/webrtc/RtpReceiver;[Lorg/webrtc/MediaStream;)V");
-  jni()->CallVoidMethod(*j_observer_global_, m, j_rtp_receiver, j_stream_array);
-  CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
+  Java_Observer_onAddTrack(env, *j_observer_global_, j_rtp_receiver,
+                           NativeToJavaMediaStreamArray(env, streams));
 }
 
 void PeerConnectionObserverJni::SetConstraints(
@@ -274,17 +238,6 @@
   DeleteGlobalRef(env, j_stream);
 }
 
-void PeerConnectionObserverJni::DisposeRtpReceiver(
-    const NativeToJavaRtpReceiverMap::iterator& it) {
-  jobject j_rtp_receiver = it->second;
-  rtp_receivers_.erase(it);
-  jni()->CallVoidMethod(
-      j_rtp_receiver,
-      GetMethodID(jni(), *j_rtp_receiver_class_, "dispose", "()V"));
-  CHECK_EXCEPTION(jni()) << "error during RtpReceiver.dispose()";
-  DeleteGlobalRef(jni(), j_rtp_receiver);
-}
-
 // If the NativeToJavaStreamsMap contains the stream, return it.
 // Otherwise, create a new Java MediaStream.
 jobject PeerConnectionObserverJni::GetOrCreateJavaStream(
diff --git a/sdk/android/src/jni/pc/peerconnectionobserver_jni.h b/sdk/android/src/jni/pc/peerconnectionobserver_jni.h
index 6f95a38..46e68cb 100644
--- a/sdk/android/src/jni/pc/peerconnectionobserver_jni.h
+++ b/sdk/android/src/jni/pc/peerconnectionobserver_jni.h
@@ -19,6 +19,7 @@
 #include "api/peerconnectioninterface.h"
 #include "sdk/android/src/jni/jni_helpers.h"
 #include "sdk/android/src/jni/pc/mediaconstraints_jni.h"
+#include "sdk/android/src/jni/pc/rtpreceiver.h"
 
 namespace webrtc {
 namespace jni {
@@ -57,14 +58,12 @@
 
  private:
   typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap;
-  typedef std::map<RtpReceiverInterface*, jobject> NativeToJavaRtpReceiverMap;
   typedef std::map<MediaStreamTrackInterface*, jobject>
       NativeToJavaMediaTrackMap;
   typedef std::map<MediaStreamTrackInterface*, RtpReceiverInterface*>
       NativeMediaStreamTrackToNativeRtpReceiver;
 
   void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it);
-  void DisposeRtpReceiver(const NativeToJavaRtpReceiverMap::iterator& it);
 
   // If the NativeToJavaStreamsMap contains the stream, return it.
   // Otherwise, create a new Java MediaStream.
@@ -100,14 +99,11 @@
                                      MediaStreamInterface* stream);
 
   const ScopedGlobalRef<jobject> j_observer_global_;
-  const ScopedGlobalRef<jclass> j_observer_class_;
-  const ScopedGlobalRef<jclass> j_rtp_receiver_class_;
-  const jmethodID j_rtp_receiver_ctor_;
 
   // C++ -> Java remote streams. The stored jobects are global refs and must be
   // manually deleted upon removal. Use DisposeRemoteStream().
   NativeToJavaStreamsMap remote_streams_;
-  NativeToJavaRtpReceiverMap rtp_receivers_;
+  std::vector<JavaRtpReceiverGlobalOwner> rtp_receivers_;
   std::unique_ptr<MediaConstraintsInterface> constraints_;
   std::vector<std::unique_ptr<webrtc::MediaStreamObserver>> stream_observers_;
 };
diff --git a/sdk/android/src/jni/pc/rtpreceiver.cc b/sdk/android/src/jni/pc/rtpreceiver.cc
new file mode 100644
index 0000000..0381b3d
--- /dev/null
+++ b/sdk/android/src/jni/pc/rtpreceiver.cc
@@ -0,0 +1,137 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#include "sdk/android/src/jni/pc/rtpreceiver.h"
+
+#include "sdk/android/generated_peerconnection_jni/jni/RtpReceiver_jni.h"
+#include "sdk/android/src/jni/jni_helpers.h"
+#include "sdk/android/src/jni/pc/java_native_conversion.h"
+
+namespace webrtc {
+namespace jni {
+
+namespace {
+
+// Adapter between the C++ RtpReceiverObserverInterface and the Java
+// RtpReceiver.Observer interface. Wraps an instance of the Java interface and
+// dispatches C++ callbacks to Java.
+class RtpReceiverObserverJni : public RtpReceiverObserverInterface {
+ public:
+  RtpReceiverObserverJni(JNIEnv* env, jobject j_observer)
+      : j_observer_global_(env, j_observer) {}
+
+  ~RtpReceiverObserverJni() override = default;
+
+  void OnFirstPacketReceived(cricket::MediaType media_type) override {
+    JNIEnv* const env = AttachCurrentThreadIfNeeded();
+    Java_Observer_onFirstPacketReceived(env, *j_observer_global_,
+                                        NativeToJavaMediaType(env, media_type));
+  }
+
+ private:
+  const ScopedGlobalRef<jobject> j_observer_global_;
+};
+
+}  // namespace
+
+jobject NativeToJavaRtpReceiver(
+    JNIEnv* env,
+    rtc::scoped_refptr<RtpReceiverInterface> receiver) {
+  // Receiver is now owned by Java object, and will be freed from there.
+  return Java_RtpReceiver_Constructor(env,
+                                      jlongFromPointer(receiver.release()));
+}
+
+JavaRtpReceiverGlobalOwner::JavaRtpReceiverGlobalOwner(JNIEnv* env,
+                                                       jobject j_receiver)
+    : j_receiver_(env, j_receiver) {}
+
+JavaRtpReceiverGlobalOwner::JavaRtpReceiverGlobalOwner(
+    JavaRtpReceiverGlobalOwner&& other) = default;
+
+JavaRtpReceiverGlobalOwner::~JavaRtpReceiverGlobalOwner() {
+  if (*j_receiver_)
+    Java_RtpReceiver_dispose(AttachCurrentThreadIfNeeded(), *j_receiver_);
+}
+
+JNI_FUNCTION_DECLARATION(jlong,
+                         RtpReceiver_getNativeTrack,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer,
+                         jlong j_track_pointer) {
+  return jlongFromPointer(
+      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
+          ->track()
+          .release());
+}
+
+JNI_FUNCTION_DECLARATION(jboolean,
+                         RtpReceiver_setNativeParameters,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer,
+                         jobject j_parameters) {
+  RtpParameters parameters = JavaToNativeRtpParameters(jni, j_parameters);
+  return reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
+      ->SetParameters(parameters);
+}
+
+JNI_FUNCTION_DECLARATION(jobject,
+                         RtpReceiver_getNativeParameters,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer) {
+  RtpParameters parameters =
+      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
+          ->GetParameters();
+  return NativeToJavaRtpParameters(jni, parameters);
+}
+
+JNI_FUNCTION_DECLARATION(jstring,
+                         RtpReceiver_getNativeId,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer) {
+  return NativeToJavaString(
+      jni,
+      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->id());
+}
+
+JNI_FUNCTION_DECLARATION(jlong,
+                         RtpReceiver_setNativeObserver,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer,
+                         jobject j_observer) {
+  RtpReceiverObserverJni* rtpReceiverObserver =
+      new RtpReceiverObserverJni(jni, j_observer);
+  reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
+      ->SetObserver(rtpReceiverObserver);
+  return jlongFromPointer(rtpReceiverObserver);
+}
+
+JNI_FUNCTION_DECLARATION(void,
+                         RtpReceiver_unsetNativeObserver,
+                         JNIEnv* jni,
+                         jclass,
+                         jlong j_rtp_receiver_pointer,
+                         jlong j_observer_pointer) {
+  reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
+      ->SetObserver(nullptr);
+  RtpReceiverObserverJni* observer =
+      reinterpret_cast<RtpReceiverObserverJni*>(j_observer_pointer);
+  if (observer) {
+    delete observer;
+  }
+}
+
+}  // namespace jni
+}  // namespace webrtc
diff --git a/sdk/android/src/jni/pc/rtpreceiver.h b/sdk/android/src/jni/pc/rtpreceiver.h
new file mode 100644
index 0000000..ec87d7c
--- /dev/null
+++ b/sdk/android/src/jni/pc/rtpreceiver.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+#ifndef SDK_ANDROID_SRC_JNI_PC_RTPRECEIVER_H_
+#define SDK_ANDROID_SRC_JNI_PC_RTPRECEIVER_H_
+
+#include <jni.h>
+
+#include "api/rtpreceiverinterface.h"
+#include "sdk/android/src/jni/jni_helpers.h"
+
+namespace webrtc {
+namespace jni {
+
+jobject NativeToJavaRtpReceiver(
+    JNIEnv* env,
+    rtc::scoped_refptr<RtpReceiverInterface> receiver);
+
+// Takes ownership of the passed |j_receiver| and stores it as a global
+// reference. Will call dispose() in the dtor.
+class JavaRtpReceiverGlobalOwner {
+ public:
+  JavaRtpReceiverGlobalOwner(JNIEnv* env, jobject j_receiver);
+  JavaRtpReceiverGlobalOwner(JavaRtpReceiverGlobalOwner&& other);
+  ~JavaRtpReceiverGlobalOwner();
+
+ private:
+  ScopedGlobalRef<jobject> j_receiver_;
+};
+
+}  // namespace jni
+}  // namespace webrtc
+
+#endif  // SDK_ANDROID_SRC_JNI_PC_RTPRECEIVER_H_
diff --git a/sdk/android/src/jni/pc/rtpreceiver_jni.cc b/sdk/android/src/jni/pc/rtpreceiver_jni.cc
deleted file mode 100644
index eb60cc0..0000000
--- a/sdk/android/src/jni/pc/rtpreceiver_jni.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *  Copyright 2017 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.
- */
-
-#include "api/rtpreceiverinterface.h"
-#include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/pc/java_native_conversion.h"
-#include "sdk/android/src/jni/pc/rtpreceiverobserver_jni.h"
-
-namespace webrtc {
-namespace jni {
-
-JNI_FUNCTION_DECLARATION(jlong,
-                         RtpReceiver_nativeGetTrack,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer,
-                         jlong j_track_pointer) {
-  return jlongFromPointer(
-      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
-          ->track()
-          .release());
-}
-
-JNI_FUNCTION_DECLARATION(jboolean,
-                         RtpReceiver_nativeSetParameters,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer,
-                         jobject j_parameters) {
-  if (IsNull(jni, j_parameters)) {
-    return false;
-  }
-  RtpParameters parameters;
-  JavaToNativeRtpParameters(jni, j_parameters, &parameters);
-  return reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
-      ->SetParameters(parameters);
-}
-
-JNI_FUNCTION_DECLARATION(jobject,
-                         RtpReceiver_nativeGetParameters,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer) {
-  RtpParameters parameters =
-      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
-          ->GetParameters();
-  return NativeToJavaRtpParameters(jni, parameters);
-}
-
-JNI_FUNCTION_DECLARATION(jstring,
-                         RtpReceiver_nativeId,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer) {
-  return NativeToJavaString(
-      jni,
-      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->id());
-}
-
-JNI_FUNCTION_DECLARATION(jlong,
-                         RtpReceiver_nativeSetObserver,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer,
-                         jobject j_observer) {
-  RtpReceiverObserverJni* rtpReceiverObserver =
-      new RtpReceiverObserverJni(jni, j_observer);
-  reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
-      ->SetObserver(rtpReceiverObserver);
-  return jlongFromPointer(rtpReceiverObserver);
-}
-
-JNI_FUNCTION_DECLARATION(void,
-                         RtpReceiver_nativeUnsetObserver,
-                         JNIEnv* jni,
-                         jclass,
-                         jlong j_rtp_receiver_pointer,
-                         jlong j_observer_pointer) {
-  reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
-      ->SetObserver(nullptr);
-  RtpReceiverObserverJni* observer =
-      reinterpret_cast<RtpReceiverObserverJni*>(j_observer_pointer);
-  if (observer) {
-    delete observer;
-  }
-}
-
-}  // namespace jni
-}  // namespace webrtc
diff --git a/sdk/android/src/jni/pc/rtpreceiverobserver_jni.cc b/sdk/android/src/jni/pc/rtpreceiverobserver_jni.cc
deleted file mode 100644
index 8e90063..0000000
--- a/sdk/android/src/jni/pc/rtpreceiverobserver_jni.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  Copyright 2017 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.
- */
-
-#include "sdk/android/src/jni/pc/rtpreceiverobserver_jni.h"
-
-#include "sdk/android/src/jni/pc/java_native_conversion.h"
-
-namespace webrtc {
-namespace jni {
-
-void RtpReceiverObserverJni::OnFirstPacketReceived(
-    cricket::MediaType media_type) {
-  JNIEnv* const jni = AttachCurrentThreadIfNeeded();
-
-  jmethodID j_on_first_packet_received_mid = GetMethodID(
-      jni, GetObjectClass(jni, *j_observer_global_), "onFirstPacketReceived",
-      "(Lorg/webrtc/MediaStreamTrack$MediaType;)V");
-  // Get the Java version of media type.
-  jobject JavaMediaType = NativeToJavaMediaType(jni, media_type);
-  // Trigger the callback function.
-  jni->CallVoidMethod(*j_observer_global_, j_on_first_packet_received_mid,
-                      JavaMediaType);
-  CHECK_EXCEPTION(jni) << "error during CallVoidMethod";
-}
-
-}  // namespace jni
-}  // namespace webrtc
diff --git a/sdk/android/src/jni/pc/rtpreceiverobserver_jni.h b/sdk/android/src/jni/pc/rtpreceiverobserver_jni.h
deleted file mode 100644
index c645533..0000000
--- a/sdk/android/src/jni/pc/rtpreceiverobserver_jni.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Copyright 2017 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.
- */
-
-#ifndef SDK_ANDROID_SRC_JNI_PC_RTPRECEIVEROBSERVER_JNI_H_
-#define SDK_ANDROID_SRC_JNI_PC_RTPRECEIVEROBSERVER_JNI_H_
-
-#include "api/rtpreceiverinterface.h"
-#include "sdk/android/src/jni/jni_helpers.h"
-
-namespace webrtc {
-namespace jni {
-
-// Adapter between the C++ RtpReceiverObserverInterface and the Java
-// RtpReceiver.Observer interface. Wraps an instance of the Java interface and
-// dispatches C++ callbacks to Java.
-class RtpReceiverObserverJni : public RtpReceiverObserverInterface {
- public:
-  RtpReceiverObserverJni(JNIEnv* jni, jobject j_observer)
-      : j_observer_global_(jni, j_observer) {}
-
-  ~RtpReceiverObserverJni() override {}
-
-  void OnFirstPacketReceived(cricket::MediaType media_type) override;
-
- private:
-  const ScopedGlobalRef<jobject> j_observer_global_;
-};
-
-}  // namespace jni
-}  // namespace webrtc
-
-#endif  // SDK_ANDROID_SRC_JNI_PC_RTPRECEIVEROBSERVER_JNI_H_
diff --git a/sdk/android/src/jni/pc/rtpsender_jni.cc b/sdk/android/src/jni/pc/rtpsender_jni.cc
index a30bc6c..7dd34bb 100644
--- a/sdk/android/src/jni/pc/rtpsender_jni.cc
+++ b/sdk/android/src/jni/pc/rtpsender_jni.cc
@@ -56,8 +56,7 @@
   if (IsNull(jni, j_parameters)) {
     return false;
   }
-  RtpParameters parameters;
-  JavaToNativeRtpParameters(jni, j_parameters, &parameters);
+  RtpParameters parameters = JavaToNativeRtpParameters(jni, j_parameters);
   return reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)
       ->SetParameters(parameters);
 }