1/*
2 * libjingle
3 * Copyright 2013 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33//   expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35//   things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36//   the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call.  Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call.  In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
59#include <limits>
60#include <utility>
61
62#include "talk/app/webrtc/java/jni/classreferenceholder.h"
63#include "talk/app/webrtc/java/jni/jni_helpers.h"
64#include "talk/app/webrtc/java/jni/native_handle_impl.h"
65#include "talk/app/webrtc/dtlsidentitystore.h"
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/rtpreceiverinterface.h"
69#include "talk/app/webrtc/rtpsenderinterface.h"
70#include "talk/app/webrtc/videosourceinterface.h"
71#include "talk/media/base/videocapturer.h"
72#include "talk/media/base/videorenderer.h"
73#include "talk/media/devices/videorendererfactory.h"
74#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
75#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
76#include "webrtc/base/bind.h"
77#include "webrtc/base/checks.h"
78#include "webrtc/base/event_tracer.h"
79#include "webrtc/base/logging.h"
80#include "webrtc/base/logsinks.h"
81#include "webrtc/base/messagequeue.h"
82#include "webrtc/base/networkmonitor.h"
83#include "webrtc/base/ssladapter.h"
84#include "webrtc/base/stringutils.h"
85#include "webrtc/system_wrappers/include/field_trial_default.h"
86#include "webrtc/system_wrappers/include/trace.h"
87#include "webrtc/voice_engine/include/voe_base.h"
88
89#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
90#include "talk/app/webrtc/androidvideocapturer.h"
91#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
92#include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h"
93#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
94#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
95#include "webrtc/modules/video_render/video_render_internal.h"
96#include "webrtc/system_wrappers/include/logcat_trace_context.h"
97using webrtc::LogcatTraceContext;
98#endif
99
100using cricket::WebRtcVideoDecoderFactory;
101using cricket::WebRtcVideoEncoderFactory;
102using rtc::Bind;
103using rtc::Thread;
104using rtc::ThreadManager;
105using rtc::scoped_ptr;
106using webrtc::AudioSourceInterface;
107using webrtc::AudioTrackInterface;
108using webrtc::AudioTrackVector;
109using webrtc::CreateSessionDescriptionObserver;
110using webrtc::DataBuffer;
111using webrtc::DataChannelInit;
112using webrtc::DataChannelInterface;
113using webrtc::DataChannelObserver;
114using webrtc::IceCandidateInterface;
115using webrtc::MediaConstraintsInterface;
116using webrtc::MediaSourceInterface;
117using webrtc::MediaStreamInterface;
118using webrtc::MediaStreamTrackInterface;
119using webrtc::PeerConnectionFactoryInterface;
120using webrtc::PeerConnectionInterface;
121using webrtc::PeerConnectionObserver;
122using webrtc::RtpReceiverInterface;
123using webrtc::RtpSenderInterface;
124using webrtc::SessionDescriptionInterface;
125using webrtc::SetSessionDescriptionObserver;
126using webrtc::StatsObserver;
127using webrtc::StatsReport;
128using webrtc::StatsReports;
129using webrtc::VideoRendererInterface;
130using webrtc::VideoSourceInterface;
131using webrtc::VideoTrackInterface;
132using webrtc::VideoTrackVector;
133using webrtc::kVideoCodecVP8;
134
135namespace webrtc_jni {
136
137// Field trials initialization string
138static char *field_trials_init_string = NULL;
139
140#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
141// Set in PeerConnectionFactory_initializeAndroidGlobals().
142static bool factory_static_initialized = false;
143static bool video_hw_acceleration_enabled = true;
144#endif
145
146// Return the (singleton) Java Enum object corresponding to |index|;
147// |state_class_fragment| is something like "MediaSource$State".
148static jobject JavaEnumFromIndex(
149    JNIEnv* jni, const std::string& state_class_fragment, int index) {
150  const std::string state_class = "org/webrtc/" + state_class_fragment;
151  return JavaEnumFromIndex(jni, FindClass(jni, state_class.c_str()),
152                           state_class, index);
153}
154
155static DataChannelInit JavaDataChannelInitToNative(
156    JNIEnv* jni, jobject j_init) {
157  DataChannelInit init;
158
159  jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
160  jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
161  jfieldID max_retransmit_time_id =
162      GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
163  jfieldID max_retransmits_id =
164      GetFieldID(jni, j_init_class, "maxRetransmits", "I");
165  jfieldID protocol_id =
166      GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
167  jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
168  jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
169
170  init.ordered = GetBooleanField(jni, j_init, ordered_id);
171  init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
172  init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
173  init.protocol = JavaToStdString(
174      jni, GetStringField(jni, j_init, protocol_id));
175  init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
176  init.id = GetIntField(jni, j_init, id_id);
177
178  return init;
179}
180
181class ConstraintsWrapper;
182
183// Adapter between the C++ PeerConnectionObserver interface and the Java
184// PeerConnection.Observer interface.  Wraps an instance of the Java interface
185// and dispatches C++ callbacks to Java.
186class PCOJava : public PeerConnectionObserver {
187 public:
188  PCOJava(JNIEnv* jni, jobject j_observer)
189      : j_observer_global_(jni, j_observer),
190        j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
191        j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
192        j_media_stream_ctor_(GetMethodID(
193            jni, *j_media_stream_class_, "<init>", "(J)V")),
194        j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
195        j_audio_track_ctor_(GetMethodID(
196            jni, *j_audio_track_class_, "<init>", "(J)V")),
197        j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
198        j_video_track_ctor_(GetMethodID(
199            jni, *j_video_track_class_, "<init>", "(J)V")),
200        j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
201        j_data_channel_ctor_(GetMethodID(
202            jni, *j_data_channel_class_, "<init>", "(J)V")) {
203  }
204
205  virtual ~PCOJava() {
206    ScopedLocalRefFrame local_ref_frame(jni());
207    while (!remote_streams_.empty())
208      DisposeRemoteStream(remote_streams_.begin());
209  }
210
211  void OnIceCandidate(const IceCandidateInterface* candidate) override {
212    ScopedLocalRefFrame local_ref_frame(jni());
213    std::string sdp;
214    RTC_CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
215    jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
216    jmethodID ctor = GetMethodID(jni(), candidate_class,
217        "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
218    jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
219    jstring j_sdp = JavaStringFromStdString(jni(), sdp);
220    jobject j_candidate = jni()->NewObject(
221        candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
222    CHECK_EXCEPTION(jni()) << "error during NewObject";
223    jmethodID m = GetMethodID(jni(), *j_observer_class_,
224                              "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
225    jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
226    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
227  }
228
229  void OnSignalingChange(
230      PeerConnectionInterface::SignalingState new_state) override {
231    ScopedLocalRefFrame local_ref_frame(jni());
232    jmethodID m = GetMethodID(
233        jni(), *j_observer_class_, "onSignalingChange",
234        "(Lorg/webrtc/PeerConnection$SignalingState;)V");
235    jobject new_state_enum =
236        JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
237    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
238    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
239  }
240
241  void OnIceConnectionChange(
242      PeerConnectionInterface::IceConnectionState new_state) override {
243    ScopedLocalRefFrame local_ref_frame(jni());
244    jmethodID m = GetMethodID(
245        jni(), *j_observer_class_, "onIceConnectionChange",
246        "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
247    jobject new_state_enum = JavaEnumFromIndex(
248        jni(), "PeerConnection$IceConnectionState", new_state);
249    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
250    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
251  }
252
253  void OnIceConnectionReceivingChange(bool receiving) override {
254    ScopedLocalRefFrame local_ref_frame(jni());
255    jmethodID m = GetMethodID(
256        jni(), *j_observer_class_, "onIceConnectionReceivingChange", "(Z)V");
257    jni()->CallVoidMethod(*j_observer_global_, m, receiving);
258    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
259  }
260
261  void OnIceGatheringChange(
262      PeerConnectionInterface::IceGatheringState new_state) override {
263    ScopedLocalRefFrame local_ref_frame(jni());
264    jmethodID m = GetMethodID(
265        jni(), *j_observer_class_, "onIceGatheringChange",
266        "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
267    jobject new_state_enum = JavaEnumFromIndex(
268        jni(), "PeerConnection$IceGatheringState", new_state);
269    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
270    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
271  }
272
273  void OnAddStream(MediaStreamInterface* stream) override {
274    ScopedLocalRefFrame local_ref_frame(jni());
275    // Java MediaStream holds one reference. Corresponding Release() is in
276    // MediaStream_free, triggered by MediaStream.dispose().
277    stream->AddRef();
278    jobject j_stream =
279        jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_,
280                         reinterpret_cast<jlong>(stream));
281    CHECK_EXCEPTION(jni()) << "error during NewObject";
282
283    for (const auto& track : stream->GetAudioTracks()) {
284      jstring id = JavaStringFromStdString(jni(), track->id());
285      // Java AudioTrack holds one reference. Corresponding Release() is in
286      // MediaStreamTrack_free, triggered by AudioTrack.dispose().
287      track->AddRef();
288      jobject j_track =
289          jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_,
290                           reinterpret_cast<jlong>(track.get()), id);
291      CHECK_EXCEPTION(jni()) << "error during NewObject";
292      jfieldID audio_tracks_id = GetFieldID(jni(),
293                                            *j_media_stream_class_,
294                                            "audioTracks",
295                                            "Ljava/util/LinkedList;");
296      jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
297      jmethodID add = GetMethodID(jni(),
298                                  GetObjectClass(jni(), audio_tracks),
299                                  "add",
300                                  "(Ljava/lang/Object;)Z");
301      jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
302      CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
303      RTC_CHECK(added);
304    }
305
306    for (const auto& track : stream->GetVideoTracks()) {
307      jstring id = JavaStringFromStdString(jni(), track->id());
308      // Java VideoTrack holds one reference. Corresponding Release() is in
309      // MediaStreamTrack_free, triggered by VideoTrack.dispose().
310      track->AddRef();
311      jobject j_track =
312          jni()->NewObject(*j_video_track_class_, j_video_track_ctor_,
313                           reinterpret_cast<jlong>(track.get()), id);
314      CHECK_EXCEPTION(jni()) << "error during NewObject";
315      jfieldID video_tracks_id = GetFieldID(jni(),
316                                            *j_media_stream_class_,
317                                            "videoTracks",
318                                            "Ljava/util/LinkedList;");
319      jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
320      jmethodID add = GetMethodID(jni(),
321                                  GetObjectClass(jni(), video_tracks),
322                                  "add",
323                                  "(Ljava/lang/Object;)Z");
324      jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
325      CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
326      RTC_CHECK(added);
327    }
328    remote_streams_[stream] = NewGlobalRef(jni(), j_stream);
329
330    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
331                              "(Lorg/webrtc/MediaStream;)V");
332    jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
333    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
334  }
335
336  void OnRemoveStream(MediaStreamInterface* stream) override {
337    ScopedLocalRefFrame local_ref_frame(jni());
338    NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
339    RTC_CHECK(it != remote_streams_.end()) << "unexpected stream: " << std::hex
340                                           << stream;
341    jobject j_stream = it->second;
342    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
343                              "(Lorg/webrtc/MediaStream;)V");
344    jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
345    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
346    DisposeRemoteStream(it);
347  }
348
349  void OnDataChannel(DataChannelInterface* channel) override {
350    ScopedLocalRefFrame local_ref_frame(jni());
351    jobject j_channel = jni()->NewObject(
352        *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
353    CHECK_EXCEPTION(jni()) << "error during NewObject";
354
355    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
356                              "(Lorg/webrtc/DataChannel;)V");
357    jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
358
359    // Channel is now owned by Java object, and will be freed from
360    // DataChannel.dispose().  Important that this be done _after_ the
361    // CallVoidMethod above as Java code might call back into native code and be
362    // surprised to see a refcount of 2.
363    int bumped_count = channel->AddRef();
364    RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
365
366    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
367  }
368
369  void OnRenegotiationNeeded() override {
370    ScopedLocalRefFrame local_ref_frame(jni());
371    jmethodID m =
372        GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
373    jni()->CallVoidMethod(*j_observer_global_, m);
374    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
375  }
376
377  void SetConstraints(ConstraintsWrapper* constraints) {
378    RTC_CHECK(!constraints_.get()) << "constraints already set!";
379    constraints_.reset(constraints);
380  }
381
382  const ConstraintsWrapper* constraints() { return constraints_.get(); }
383
384 private:
385  typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap;
386
387  void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it) {
388    jobject j_stream = it->second;
389    remote_streams_.erase(it);
390    jni()->CallVoidMethod(
391        j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V"));
392    CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()";
393    DeleteGlobalRef(jni(), j_stream);
394  }
395
396  JNIEnv* jni() {
397    return AttachCurrentThreadIfNeeded();
398  }
399
400  const ScopedGlobalRef<jobject> j_observer_global_;
401  const ScopedGlobalRef<jclass> j_observer_class_;
402  const ScopedGlobalRef<jclass> j_media_stream_class_;
403  const jmethodID j_media_stream_ctor_;
404  const ScopedGlobalRef<jclass> j_audio_track_class_;
405  const jmethodID j_audio_track_ctor_;
406  const ScopedGlobalRef<jclass> j_video_track_class_;
407  const jmethodID j_video_track_ctor_;
408  const ScopedGlobalRef<jclass> j_data_channel_class_;
409  const jmethodID j_data_channel_ctor_;
410  // C++ -> Java remote streams. The stored jobects are global refs and must be
411  // manually deleted upon removal. Use DisposeRemoteStream().
412  NativeToJavaStreamsMap remote_streams_;
413  scoped_ptr<ConstraintsWrapper> constraints_;
414};
415
416// Wrapper for a Java MediaConstraints object.  Copies all needed data so when
417// the constructor returns the Java object is no longer needed.
418class ConstraintsWrapper : public MediaConstraintsInterface {
419 public:
420  ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
421    PopulateConstraintsFromJavaPairList(
422        jni, j_constraints, "mandatory", &mandatory_);
423    PopulateConstraintsFromJavaPairList(
424        jni, j_constraints, "optional", &optional_);
425  }
426
427  virtual ~ConstraintsWrapper() {}
428
429  // MediaConstraintsInterface.
430  const Constraints& GetMandatory() const override { return mandatory_; }
431
432  const Constraints& GetOptional() const override { return optional_; }
433
434 private:
435  // Helper for translating a List<Pair<String, String>> to a Constraints.
436  static void PopulateConstraintsFromJavaPairList(
437      JNIEnv* jni, jobject j_constraints,
438      const char* field_name, Constraints* field) {
439    jfieldID j_id = GetFieldID(jni,
440        GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
441    jobject j_list = GetObjectField(jni, j_constraints, j_id);
442    jmethodID j_iterator_id = GetMethodID(jni,
443        GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
444    jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
445    CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
446    jmethodID j_has_next = GetMethodID(jni,
447        GetObjectClass(jni, j_iterator), "hasNext", "()Z");
448    jmethodID j_next = GetMethodID(jni,
449        GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
450    while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
451      CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
452      jobject entry = jni->CallObjectMethod(j_iterator, j_next);
453      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
454      jmethodID get_key = GetMethodID(jni,
455          GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
456      jstring j_key = reinterpret_cast<jstring>(
457          jni->CallObjectMethod(entry, get_key));
458      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
459      jmethodID get_value = GetMethodID(jni,
460          GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
461      jstring j_value = reinterpret_cast<jstring>(
462          jni->CallObjectMethod(entry, get_value));
463      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
464      field->push_back(Constraint(JavaToStdString(jni, j_key),
465                                  JavaToStdString(jni, j_value)));
466    }
467    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
468  }
469
470  Constraints mandatory_;
471  Constraints optional_;
472};
473
474static jobject JavaSdpFromNativeSdp(
475    JNIEnv* jni, const SessionDescriptionInterface* desc) {
476  std::string sdp;
477  RTC_CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
478  jstring j_description = JavaStringFromStdString(jni, sdp);
479
480  jclass j_type_class = FindClass(
481      jni, "org/webrtc/SessionDescription$Type");
482  jmethodID j_type_from_canonical = GetStaticMethodID(
483      jni, j_type_class, "fromCanonicalForm",
484      "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
485  jstring j_type_string = JavaStringFromStdString(jni, desc->type());
486  jobject j_type = jni->CallStaticObjectMethod(
487      j_type_class, j_type_from_canonical, j_type_string);
488  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
489
490  jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
491  jmethodID j_sdp_ctor = GetMethodID(
492      jni, j_sdp_class, "<init>",
493      "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
494  jobject j_sdp = jni->NewObject(
495      j_sdp_class, j_sdp_ctor, j_type, j_description);
496  CHECK_EXCEPTION(jni) << "error during NewObject";
497  return j_sdp;
498}
499
500template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
501class SdpObserverWrapper : public T {
502 public:
503  SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
504                     ConstraintsWrapper* constraints)
505      : constraints_(constraints),
506        j_observer_global_(jni, j_observer),
507        j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
508  }
509
510  virtual ~SdpObserverWrapper() {}
511
512  // Can't mark override because of templating.
513  virtual void OnSuccess() {
514    ScopedLocalRefFrame local_ref_frame(jni());
515    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
516    jni()->CallVoidMethod(*j_observer_global_, m);
517    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
518  }
519
520  // Can't mark override because of templating.
521  virtual void OnSuccess(SessionDescriptionInterface* desc) {
522    ScopedLocalRefFrame local_ref_frame(jni());
523    jmethodID m = GetMethodID(
524        jni(), *j_observer_class_, "onCreateSuccess",
525        "(Lorg/webrtc/SessionDescription;)V");
526    jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
527    jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
528    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
529  }
530
531 protected:
532  // Common implementation for failure of Set & Create types, distinguished by
533  // |op| being "Set" or "Create".
534  void DoOnFailure(const std::string& op, const std::string& error) {
535    jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
536                              "(Ljava/lang/String;)V");
537    jstring j_error_string = JavaStringFromStdString(jni(), error);
538    jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
539    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
540  }
541
542  JNIEnv* jni() {
543    return AttachCurrentThreadIfNeeded();
544  }
545
546 private:
547  scoped_ptr<ConstraintsWrapper> constraints_;
548  const ScopedGlobalRef<jobject> j_observer_global_;
549  const ScopedGlobalRef<jclass> j_observer_class_;
550};
551
552class CreateSdpObserverWrapper
553    : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
554 public:
555  CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
556                           ConstraintsWrapper* constraints)
557      : SdpObserverWrapper(jni, j_observer, constraints) {}
558
559  void OnFailure(const std::string& error) override {
560    ScopedLocalRefFrame local_ref_frame(jni());
561    SdpObserverWrapper::DoOnFailure(std::string("Create"), error);
562  }
563};
564
565class SetSdpObserverWrapper
566    : public SdpObserverWrapper<SetSessionDescriptionObserver> {
567 public:
568  SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
569                        ConstraintsWrapper* constraints)
570      : SdpObserverWrapper(jni, j_observer, constraints) {}
571
572  void OnFailure(const std::string& error) override {
573    ScopedLocalRefFrame local_ref_frame(jni());
574    SdpObserverWrapper::DoOnFailure(std::string("Set"), error);
575  }
576};
577
578// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
579// and dispatching the callback from C++ back to Java.
580class DataChannelObserverWrapper : public DataChannelObserver {
581 public:
582  DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
583      : j_observer_global_(jni, j_observer),
584        j_observer_class_(jni, GetObjectClass(jni, j_observer)),
585        j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
586        j_on_buffered_amount_change_mid_(GetMethodID(
587            jni, *j_observer_class_, "onBufferedAmountChange", "(J)V")),
588        j_on_state_change_mid_(
589            GetMethodID(jni, *j_observer_class_, "onStateChange", "()V")),
590        j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
591                                      "(Lorg/webrtc/DataChannel$Buffer;)V")),
592        j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_, "<init>",
593                                   "(Ljava/nio/ByteBuffer;Z)V")) {}
594
595  virtual ~DataChannelObserverWrapper() {}
596
597  void OnBufferedAmountChange(uint64_t previous_amount) override {
598    ScopedLocalRefFrame local_ref_frame(jni());
599    jni()->CallVoidMethod(*j_observer_global_, j_on_buffered_amount_change_mid_,
600                          previous_amount);
601    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
602  }
603
604  void OnStateChange() override {
605    ScopedLocalRefFrame local_ref_frame(jni());
606    jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
607    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
608  }
609
610  void OnMessage(const DataBuffer& buffer) override {
611    ScopedLocalRefFrame local_ref_frame(jni());
612    jobject byte_buffer = jni()->NewDirectByteBuffer(
613        const_cast<char*>(buffer.data.data<char>()), buffer.data.size());
614    jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
615                                        byte_buffer, buffer.binary);
616    jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
617    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
618  }
619
620 private:
621  JNIEnv* jni() {
622    return AttachCurrentThreadIfNeeded();
623  }
624
625  const ScopedGlobalRef<jobject> j_observer_global_;
626  const ScopedGlobalRef<jclass> j_observer_class_;
627  const ScopedGlobalRef<jclass> j_buffer_class_;
628  const jmethodID j_on_buffered_amount_change_mid_;
629  const jmethodID j_on_state_change_mid_;
630  const jmethodID j_on_message_mid_;
631  const jmethodID j_buffer_ctor_;
632};
633
634// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
635// dispatching the callback from C++ back to Java.
636class StatsObserverWrapper : public StatsObserver {
637 public:
638  StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
639      : j_observer_global_(jni, j_observer),
640        j_observer_class_(jni, GetObjectClass(jni, j_observer)),
641        j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
642        j_stats_report_ctor_(GetMethodID(
643            jni, *j_stats_report_class_, "<init>",
644            "(Ljava/lang/String;Ljava/lang/String;D"
645            "[Lorg/webrtc/StatsReport$Value;)V")),
646        j_value_class_(jni, FindClass(
647            jni, "org/webrtc/StatsReport$Value")),
648        j_value_ctor_(GetMethodID(
649            jni, *j_value_class_, "<init>",
650            "(Ljava/lang/String;Ljava/lang/String;)V")) {
651  }
652
653  virtual ~StatsObserverWrapper() {}
654
655  void OnComplete(const StatsReports& reports) override {
656    ScopedLocalRefFrame local_ref_frame(jni());
657    jobjectArray j_reports = ReportsToJava(jni(), reports);
658    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
659                              "([Lorg/webrtc/StatsReport;)V");
660    jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
661    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
662  }
663
664 private:
665  jobjectArray ReportsToJava(
666      JNIEnv* jni, const StatsReports& reports) {
667    jobjectArray reports_array = jni->NewObjectArray(
668        reports.size(), *j_stats_report_class_, NULL);
669    int i = 0;
670    for (const auto* report : reports) {
671      ScopedLocalRefFrame local_ref_frame(jni);
672      jstring j_id = JavaStringFromStdString(jni, report->id()->ToString());
673      jstring j_type = JavaStringFromStdString(jni, report->TypeToString());
674      jobjectArray j_values = ValuesToJava(jni, report->values());
675      jobject j_report = jni->NewObject(*j_stats_report_class_,
676                                        j_stats_report_ctor_,
677                                        j_id,
678                                        j_type,
679                                        report->timestamp(),
680                                        j_values);
681      jni->SetObjectArrayElement(reports_array, i++, j_report);
682    }
683    return reports_array;
684  }
685
686  jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
687    jobjectArray j_values = jni->NewObjectArray(
688        values.size(), *j_value_class_, NULL);
689    int i = 0;
690    for (const auto& it : values) {
691      ScopedLocalRefFrame local_ref_frame(jni);
692      // Should we use the '.name' enum value here instead of converting the
693      // name to a string?
694      jstring j_name = JavaStringFromStdString(jni, it.second->display_name());
695      jstring j_value = JavaStringFromStdString(jni, it.second->ToString());
696      jobject j_element_value =
697          jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
698      jni->SetObjectArrayElement(j_values, i++, j_element_value);
699    }
700    return j_values;
701  }
702
703  JNIEnv* jni() {
704    return AttachCurrentThreadIfNeeded();
705  }
706
707  const ScopedGlobalRef<jobject> j_observer_global_;
708  const ScopedGlobalRef<jclass> j_observer_class_;
709  const ScopedGlobalRef<jclass> j_stats_report_class_;
710  const jmethodID j_stats_report_ctor_;
711  const ScopedGlobalRef<jclass> j_value_class_;
712  const jmethodID j_value_ctor_;
713};
714
715// Adapter presenting a cricket::VideoRenderer as a
716// webrtc::VideoRendererInterface.
717class VideoRendererWrapper : public VideoRendererInterface {
718 public:
719  static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
720    if (renderer)
721      return new VideoRendererWrapper(renderer);
722    return NULL;
723  }
724
725  virtual ~VideoRendererWrapper() {}
726
727  // This wraps VideoRenderer which still has SetSize.
728  void RenderFrame(const cricket::VideoFrame* video_frame) override {
729    ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
730    const cricket::VideoFrame* frame =
731      video_frame->GetCopyWithRotationApplied();
732    if (width_ != frame->GetWidth() || height_ != frame->GetHeight()) {
733      width_ = frame->GetWidth();
734      height_ = frame->GetHeight();
735      renderer_->SetSize(width_, height_, 0);
736    }
737    renderer_->RenderFrame(frame);
738  }
739
740 private:
741  explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
742    : width_(0), height_(0), renderer_(renderer) {}
743  int width_, height_;
744  scoped_ptr<cricket::VideoRenderer> renderer_;
745};
746
747// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
748// instance.
749class JavaVideoRendererWrapper : public VideoRendererInterface {
750 public:
751  JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
752      : j_callbacks_(jni, j_callbacks),
753        j_render_frame_id_(GetMethodID(
754            jni, GetObjectClass(jni, j_callbacks), "renderFrame",
755            "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
756        j_frame_class_(jni,
757                       FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
758        j_i420_frame_ctor_id_(GetMethodID(
759            jni, *j_frame_class_, "<init>", "(III[I[Ljava/nio/ByteBuffer;J)V")),
760        j_texture_frame_ctor_id_(GetMethodID(
761            jni, *j_frame_class_, "<init>",
762            "(IIII[FJ)V")),
763        j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
764    CHECK_EXCEPTION(jni);
765  }
766
767  virtual ~JavaVideoRendererWrapper() {}
768
769  void RenderFrame(const cricket::VideoFrame* video_frame) override {
770    ScopedLocalRefFrame local_ref_frame(jni());
771    jobject j_frame = (video_frame->GetNativeHandle() != nullptr)
772                          ? CricketToJavaTextureFrame(video_frame)
773                          : CricketToJavaI420Frame(video_frame);
774    // |j_callbacks_| is responsible for releasing |j_frame| with
775    // VideoRenderer.renderFrameDone().
776    jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
777    CHECK_EXCEPTION(jni());
778  }
779
780 private:
781  // Make a shallow copy of |frame| to be used with Java. The callee has
782  // ownership of the frame, and the frame should be released with
783  // VideoRenderer.releaseNativeFrame().
784  static jlong javaShallowCopy(const cricket::VideoFrame* frame) {
785    return jlongFromPointer(frame->Copy());
786  }
787
788  // Return a VideoRenderer.I420Frame referring to the data in |frame|.
789  jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
790    jintArray strides = jni()->NewIntArray(3);
791    jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
792    strides_array[0] = frame->GetYPitch();
793    strides_array[1] = frame->GetUPitch();
794    strides_array[2] = frame->GetVPitch();
795    jni()->ReleaseIntArrayElements(strides, strides_array, 0);
796    jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
797    jobject y_buffer =
798        jni()->NewDirectByteBuffer(const_cast<uint8_t*>(frame->GetYPlane()),
799                                   frame->GetYPitch() * frame->GetHeight());
800    jobject u_buffer = jni()->NewDirectByteBuffer(
801        const_cast<uint8_t*>(frame->GetUPlane()), frame->GetChromaSize());
802    jobject v_buffer = jni()->NewDirectByteBuffer(
803        const_cast<uint8_t*>(frame->GetVPlane()), frame->GetChromaSize());
804    jni()->SetObjectArrayElement(planes, 0, y_buffer);
805    jni()->SetObjectArrayElement(planes, 1, u_buffer);
806    jni()->SetObjectArrayElement(planes, 2, v_buffer);
807    return jni()->NewObject(
808        *j_frame_class_, j_i420_frame_ctor_id_,
809        frame->GetWidth(), frame->GetHeight(),
810        static_cast<int>(frame->GetVideoRotation()),
811        strides, planes, javaShallowCopy(frame));
812  }
813
814  // Return a VideoRenderer.I420Frame referring texture object in |frame|.
815  jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
816    NativeHandleImpl* handle =
817        reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
818    jfloatArray sampling_matrix = jni()->NewFloatArray(16);
819    jni()->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix);
820    return jni()->NewObject(
821        *j_frame_class_, j_texture_frame_ctor_id_,
822        frame->GetWidth(), frame->GetHeight(),
823        static_cast<int>(frame->GetVideoRotation()),
824        handle->oes_texture_id, sampling_matrix, javaShallowCopy(frame));
825  }
826
827  JNIEnv* jni() {
828    return AttachCurrentThreadIfNeeded();
829  }
830
831  ScopedGlobalRef<jobject> j_callbacks_;
832  jmethodID j_render_frame_id_;
833  ScopedGlobalRef<jclass> j_frame_class_;
834  jmethodID j_i420_frame_ctor_id_;
835  jmethodID j_texture_frame_ctor_id_;
836  ScopedGlobalRef<jclass> j_byte_buffer_class_;
837};
838
839
840static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
841  jfieldID native_dc_id = GetFieldID(jni,
842      GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
843  jlong j_d = GetLongField(jni, j_dc, native_dc_id);
844  return reinterpret_cast<DataChannelInterface*>(j_d);
845}
846
847JOW(jlong, DataChannel_registerObserverNative)(
848    JNIEnv* jni, jobject j_dc, jobject j_observer) {
849  scoped_ptr<DataChannelObserverWrapper> observer(
850      new DataChannelObserverWrapper(jni, j_observer));
851  ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
852  return jlongFromPointer(observer.release());
853}
854
855JOW(void, DataChannel_unregisterObserverNative)(
856    JNIEnv* jni, jobject j_dc, jlong native_observer) {
857  ExtractNativeDC(jni, j_dc)->UnregisterObserver();
858  delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
859}
860
861JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
862  return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
863}
864
865JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
866  return JavaEnumFromIndex(
867      jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
868}
869
870JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
871  uint64_t buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
872  RTC_CHECK_LE(buffered_amount, std::numeric_limits<int64_t>::max())
873      << "buffered_amount overflowed jlong!";
874  return static_cast<jlong>(buffered_amount);
875}
876
877JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
878  ExtractNativeDC(jni, j_dc)->Close();
879}
880
881JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
882                                      jbyteArray data, jboolean binary) {
883  jbyte* bytes = jni->GetByteArrayElements(data, NULL);
884  bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
885      rtc::Buffer(bytes, jni->GetArrayLength(data)),
886      binary));
887  jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
888  return ret;
889}
890
891JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
892  CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
893}
894
895JOW(void, Logging_nativeEnableTracing)(
896    JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
897    jint nativeSeverity) {
898  std::string path = JavaToStdString(jni, j_path);
899  if (nativeLevels != webrtc::kTraceNone) {
900    webrtc::Trace::set_level_filter(nativeLevels);
901#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
902    if (path != "logcat:") {
903#endif
904      RTC_CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
905          << "SetTraceFile failed";
906#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
907    } else {
908      // Intentionally leak this to avoid needing to reason about its lifecycle.
909      // It keeps no state and functions only as a dispatch point.
910      static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
911    }
912#endif
913  }
914  if (nativeSeverity >= rtc::LS_SENSITIVE && nativeSeverity <= rtc::LS_ERROR) {
915    rtc::LogMessage::LogToDebug(
916        static_cast<rtc::LoggingSeverity>(nativeSeverity));
917  }
918}
919
920JOW(void, Logging_nativeEnableLogThreads)(JNIEnv* jni, jclass) {
921  rtc::LogMessage::LogThreads(true);
922}
923
924JOW(void, Logging_nativeEnableLogTimeStamps)(JNIEnv* jni, jclass) {
925  rtc::LogMessage::LogTimestamps(true);
926}
927
928JOW(void, Logging_nativeLog)(
929    JNIEnv* jni, jclass, jint j_severity, jstring j_tag, jstring j_message) {
930  std::string message = JavaToStdString(jni, j_message);
931  std::string tag = JavaToStdString(jni, j_tag);
932  LOG_TAG(static_cast<rtc::LoggingSeverity>(j_severity), tag) << message;
933}
934
935JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
936  CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
937}
938
939JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
940  PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
941  delete p;
942}
943
944JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
945  CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
946}
947
948JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
949  delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
950}
951
952JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
953  delete reinterpret_cast<VideoRendererWrapper*>(j_p);
954}
955
956JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
957  delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
958}
959
960JOW(void, VideoRenderer_releaseNativeFrame)(
961    JNIEnv* jni, jclass, jlong j_frame_ptr) {
962  delete reinterpret_cast<const cricket::VideoFrame*>(j_frame_ptr);
963}
964
965JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
966  reinterpret_cast<MediaStreamTrackInterface*>(j_p)->Release();
967}
968
969JOW(jboolean, MediaStream_nativeAddAudioTrack)(
970    JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
971  return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
972      reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
973}
974
975JOW(jboolean, MediaStream_nativeAddVideoTrack)(
976    JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
977  return reinterpret_cast<MediaStreamInterface*>(pointer)
978      ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
979}
980
981JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
982    JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
983  return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
984      reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
985}
986
987JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
988    JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
989  return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
990      reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
991}
992
993JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
994  return JavaStringFromStdString(
995      jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
996}
997
998JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
999  CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1000}
1001
1002JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1003    JNIEnv * jni, jclass, jobject j_observer) {
1004  return (jlong)new PCOJava(jni, j_observer);
1005}
1006
1007#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
1008JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1009    JNIEnv* jni, jclass, jobject context,
1010    jboolean initialize_audio, jboolean initialize_video,
1011    jboolean video_hw_acceleration) {
1012  bool failure = false;
1013  video_hw_acceleration_enabled = video_hw_acceleration;
1014  AndroidNetworkMonitor::SetAndroidContext(jni, context);
1015  if (!factory_static_initialized) {
1016    if (initialize_video) {
1017      failure |= webrtc::SetRenderAndroidVM(GetJVM());
1018      failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context);
1019    }
1020    if (initialize_audio)
1021      failure |= webrtc::VoiceEngine::SetAndroidObjects(GetJVM(), context);
1022    factory_static_initialized = true;
1023  }
1024  return !failure;
1025}
1026#endif  // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
1027
1028JOW(void, PeerConnectionFactory_initializeFieldTrials)(
1029    JNIEnv* jni, jclass, jstring j_trials_init_string) {
1030  field_trials_init_string = NULL;
1031  if (j_trials_init_string != NULL) {
1032    const char* init_string =
1033        jni->GetStringUTFChars(j_trials_init_string, NULL);
1034    int init_string_length = jni->GetStringUTFLength(j_trials_init_string);
1035    field_trials_init_string = new char[init_string_length + 1];
1036    rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string);
1037    jni->ReleaseStringUTFChars(j_trials_init_string, init_string);
1038    LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string;
1039  }
1040  webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string);
1041}
1042
1043JOW(void, PeerConnectionFactory_initializeInternalTracer)(JNIEnv* jni, jclass) {
1044  rtc::tracing::SetupInternalTracer();
1045}
1046
1047JOW(jboolean, PeerConnectionFactory_startInternalTracingCapture)(
1048    JNIEnv* jni, jclass, jstring j_event_tracing_filename) {
1049  if (!j_event_tracing_filename)
1050    return false;
1051
1052  const char* init_string =
1053      jni->GetStringUTFChars(j_event_tracing_filename, NULL);
1054  LOG(LS_INFO) << "Starting internal tracing to: " << init_string;
1055  bool ret = rtc::tracing::StartInternalCapture(init_string);
1056  jni->ReleaseStringUTFChars(j_event_tracing_filename, init_string);
1057  return ret;
1058}
1059
1060JOW(void, PeerConnectionFactory_stopInternalTracingCapture)(
1061    JNIEnv* jni, jclass) {
1062  rtc::tracing::StopInternalCapture();
1063}
1064
1065JOW(void, PeerConnectionFactory_shutdownInternalTracer)(JNIEnv* jni, jclass) {
1066  rtc::tracing::ShutdownInternalTracer();
1067}
1068
1069// Helper struct for working around the fact that CreatePeerConnectionFactory()
1070// comes in two flavors: either entirely automagical (constructing its own
1071// threads and deleting them on teardown, but no external codec factory support)
1072// or entirely manual (requires caller to delete threads after factory
1073// teardown).  This struct takes ownership of its ctor's arguments to present a
1074// single thing for Java to hold and eventually free.
1075class OwnedFactoryAndThreads {
1076 public:
1077  OwnedFactoryAndThreads(Thread* worker_thread,
1078                         Thread* signaling_thread,
1079                         WebRtcVideoEncoderFactory* encoder_factory,
1080                         WebRtcVideoDecoderFactory* decoder_factory,
1081                         rtc::NetworkMonitorFactory* network_monitor_factory,
1082                         PeerConnectionFactoryInterface* factory)
1083      : worker_thread_(worker_thread),
1084        signaling_thread_(signaling_thread),
1085        encoder_factory_(encoder_factory),
1086        decoder_factory_(decoder_factory),
1087        network_monitor_factory_(network_monitor_factory),
1088        factory_(factory) {}
1089
1090  ~OwnedFactoryAndThreads() {
1091    CHECK_RELEASE(factory_);
1092    if (network_monitor_factory_ != nullptr) {
1093      rtc::NetworkMonitorFactory::ReleaseFactory(network_monitor_factory_);
1094    }
1095  }
1096
1097  PeerConnectionFactoryInterface* factory() { return factory_; }
1098  WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; }
1099  WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; }
1100  rtc::NetworkMonitorFactory* network_monitor_factory() {
1101    return network_monitor_factory_;
1102  }
1103  void clear_network_monitor_factory() { network_monitor_factory_ = nullptr; }
1104  void InvokeJavaCallbacksOnFactoryThreads();
1105
1106 private:
1107  void JavaCallbackOnFactoryThreads();
1108
1109  const scoped_ptr<Thread> worker_thread_;
1110  const scoped_ptr<Thread> signaling_thread_;
1111  WebRtcVideoEncoderFactory* encoder_factory_;
1112  WebRtcVideoDecoderFactory* decoder_factory_;
1113  rtc::NetworkMonitorFactory* network_monitor_factory_;
1114  PeerConnectionFactoryInterface* factory_;  // Const after ctor except dtor.
1115};
1116
1117void OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads() {
1118  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1119  ScopedLocalRefFrame local_ref_frame(jni);
1120  jclass j_factory_class = FindClass(jni, "org/webrtc/PeerConnectionFactory");
1121  jmethodID m = nullptr;
1122  if (Thread::Current() == worker_thread_) {
1123    LOG(LS_INFO) << "Worker thread JavaCallback";
1124    m = GetStaticMethodID(jni, j_factory_class, "onWorkerThreadReady", "()V");
1125  }
1126  if (Thread::Current() == signaling_thread_) {
1127    LOG(LS_INFO) << "Signaling thread JavaCallback";
1128    m = GetStaticMethodID(
1129        jni, j_factory_class, "onSignalingThreadReady", "()V");
1130  }
1131  if (m != nullptr) {
1132    jni->CallStaticVoidMethod(j_factory_class, m);
1133    CHECK_EXCEPTION(jni) << "error during JavaCallback::CallStaticVoidMethod";
1134  }
1135}
1136
1137void OwnedFactoryAndThreads::InvokeJavaCallbacksOnFactoryThreads() {
1138  LOG(LS_INFO) << "InvokeJavaCallbacksOnFactoryThreads.";
1139  worker_thread_->Invoke<void>(
1140      Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this));
1141  signaling_thread_->Invoke<void>(
1142      Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this));
1143}
1144
1145JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1146    JNIEnv* jni, jclass) {
1147  // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
1148  // ThreadManager only WrapCurrentThread()s the thread where it is first
1149  // created.  Since the semantics around when auto-wrapping happens in
1150  // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
1151  // about ramifications of auto-wrapping there.
1152  rtc::ThreadManager::Instance()->WrapCurrentThread();
1153  webrtc::Trace::CreateTrace();
1154  Thread* worker_thread = new Thread();
1155  worker_thread->SetName("worker_thread", NULL);
1156  Thread* signaling_thread = new Thread();
1157  signaling_thread->SetName("signaling_thread", NULL);
1158  RTC_CHECK(worker_thread->Start() && signaling_thread->Start())
1159      << "Failed to start threads";
1160  WebRtcVideoEncoderFactory* encoder_factory = nullptr;
1161  WebRtcVideoDecoderFactory* decoder_factory = nullptr;
1162  rtc::NetworkMonitorFactory* network_monitor_factory = nullptr;
1163
1164#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
1165  if (video_hw_acceleration_enabled) {
1166    encoder_factory = new MediaCodecVideoEncoderFactory();
1167    decoder_factory = new MediaCodecVideoDecoderFactory();
1168  }
1169  network_monitor_factory = new AndroidNetworkMonitorFactory();
1170  rtc::NetworkMonitorFactory::SetFactory(network_monitor_factory);
1171#endif
1172  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1173      webrtc::CreatePeerConnectionFactory(worker_thread,
1174                                          signaling_thread,
1175                                          NULL,
1176                                          encoder_factory,
1177                                          decoder_factory));
1178  RTC_CHECK(factory) << "Failed to create the peer connection factory; "
1179                     << "WebRTC/libjingle init likely failed on this device";
1180  OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
1181      worker_thread, signaling_thread,
1182      encoder_factory, decoder_factory,
1183      network_monitor_factory, factory.release());
1184  owned_factory->InvokeJavaCallbacksOnFactoryThreads();
1185  return jlongFromPointer(owned_factory);
1186}
1187
1188JOW(void, PeerConnectionFactory_nativeFreeFactory)(JNIEnv*, jclass, jlong j_p) {
1189  delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
1190  if (field_trials_init_string) {
1191    webrtc::field_trial::InitFieldTrialsFromString(NULL);
1192    delete field_trials_init_string;
1193    field_trials_init_string = NULL;
1194  }
1195  webrtc::Trace::ReturnTrace();
1196}
1197
1198static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
1199  return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
1200}
1201
1202JOW(void, PeerConnectionFactory_nativeThreadsCallbacks)(
1203    JNIEnv*, jclass, jlong j_p) {
1204  OwnedFactoryAndThreads *factory =
1205      reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
1206  factory->InvokeJavaCallbacksOnFactoryThreads();
1207}
1208
1209JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1210    JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1211  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1212      factoryFromJava(native_factory));
1213  rtc::scoped_refptr<MediaStreamInterface> stream(
1214      factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1215  return (jlong)stream.release();
1216}
1217
1218JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1219    JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1220    jobject j_constraints) {
1221  scoped_ptr<ConstraintsWrapper> constraints(
1222      new ConstraintsWrapper(jni, j_constraints));
1223  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1224      factoryFromJava(native_factory));
1225  rtc::scoped_refptr<VideoSourceInterface> source(
1226      factory->CreateVideoSource(
1227          reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1228          constraints.get()));
1229  return (jlong)source.release();
1230}
1231
1232JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1233    JNIEnv* jni, jclass, jlong native_factory, jstring id,
1234    jlong native_source) {
1235  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1236      factoryFromJava(native_factory));
1237  rtc::scoped_refptr<VideoTrackInterface> track(
1238      factory->CreateVideoTrack(
1239          JavaToStdString(jni, id),
1240          reinterpret_cast<VideoSourceInterface*>(native_source)));
1241  return (jlong)track.release();
1242}
1243
1244JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
1245    JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
1246  scoped_ptr<ConstraintsWrapper> constraints(
1247      new ConstraintsWrapper(jni, j_constraints));
1248  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1249      factoryFromJava(native_factory));
1250  rtc::scoped_refptr<AudioSourceInterface> source(
1251      factory->CreateAudioSource(constraints.get()));
1252  return (jlong)source.release();
1253}
1254
1255JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1256    JNIEnv* jni, jclass, jlong native_factory, jstring id,
1257    jlong native_source) {
1258  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1259      factoryFromJava(native_factory));
1260  rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
1261      JavaToStdString(jni, id),
1262      reinterpret_cast<AudioSourceInterface*>(native_source)));
1263  return (jlong)track.release();
1264}
1265
1266JOW(jboolean, PeerConnectionFactory_nativeStartAecDump)(
1267    JNIEnv* jni, jclass, jlong native_factory, jint file) {
1268#if defined(ANDROID)
1269  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1270      factoryFromJava(native_factory));
1271  return factory->StartAecDump(file);
1272#else
1273  return false;
1274#endif
1275}
1276
1277JOW(void, PeerConnectionFactory_nativeStopAecDump)(
1278    JNIEnv* jni, jclass, jlong native_factory) {
1279#if defined(ANDROID)
1280  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1281      factoryFromJava(native_factory));
1282  factory->StopAecDump();
1283#endif
1284}
1285
1286JOW(jboolean, PeerConnectionFactory_nativeStartRtcEventLog)(
1287    JNIEnv* jni, jclass, jlong native_factory, jint file) {
1288#if defined(ANDROID)
1289  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1290      factoryFromJava(native_factory));
1291  return factory->StartRtcEventLog(file);
1292#else
1293  return false;
1294#endif
1295}
1296
1297JOW(void, PeerConnectionFactory_nativeStopRtcEventLog)(
1298    JNIEnv* jni, jclass, jlong native_factory) {
1299#if defined(ANDROID)
1300  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1301      factoryFromJava(native_factory));
1302  factory->StopRtcEventLog();
1303#endif
1304}
1305
1306JOW(void, PeerConnectionFactory_nativeSetOptions)(
1307    JNIEnv* jni, jclass, jlong native_factory, jobject options) {
1308  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
1309      factoryFromJava(native_factory));
1310  jclass options_class = jni->GetObjectClass(options);
1311  jfieldID network_ignore_mask_field =
1312      jni->GetFieldID(options_class, "networkIgnoreMask", "I");
1313  int network_ignore_mask =
1314      jni->GetIntField(options, network_ignore_mask_field);
1315
1316  jfieldID disable_encryption_field =
1317      jni->GetFieldID(options_class, "disableEncryption", "Z");
1318  bool disable_encryption =
1319      jni->GetBooleanField(options, disable_encryption_field);
1320
1321  jfieldID disable_network_monitor_field =
1322      jni->GetFieldID(options_class, "disableNetworkMonitor", "Z");
1323  bool disable_network_monitor =
1324      jni->GetBooleanField(options, disable_network_monitor_field);
1325
1326  PeerConnectionFactoryInterface::Options options_to_set;
1327
1328  // This doesn't necessarily match the c++ version of this struct; feel free
1329  // to add more parameters as necessary.
1330  options_to_set.network_ignore_mask = network_ignore_mask;
1331  options_to_set.disable_encryption = disable_encryption;
1332  options_to_set.disable_network_monitor = disable_network_monitor;
1333  factory->SetOptions(options_to_set);
1334
1335  if (disable_network_monitor) {
1336    OwnedFactoryAndThreads* owner =
1337        reinterpret_cast<OwnedFactoryAndThreads*>(native_factory);
1338    if (owner->network_monitor_factory()) {
1339      rtc::NetworkMonitorFactory::ReleaseFactory(
1340          owner->network_monitor_factory());
1341      owner->clear_network_monitor_factory();
1342    }
1343  }
1344}
1345
1346JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)(
1347    JNIEnv* jni, jclass, jlong native_factory, jobject local_egl_context,
1348    jobject remote_egl_context) {
1349#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
1350  OwnedFactoryAndThreads* owned_factory =
1351      reinterpret_cast<OwnedFactoryAndThreads*>(native_factory);
1352
1353  jclass j_eglbase14_context_class =
1354      FindClass(jni, "org/webrtc/EglBase14$Context");
1355
1356  MediaCodecVideoEncoderFactory* encoder_factory =
1357      static_cast<MediaCodecVideoEncoderFactory*>
1358          (owned_factory->encoder_factory());
1359  if (encoder_factory &&
1360      jni->IsInstanceOf(local_egl_context, j_eglbase14_context_class)) {
1361    LOG(LS_INFO) << "Set EGL context for HW encoding.";
1362    encoder_factory->SetEGLContext(jni, local_egl_context);
1363  }
1364
1365  MediaCodecVideoDecoderFactory* decoder_factory =
1366      static_cast<MediaCodecVideoDecoderFactory*>
1367          (owned_factory->decoder_factory());
1368  if (decoder_factory &&
1369      jni->IsInstanceOf(remote_egl_context, j_eglbase14_context_class)) {
1370    LOG(LS_INFO) << "Set EGL context for HW decoding.";
1371    decoder_factory->SetEGLContext(jni, remote_egl_context);
1372  }
1373#endif
1374}
1375
1376static std::string
1377GetJavaEnumName(JNIEnv* jni, const std::string& className, jobject j_enum) {
1378  jclass enumClass = FindClass(jni, className.c_str());
1379  jmethodID nameMethod =
1380      GetMethodID(jni, enumClass, "name", "()Ljava/lang/String;");
1381  jstring name =
1382      reinterpret_cast<jstring>(jni->CallObjectMethod(j_enum, nameMethod));
1383  CHECK_EXCEPTION(jni) << "error during CallObjectMethod for "
1384                       << className << ".name";
1385  return JavaToStdString(jni, name);
1386}
1387
1388static PeerConnectionInterface::IceTransportsType
1389JavaIceTransportsTypeToNativeType(JNIEnv* jni, jobject j_ice_transports_type) {
1390  std::string enum_name = GetJavaEnumName(
1391      jni, "org/webrtc/PeerConnection$IceTransportsType",
1392      j_ice_transports_type);
1393
1394  if (enum_name == "ALL")
1395    return PeerConnectionInterface::kAll;
1396
1397  if (enum_name == "RELAY")
1398    return PeerConnectionInterface::kRelay;
1399
1400  if (enum_name == "NOHOST")
1401    return PeerConnectionInterface::kNoHost;
1402
1403  if (enum_name == "NONE")
1404    return PeerConnectionInterface::kNone;
1405
1406  RTC_CHECK(false) << "Unexpected IceTransportsType enum_name " << enum_name;
1407  return PeerConnectionInterface::kAll;
1408}
1409
1410static PeerConnectionInterface::BundlePolicy
1411JavaBundlePolicyToNativeType(JNIEnv* jni, jobject j_bundle_policy) {
1412  std::string enum_name = GetJavaEnumName(
1413      jni, "org/webrtc/PeerConnection$BundlePolicy",
1414      j_bundle_policy);
1415
1416  if (enum_name == "BALANCED")
1417    return PeerConnectionInterface::kBundlePolicyBalanced;
1418
1419  if (enum_name == "MAXBUNDLE")
1420    return PeerConnectionInterface::kBundlePolicyMaxBundle;
1421
1422  if (enum_name == "MAXCOMPAT")
1423    return PeerConnectionInterface::kBundlePolicyMaxCompat;
1424
1425  RTC_CHECK(false) << "Unexpected BundlePolicy enum_name " << enum_name;
1426  return PeerConnectionInterface::kBundlePolicyBalanced;
1427}
1428
1429static PeerConnectionInterface::RtcpMuxPolicy
1430JavaRtcpMuxPolicyToNativeType(JNIEnv* jni, jobject j_rtcp_mux_policy) {
1431  std::string enum_name = GetJavaEnumName(
1432      jni, "org/webrtc/PeerConnection$RtcpMuxPolicy",
1433      j_rtcp_mux_policy);
1434
1435  if (enum_name == "NEGOTIATE")
1436    return PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
1437
1438  if (enum_name == "REQUIRE")
1439    return PeerConnectionInterface::kRtcpMuxPolicyRequire;
1440
1441  RTC_CHECK(false) << "Unexpected RtcpMuxPolicy enum_name " << enum_name;
1442  return PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
1443}
1444
1445static PeerConnectionInterface::TcpCandidatePolicy
1446JavaTcpCandidatePolicyToNativeType(
1447    JNIEnv* jni, jobject j_tcp_candidate_policy) {
1448  std::string enum_name = GetJavaEnumName(
1449      jni, "org/webrtc/PeerConnection$TcpCandidatePolicy",
1450      j_tcp_candidate_policy);
1451
1452  if (enum_name == "ENABLED")
1453    return PeerConnectionInterface::kTcpCandidatePolicyEnabled;
1454
1455  if (enum_name == "DISABLED")
1456    return PeerConnectionInterface::kTcpCandidatePolicyDisabled;
1457
1458  RTC_CHECK(false) << "Unexpected TcpCandidatePolicy enum_name " << enum_name;
1459  return PeerConnectionInterface::kTcpCandidatePolicyEnabled;
1460}
1461
1462static rtc::KeyType JavaKeyTypeToNativeType(JNIEnv* jni, jobject j_key_type) {
1463  std::string enum_name = GetJavaEnumName(
1464      jni, "org/webrtc/PeerConnection$KeyType", j_key_type);
1465
1466  if (enum_name == "RSA")
1467    return rtc::KT_RSA;
1468  if (enum_name == "ECDSA")
1469    return rtc::KT_ECDSA;
1470
1471  RTC_CHECK(false) << "Unexpected KeyType enum_name " << enum_name;
1472  return rtc::KT_ECDSA;
1473}
1474
1475static PeerConnectionInterface::ContinualGatheringPolicy
1476    JavaContinualGatheringPolicyToNativeType(
1477        JNIEnv* jni, jobject j_gathering_policy) {
1478  std::string enum_name = GetJavaEnumName(
1479      jni, "org/webrtc/PeerConnection$ContinualGatheringPolicy",
1480      j_gathering_policy);
1481  if (enum_name == "GATHER_ONCE")
1482    return PeerConnectionInterface::GATHER_ONCE;
1483
1484  if (enum_name == "GATHER_CONTINUALLY")
1485    return PeerConnectionInterface::GATHER_CONTINUALLY;
1486
1487  RTC_CHECK(false) << "Unexpected ContinualGatheringPolicy enum name "
1488                   << enum_name;
1489  return PeerConnectionInterface::GATHER_ONCE;
1490}
1491
1492static void JavaIceServersToJsepIceServers(
1493    JNIEnv* jni, jobject j_ice_servers,
1494    PeerConnectionInterface::IceServers* ice_servers) {
1495  jclass list_class = GetObjectClass(jni, j_ice_servers);
1496  jmethodID iterator_id = GetMethodID(
1497      jni, list_class, "iterator", "()Ljava/util/Iterator;");
1498  jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1499  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
1500  jmethodID iterator_has_next = GetMethodID(
1501      jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1502  jmethodID iterator_next = GetMethodID(
1503      jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1504  while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1505    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
1506    jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1507    CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
1508    jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1509    jfieldID j_ice_server_uri_id =
1510        GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1511    jfieldID j_ice_server_username_id =
1512        GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1513    jfieldID j_ice_server_password_id =
1514        GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1515    jstring uri = reinterpret_cast<jstring>(
1516        GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1517    jstring username = reinterpret_cast<jstring>(
1518        GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1519    jstring password = reinterpret_cast<jstring>(
1520        GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1521    PeerConnectionInterface::IceServer server;
1522    server.uri = JavaToStdString(jni, uri);
1523    server.username = JavaToStdString(jni, username);
1524    server.password = JavaToStdString(jni, password);
1525    ice_servers->push_back(server);
1526  }
1527  CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
1528}
1529
1530static void JavaRTCConfigurationToJsepRTCConfiguration(
1531    JNIEnv* jni,
1532    jobject j_rtc_config,
1533    PeerConnectionInterface::RTCConfiguration* rtc_config) {
1534  jclass j_rtc_config_class = GetObjectClass(jni, j_rtc_config);
1535
1536  jfieldID j_ice_transports_type_id = GetFieldID(
1537      jni, j_rtc_config_class, "iceTransportsType",
1538      "Lorg/webrtc/PeerConnection$IceTransportsType;");
1539  jobject j_ice_transports_type = GetObjectField(
1540      jni, j_rtc_config, j_ice_transports_type_id);
1541
1542  jfieldID j_bundle_policy_id = GetFieldID(
1543      jni, j_rtc_config_class, "bundlePolicy",
1544      "Lorg/webrtc/PeerConnection$BundlePolicy;");
1545  jobject j_bundle_policy = GetObjectField(
1546      jni, j_rtc_config, j_bundle_policy_id);
1547
1548  jfieldID j_rtcp_mux_policy_id = GetFieldID(
1549      jni, j_rtc_config_class, "rtcpMuxPolicy",
1550      "Lorg/webrtc/PeerConnection$RtcpMuxPolicy;");
1551  jobject j_rtcp_mux_policy = GetObjectField(
1552      jni, j_rtc_config, j_rtcp_mux_policy_id);
1553
1554  jfieldID j_tcp_candidate_policy_id = GetFieldID(
1555      jni, j_rtc_config_class, "tcpCandidatePolicy",
1556      "Lorg/webrtc/PeerConnection$TcpCandidatePolicy;");
1557  jobject j_tcp_candidate_policy = GetObjectField(
1558      jni, j_rtc_config, j_tcp_candidate_policy_id);
1559
1560  jfieldID j_ice_servers_id = GetFieldID(
1561      jni, j_rtc_config_class, "iceServers", "Ljava/util/List;");
1562  jobject j_ice_servers = GetObjectField(jni, j_rtc_config, j_ice_servers_id);
1563
1564  jfieldID j_audio_jitter_buffer_max_packets_id =
1565      GetFieldID(jni, j_rtc_config_class, "audioJitterBufferMaxPackets", "I");
1566  jfieldID j_audio_jitter_buffer_fast_accelerate_id = GetFieldID(
1567      jni, j_rtc_config_class, "audioJitterBufferFastAccelerate", "Z");
1568
1569  jfieldID j_ice_connection_receiving_timeout_id =
1570      GetFieldID(jni, j_rtc_config_class, "iceConnectionReceivingTimeout", "I");
1571
1572  jfieldID j_ice_backup_candidate_pair_ping_interval_id = GetFieldID(
1573      jni, j_rtc_config_class, "iceBackupCandidatePairPingInterval", "I");
1574
1575  jfieldID j_continual_gathering_policy_id =
1576      GetFieldID(jni, j_rtc_config_class, "continualGatheringPolicy",
1577                 "Lorg/webrtc/PeerConnection$ContinualGatheringPolicy;");
1578  jobject j_continual_gathering_policy =
1579      GetObjectField(jni, j_rtc_config, j_continual_gathering_policy_id);
1580
1581  rtc_config->type =
1582      JavaIceTransportsTypeToNativeType(jni, j_ice_transports_type);
1583  rtc_config->bundle_policy =
1584      JavaBundlePolicyToNativeType(jni, j_bundle_policy);
1585  rtc_config->rtcp_mux_policy =
1586      JavaRtcpMuxPolicyToNativeType(jni, j_rtcp_mux_policy);
1587  rtc_config->tcp_candidate_policy =
1588      JavaTcpCandidatePolicyToNativeType(jni, j_tcp_candidate_policy);
1589  JavaIceServersToJsepIceServers(jni, j_ice_servers, &rtc_config->servers);
1590  rtc_config->audio_jitter_buffer_max_packets =
1591      GetIntField(jni, j_rtc_config, j_audio_jitter_buffer_max_packets_id);
1592  rtc_config->audio_jitter_buffer_fast_accelerate = GetBooleanField(
1593      jni, j_rtc_config, j_audio_jitter_buffer_fast_accelerate_id);
1594  rtc_config->ice_connection_receiving_timeout =
1595      GetIntField(jni, j_rtc_config, j_ice_connection_receiving_timeout_id);
1596  rtc_config->ice_backup_candidate_pair_ping_interval = GetIntField(
1597      jni, j_rtc_config, j_ice_backup_candidate_pair_ping_interval_id);
1598  rtc_config->continual_gathering_policy =
1599      JavaContinualGatheringPolicyToNativeType(
1600          jni, j_continual_gathering_policy);
1601}
1602
1603JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1604    JNIEnv *jni, jclass, jlong factory, jobject j_rtc_config,
1605    jobject j_constraints, jlong observer_p) {
1606  rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
1607      reinterpret_cast<PeerConnectionFactoryInterface*>(
1608          factoryFromJava(factory)));
1609
1610  PeerConnectionInterface::RTCConfiguration rtc_config;
1611  JavaRTCConfigurationToJsepRTCConfiguration(jni, j_rtc_config, &rtc_config);
1612
1613  jclass j_rtc_config_class = GetObjectClass(jni, j_rtc_config);
1614  jfieldID j_key_type_id = GetFieldID(jni, j_rtc_config_class, "keyType",
1615                                      "Lorg/webrtc/PeerConnection$KeyType;");
1616  jobject j_key_type = GetObjectField(jni, j_rtc_config, j_key_type_id);
1617
1618  // Create ECDSA certificate.
1619  if (JavaKeyTypeToNativeType(jni, j_key_type) == rtc::KT_ECDSA) {
1620    scoped_ptr<rtc::SSLIdentity> ssl_identity(
1621        rtc::SSLIdentity::Generate(webrtc::kIdentityName, rtc::KT_ECDSA));
1622    if (ssl_identity.get()) {
1623      rtc_config.certificates.push_back(
1624          rtc::RTCCertificate::Create(std::move(ssl_identity)));
1625      LOG(LS_INFO) << "ECDSA certificate created.";
1626    } else {
1627      // Failing to create certificate should not abort peer connection
1628      // creation. Instead default encryption (currently RSA) will be used.
1629      LOG(LS_WARNING) <<
1630          "Failed to generate SSLIdentity. Default encryption will be used.";
1631    }
1632  }
1633
1634  PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1635  observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1636  rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1637      rtc_config, observer->constraints(), NULL, NULL, observer));
1638  return (jlong)pc.release();
1639}
1640
1641static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1642    JNIEnv* jni, jobject j_pc) {
1643  jfieldID native_pc_id = GetFieldID(jni,
1644      GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1645  jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1646  return rtc::scoped_refptr<PeerConnectionInterface>(
1647      reinterpret_cast<PeerConnectionInterface*>(j_p));
1648}
1649
1650JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1651  const SessionDescriptionInterface* sdp =
1652      ExtractNativePC(jni, j_pc)->local_description();
1653  return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1654}
1655
1656JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1657  const SessionDescriptionInterface* sdp =
1658      ExtractNativePC(jni, j_pc)->remote_description();
1659  return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1660}
1661
1662JOW(jobject, PeerConnection_createDataChannel)(
1663    JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1664  DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1665  rtc::scoped_refptr<DataChannelInterface> channel(
1666      ExtractNativePC(jni, j_pc)->CreateDataChannel(
1667          JavaToStdString(jni, j_label), &init));
1668  // Mustn't pass channel.get() directly through NewObject to avoid reading its
1669  // vararg parameter as 64-bit and reading memory that doesn't belong to the
1670  // 32-bit parameter.
1671  jlong nativeChannelPtr = jlongFromPointer(channel.get());
1672  RTC_CHECK(nativeChannelPtr) << "Failed to create DataChannel";
1673  jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1674  jmethodID j_data_channel_ctor = GetMethodID(
1675      jni, j_data_channel_class, "<init>", "(J)V");
1676  jobject j_channel = jni->NewObject(
1677      j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
1678  CHECK_EXCEPTION(jni) << "error during NewObject";
1679  // Channel is now owned by Java object, and will be freed from there.
1680  int bumped_count = channel->AddRef();
1681  RTC_CHECK(bumped_count == 2) << "Unexpected refcount";
1682  return j_channel;
1683}
1684
1685JOW(void, PeerConnection_createOffer)(
1686    JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1687  ConstraintsWrapper* constraints =
1688      new ConstraintsWrapper(jni, j_constraints);
1689  rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
1690      new rtc::RefCountedObject<CreateSdpObserverWrapper>(
1691          jni, j_observer, constraints));
1692  ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1693}
1694
1695JOW(void, PeerConnection_createAnswer)(
1696    JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1697  ConstraintsWrapper* constraints =
1698      new ConstraintsWrapper(jni, j_constraints);
1699  rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
1700      new rtc::RefCountedObject<CreateSdpObserverWrapper>(
1701          jni, j_observer, constraints));
1702  ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1703}
1704
1705// Helper to create a SessionDescriptionInterface from a SessionDescription.
1706static SessionDescriptionInterface* JavaSdpToNativeSdp(
1707    JNIEnv* jni, jobject j_sdp) {
1708  jfieldID j_type_id = GetFieldID(
1709      jni, GetObjectClass(jni, j_sdp), "type",
1710      "Lorg/webrtc/SessionDescription$Type;");
1711  jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1712  jmethodID j_canonical_form_id = GetMethodID(
1713      jni, GetObjectClass(jni, j_type), "canonicalForm",
1714      "()Ljava/lang/String;");
1715  jstring j_type_string = (jstring)jni->CallObjectMethod(
1716      j_type, j_canonical_form_id);
1717  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
1718  std::string std_type = JavaToStdString(jni, j_type_string);
1719
1720  jfieldID j_description_id = GetFieldID(
1721      jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1722  jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1723  std::string std_description = JavaToStdString(jni, j_description);
1724
1725  return webrtc::CreateSessionDescription(
1726      std_type, std_description, NULL);
1727}
1728
1729JOW(void, PeerConnection_setLocalDescription)(
1730    JNIEnv* jni, jobject j_pc,
1731    jobject j_observer, jobject j_sdp) {
1732  rtc::scoped_refptr<SetSdpObserverWrapper> observer(
1733      new rtc::RefCountedObject<SetSdpObserverWrapper>(
1734          jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1735  ExtractNativePC(jni, j_pc)->SetLocalDescription(
1736      observer, JavaSdpToNativeSdp(jni, j_sdp));
1737}
1738
1739JOW(void, PeerConnection_setRemoteDescription)(
1740    JNIEnv* jni, jobject j_pc,
1741    jobject j_observer, jobject j_sdp) {
1742  rtc::scoped_refptr<SetSdpObserverWrapper> observer(
1743      new rtc::RefCountedObject<SetSdpObserverWrapper>(
1744          jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1745  ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1746      observer, JavaSdpToNativeSdp(jni, j_sdp));
1747}
1748
1749JOW(jboolean, PeerConnection_setConfiguration)(
1750    JNIEnv* jni, jobject j_pc, jobject j_rtc_config) {
1751  PeerConnectionInterface::RTCConfiguration rtc_config;
1752  JavaRTCConfigurationToJsepRTCConfiguration(jni, j_rtc_config, &rtc_config);
1753  return ExtractNativePC(jni, j_pc)->SetConfiguration(rtc_config);
1754}
1755
1756JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1757    JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1758    jint j_sdp_mline_index, jstring j_candidate_sdp) {
1759  std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1760  std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1761  scoped_ptr<IceCandidateInterface> candidate(
1762      webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1763  return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1764}
1765
1766JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1767    JNIEnv* jni, jobject j_pc, jlong native_stream) {
1768  return ExtractNativePC(jni, j_pc)->AddStream(
1769      reinterpret_cast<MediaStreamInterface*>(native_stream));
1770}
1771
1772JOW(void, PeerConnection_nativeRemoveLocalStream)(
1773    JNIEnv* jni, jobject j_pc, jlong native_stream) {
1774  ExtractNativePC(jni, j_pc)->RemoveStream(
1775      reinterpret_cast<MediaStreamInterface*>(native_stream));
1776}
1777
1778JOW(jobject, PeerConnection_nativeCreateSender)(
1779    JNIEnv* jni, jobject j_pc, jstring j_kind, jstring j_stream_id) {
1780  jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender");
1781  jmethodID j_rtp_sender_ctor =
1782      GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V");
1783
1784  std::string kind = JavaToStdString(jni, j_kind);
1785  std::string stream_id = JavaToStdString(jni, j_stream_id);
1786  rtc::scoped_refptr<RtpSenderInterface> sender =
1787      ExtractNativePC(jni, j_pc)->CreateSender(kind, stream_id);
1788  if (!sender.get()) {
1789    return nullptr;
1790  }
1791  jlong nativeSenderPtr = jlongFromPointer(sender.get());
1792  jobject j_sender =
1793      jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr);
1794  CHECK_EXCEPTION(jni) << "error during NewObject";
1795  // Sender is now owned by the Java object, and will be freed from
1796  // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders().
1797  sender->AddRef();
1798  return j_sender;
1799}
1800
1801JOW(jobject, PeerConnection_nativeGetSenders)(JNIEnv* jni, jobject j_pc) {
1802  jclass j_array_list_class = FindClass(jni, "java/util/ArrayList");
1803  jmethodID j_array_list_ctor =
1804      GetMethodID(jni, j_array_list_class, "<init>", "()V");
1805  jmethodID j_array_list_add =
1806      GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z");
1807  jobject j_senders = jni->NewObject(j_array_list_class, j_array_list_ctor);
1808  CHECK_EXCEPTION(jni) << "error during NewObject";
1809
1810  jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender");
1811  jmethodID j_rtp_sender_ctor =
1812      GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V");
1813
1814  auto senders = ExtractNativePC(jni, j_pc)->GetSenders();
1815  for (const auto& sender : senders) {
1816    jlong nativeSenderPtr = jlongFromPointer(sender.get());
1817    jobject j_sender =
1818        jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr);
1819    CHECK_EXCEPTION(jni) << "error during NewObject";
1820    // Sender is now owned by the Java object, and will be freed from
1821    // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders().
1822    sender->AddRef();
1823    jni->CallBooleanMethod(j_senders, j_array_list_add, j_sender);
1824    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
1825  }
1826  return j_senders;
1827}
1828
1829JOW(jobject, PeerConnection_nativeGetReceivers)(JNIEnv* jni, jobject j_pc) {
1830  jclass j_array_list_class = FindClass(jni, "java/util/ArrayList");
1831  jmethodID j_array_list_ctor =
1832      GetMethodID(jni, j_array_list_class, "<init>", "()V");
1833  jmethodID j_array_list_add =
1834      GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z");
1835  jobject j_receivers = jni->NewObject(j_array_list_class, j_array_list_ctor);
1836  CHECK_EXCEPTION(jni) << "error during NewObject";
1837
1838  jclass j_rtp_receiver_class = FindClass(jni, "org/webrtc/RtpReceiver");
1839  jmethodID j_rtp_receiver_ctor =
1840      GetMethodID(jni, j_rtp_receiver_class, "<init>", "(J)V");
1841
1842  auto receivers = ExtractNativePC(jni, j_pc)->GetReceivers();
1843  for (const auto& receiver : receivers) {
1844    jlong nativeReceiverPtr = jlongFromPointer(receiver.get());
1845    jobject j_receiver = jni->NewObject(j_rtp_receiver_class,
1846                                        j_rtp_receiver_ctor, nativeReceiverPtr);
1847    CHECK_EXCEPTION(jni) << "error during NewObject";
1848    // Receiver is now owned by Java object, and will be freed from there.
1849    receiver->AddRef();
1850    jni->CallBooleanMethod(j_receivers, j_array_list_add, j_receiver);
1851    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
1852  }
1853  return j_receivers;
1854}
1855
1856JOW(bool, PeerConnection_nativeGetStats)(
1857    JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1858  rtc::scoped_refptr<StatsObserverWrapper> observer(
1859      new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1860  return ExtractNativePC(jni, j_pc)->GetStats(
1861      observer,
1862      reinterpret_cast<MediaStreamTrackInterface*>(native_track),
1863      PeerConnectionInterface::kStatsOutputLevelStandard);
1864}
1865
1866JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1867  PeerConnectionInterface::SignalingState state =
1868      ExtractNativePC(jni, j_pc)->signaling_state();
1869  return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1870}
1871
1872JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1873  PeerConnectionInterface::IceConnectionState state =
1874      ExtractNativePC(jni, j_pc)->ice_connection_state();
1875  return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1876}
1877
1878JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1879  PeerConnectionInterface::IceGatheringState state =
1880      ExtractNativePC(jni, j_pc)->ice_gathering_state();
1881  return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state);
1882}
1883
1884JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1885  ExtractNativePC(jni, j_pc)->Close();
1886  return;
1887}
1888
1889JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1890  rtc::scoped_refptr<MediaSourceInterface> p(
1891      reinterpret_cast<MediaSourceInterface*>(j_p));
1892  return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1893}
1894
1895JOW(jobject, VideoCapturer_nativeCreateVideoCapturer)(
1896    JNIEnv* jni, jclass, jstring j_device_name) {
1897// Since we can't create platform specific java implementations in Java, we
1898// defer the creation to C land.
1899#if defined(ANDROID)
1900  // TODO(nisse): This case is intended to be deleted.
1901  jclass j_video_capturer_class(
1902      FindClass(jni, "org/webrtc/VideoCapturerAndroid"));
1903  const int camera_id = jni->CallStaticIntMethod(
1904      j_video_capturer_class,
1905      GetStaticMethodID(jni, j_video_capturer_class, "lookupDeviceName",
1906                        "(Ljava/lang/String;)I"),
1907      j_device_name);
1908  CHECK_EXCEPTION(jni) << "error during VideoCapturerAndroid.lookupDeviceName";
1909  if (camera_id == -1)
1910    return nullptr;
1911  jobject j_video_capturer = jni->NewObject(
1912      j_video_capturer_class,
1913      GetMethodID(jni, j_video_capturer_class, "<init>", "(I)V"), camera_id);
1914  CHECK_EXCEPTION(jni) << "error during creation of VideoCapturerAndroid";
1915  jfieldID helper_fid = GetFieldID(jni, j_video_capturer_class, "surfaceHelper",
1916                                   "Lorg/webrtc/SurfaceTextureHelper;");
1917
1918  rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate =
1919      new rtc::RefCountedObject<AndroidVideoCapturerJni>(
1920          jni, j_video_capturer,
1921          GetObjectField(jni, j_video_capturer, helper_fid));
1922  rtc::scoped_ptr<cricket::VideoCapturer> capturer(
1923      new webrtc::AndroidVideoCapturer(delegate));
1924
1925#else
1926  std::string device_name = JavaToStdString(jni, j_device_name);
1927  scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1928      cricket::DeviceManagerFactory::Create());
1929  RTC_CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
1930  cricket::Device device;
1931  if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1932    LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
1933    return 0;
1934  }
1935  scoped_ptr<cricket::VideoCapturer> capturer(
1936      device_manager->CreateVideoCapturer(device));
1937
1938  jclass j_video_capturer_class(
1939      FindClass(jni, "org/webrtc/VideoCapturer"));
1940  const jmethodID j_videocapturer_ctor(GetMethodID(
1941      jni, j_video_capturer_class, "<init>", "()V"));
1942  jobject j_video_capturer =
1943      jni->NewObject(j_video_capturer_class,
1944                     j_videocapturer_ctor);
1945  CHECK_EXCEPTION(jni) << "error during creation of VideoCapturer";
1946
1947#endif
1948  const jmethodID j_videocapturer_set_native_capturer(GetMethodID(
1949      jni, j_video_capturer_class, "setNativeCapturer", "(J)V"));
1950  jni->CallVoidMethod(j_video_capturer,
1951                      j_videocapturer_set_native_capturer,
1952                      jlongFromPointer(capturer.release()));
1953  CHECK_EXCEPTION(jni) << "error during setNativeCapturer";
1954  return j_video_capturer;
1955}
1956
1957JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1958    JNIEnv* jni, jclass, int x, int y) {
1959  scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
1960      cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1961  return (jlong)renderer.release();
1962}
1963
1964JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1965    JNIEnv* jni, jclass, jobject j_callbacks) {
1966  scoped_ptr<JavaVideoRendererWrapper> renderer(
1967      new JavaVideoRendererWrapper(jni, j_callbacks));
1968  return (jlong)renderer.release();
1969}
1970
1971JOW(void, VideoRenderer_nativeCopyPlane)(
1972    JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height,
1973    jint src_stride, jobject j_dst_buffer, jint dst_stride) {
1974  size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer);
1975  size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer);
1976  RTC_CHECK(src_stride >= width) << "Wrong source stride " << src_stride;
1977  RTC_CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride;
1978  RTC_CHECK(src_size >= src_stride * height)
1979      << "Insufficient source buffer capacity " << src_size;
1980  RTC_CHECK(dst_size >= dst_stride * height)
1981      << "Isufficient destination buffer capacity " << dst_size;
1982  uint8_t *src =
1983      reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
1984  uint8_t *dst =
1985      reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer));
1986  if (src_stride == dst_stride) {
1987    memcpy(dst, src, src_stride * height);
1988  } else {
1989    for (int i = 0; i < height; i++) {
1990      memcpy(dst, src, width);
1991      src += src_stride;
1992      dst += dst_stride;
1993    }
1994  }
1995}
1996
1997JOW(void, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
1998  reinterpret_cast<VideoSourceInterface*>(j_p)->Stop();
1999}
2000
2001JOW(void, VideoSource_restart)(
2002    JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
2003  reinterpret_cast<VideoSourceInterface*>(j_p_source)->Restart();
2004}
2005
2006JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
2007  return JavaStringFromStdString(
2008      jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
2009}
2010
2011JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
2012  return JavaStringFromStdString(
2013      jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
2014}
2015
2016JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
2017  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
2018}
2019
2020JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2021  return JavaEnumFromIndex(
2022      jni,
2023      "MediaStreamTrack$State",
2024      reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
2025}
2026
2027JOW(jboolean, MediaStreamTrack_nativeSetState)(
2028    JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
2029  MediaStreamTrackInterface::TrackState new_state =
2030      (MediaStreamTrackInterface::TrackState)j_new_state;
2031  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2032      ->set_state(new_state);
2033}
2034
2035JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2036    JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
2037  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2038      ->set_enabled(enabled);
2039}
2040
2041JOW(void, VideoTrack_nativeAddRenderer)(
2042    JNIEnv* jni, jclass,
2043    jlong j_video_track_pointer, jlong j_renderer_pointer) {
2044  reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
2045      reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2046}
2047
2048JOW(void, VideoTrack_nativeRemoveRenderer)(
2049    JNIEnv* jni, jclass,
2050    jlong j_video_track_pointer, jlong j_renderer_pointer) {
2051  reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
2052      reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2053}
2054
2055JOW(jlong, CallSessionFileRotatingLogSink_nativeAddSink)(
2056    JNIEnv* jni, jclass,
2057    jstring j_dirPath, jint j_maxFileSize, jint j_severity) {
2058  std::string dir_path = JavaToStdString(jni, j_dirPath);
2059  rtc::CallSessionFileRotatingLogSink* sink =
2060      new rtc::CallSessionFileRotatingLogSink(dir_path, j_maxFileSize);
2061  if (!sink->Init()) {
2062    LOG_V(rtc::LoggingSeverity::LS_WARNING) <<
2063        "Failed to init CallSessionFileRotatingLogSink for path " << dir_path;
2064    delete sink;
2065    return 0;
2066  }
2067  rtc::LogMessage::AddLogToStream(
2068      sink, static_cast<rtc::LoggingSeverity>(j_severity));
2069  return (jlong) sink;
2070}
2071
2072JOW(void, CallSessionFileRotatingLogSink_nativeDeleteSink)(
2073    JNIEnv* jni, jclass, jlong j_sink) {
2074  rtc::CallSessionFileRotatingLogSink* sink =
2075      reinterpret_cast<rtc::CallSessionFileRotatingLogSink*>(j_sink);
2076  rtc::LogMessage::RemoveLogToStream(sink);
2077  delete sink;
2078}
2079
2080JOW(jbyteArray, CallSessionFileRotatingLogSink_nativeGetLogData)(
2081    JNIEnv* jni, jclass, jstring j_dirPath) {
2082  std::string dir_path = JavaToStdString(jni, j_dirPath);
2083  rtc::scoped_ptr<rtc::CallSessionFileRotatingStream> stream(
2084      new rtc::CallSessionFileRotatingStream(dir_path));
2085  if (!stream->Open()) {
2086    LOG_V(rtc::LoggingSeverity::LS_WARNING) <<
2087        "Failed to open CallSessionFileRotatingStream for path " << dir_path;
2088    return jni->NewByteArray(0);
2089  }
2090  size_t log_size = 0;
2091  if (!stream->GetSize(&log_size) || log_size == 0) {
2092    LOG_V(rtc::LoggingSeverity::LS_WARNING) <<
2093        "CallSessionFileRotatingStream returns 0 size for path " << dir_path;
2094    return jni->NewByteArray(0);
2095  }
2096
2097  size_t read = 0;
2098  rtc::scoped_ptr<jbyte> buffer(static_cast<jbyte*>(malloc(log_size)));
2099  stream->ReadAll(buffer.get(), log_size, &read, nullptr);
2100
2101  jbyteArray result = jni->NewByteArray(read);
2102  jni->SetByteArrayRegion(result, 0, read, buffer.get());
2103
2104  return result;
2105}
2106
2107JOW(jboolean, RtpSender_nativeSetTrack)(JNIEnv* jni,
2108                                    jclass,
2109                                    jlong j_rtp_sender_pointer,
2110                                    jlong j_track_pointer) {
2111  return reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)
2112      ->SetTrack(reinterpret_cast<MediaStreamTrackInterface*>(j_track_pointer));
2113}
2114
2115JOW(jlong, RtpSender_nativeGetTrack)(JNIEnv* jni,
2116                                  jclass,
2117                                  jlong j_rtp_sender_pointer,
2118                                  jlong j_track_pointer) {
2119  return jlongFromPointer(
2120      reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)
2121          ->track()
2122          .release());
2123}
2124
2125JOW(jstring, RtpSender_nativeId)(
2126    JNIEnv* jni, jclass, jlong j_rtp_sender_pointer) {
2127  return JavaStringFromStdString(
2128      jni, reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)->id());
2129}
2130
2131JOW(void, RtpSender_free)(JNIEnv* jni, jclass, jlong j_rtp_sender_pointer) {
2132  reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)->Release();
2133}
2134
2135JOW(jlong, RtpReceiver_nativeGetTrack)(JNIEnv* jni,
2136                                    jclass,
2137                                    jlong j_rtp_receiver_pointer,
2138                                    jlong j_track_pointer) {
2139  return jlongFromPointer(
2140      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)
2141          ->track()
2142          .release());
2143}
2144
2145JOW(jstring, RtpReceiver_nativeId)(
2146    JNIEnv* jni, jclass, jlong j_rtp_receiver_pointer) {
2147  return JavaStringFromStdString(
2148      jni,
2149      reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->id());
2150}
2151
2152JOW(void, RtpReceiver_free)(JNIEnv* jni, jclass, jlong j_rtp_receiver_pointer) {
2153  reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->Release();
2154}
2155
2156}  // namespace webrtc_jni
2157