12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/*
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * libjingle
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright 2013, Google Inc.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * modification, are permitted provided that the following conditions are met:
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *  1. Redistributions of source code must retain the above copyright notice,
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     this list of conditions and the following disclaimer.
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *  2. Redistributions in binary form must reproduce the above copyright notice,
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *     this list of conditions and the following disclaimer in the documentation
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *     and/or other materials provided with the distribution.
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *  3. The name of the author may not be used to endorse or promote products
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *     derived from this software without specific prior written permission.
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) */
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Hints for future visitors:
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// This entire file is an implementation detail of the org.webrtc Java package,
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The layout of this file is roughly:
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// - various helper C++ functions & classes that wrap Java counterparts and
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)//   expose a C++ interface that can be passed to the C++ PeerConnection APIs
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// - implementations of methods declared "static" in the Java package (named
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)//   things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)//   the JNI spec).
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Lifecycle notes: objects are owned where they will be called; in other words
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// FooObservers are owned by C++-land, and user-callable objects (e.g.
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// PeerConnection and VideoTrack) are owned by Java-land.
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// ref simulating the jlong held in Java-land, and then Release()s the ref in
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// the respective free call.  Sometimes this AddRef is implicit in the
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// construction of a scoped_refptr<> which is then .release()d.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Any persistent (non-local) references from C++ to Java must be global or weak
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (in which case they must be checked before use)!
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// call.  In this file this is done in CHECK_EXCEPTION, making for much easier
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// debugging in case of failure (the alternative is to wait for control to
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// return to the Java frame that called code in this file, at which point it's
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// impossible to tell which JNI call broke).
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <jni.h>
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#undef JNIEXPORT
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define JNIEXPORT __attribute__((visibility("default")))
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <asm/unistd.h>
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <sys/prctl.h>
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/syscall.h>
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h>
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <limits>
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <map>
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/app/webrtc/mediaconstraintsinterface.h"
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/app/webrtc/peerconnectioninterface.h"
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/app/webrtc/videosourceinterface.h"
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "talk/media/base/videocapturer.h"
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/media/base/videorenderer.h"
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/media/devices/videorendererfactory.h"
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "talk/media/webrtc/webrtcvideocapturer.h"
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/icu/source/common/unicode/unistr.h"
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/libyuv/include/libyuv/convert.h"
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/libyuv/include/libyuv/convert_from.h"
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/libyuv/include/libyuv/video_common.h"
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webrtc/base/bind.h"
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "webrtc/base/checks.h"
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "webrtc/base/logging.h"
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "webrtc/base/messagequeue.h"
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webrtc/base/ssladapter.h"
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "webrtc/common_video/interface/texture_video_frame.h"
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webrtc/system_wrappers/interface/compile_assert.h"
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webrtc/system_wrappers/interface/trace.h"
88#include "webrtc/video_engine/include/vie_base.h"
89#include "webrtc/voice_engine/include/voe_base.h"
90
91#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
92#include <android/log.h>
93#include "webrtc/modules/video_capture/video_capture_internal.h"
94#include "webrtc/modules/video_render/video_render_internal.h"
95#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
96#include "webrtc/system_wrappers/interface/tick_util.h"
97using webrtc::CodecSpecificInfo;
98using webrtc::DecodedImageCallback;
99using webrtc::EncodedImage;
100using webrtc::I420VideoFrame;
101using webrtc::LogcatTraceContext;
102using webrtc::RTPFragmentationHeader;
103using webrtc::TextureVideoFrame;
104using webrtc::TickTime;
105using webrtc::VideoCodec;
106#endif
107
108using icu::UnicodeString;
109using rtc::Bind;
110using rtc::Thread;
111using rtc::ThreadManager;
112using rtc::scoped_ptr;
113using webrtc::AudioSourceInterface;
114using webrtc::AudioTrackInterface;
115using webrtc::AudioTrackVector;
116using webrtc::CreateSessionDescriptionObserver;
117using webrtc::DataBuffer;
118using webrtc::DataChannelInit;
119using webrtc::DataChannelInterface;
120using webrtc::DataChannelObserver;
121using webrtc::IceCandidateInterface;
122using webrtc::NativeHandle;
123using webrtc::MediaConstraintsInterface;
124using webrtc::MediaSourceInterface;
125using webrtc::MediaStreamInterface;
126using webrtc::MediaStreamTrackInterface;
127using webrtc::PeerConnectionFactoryInterface;
128using webrtc::PeerConnectionInterface;
129using webrtc::PeerConnectionObserver;
130using webrtc::SessionDescriptionInterface;
131using webrtc::SetSessionDescriptionObserver;
132using webrtc::StatsObserver;
133using webrtc::StatsReport;
134using webrtc::VideoRendererInterface;
135using webrtc::VideoSourceInterface;
136using webrtc::VideoTrackInterface;
137using webrtc::VideoTrackVector;
138using webrtc::kVideoCodecVP8;
139
140// Abort the process if |jni| has a Java exception pending.
141// This macros uses the comma operator to execute ExceptionDescribe
142// and ExceptionClear ignoring their return values and sending ""
143// to the error stream.
144#define CHECK_EXCEPTION(jni)    \
145  CHECK(!jni->ExceptionCheck()) \
146      << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
147
148// Helper that calls ptr->Release() and aborts the process with a useful
149// message if that didn't actually delete *ptr because of extra refcounts.
150#define CHECK_RELEASE(ptr) \
151  CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
152
153namespace {
154
155static JavaVM* g_jvm = NULL;  // Set in JNI_OnLoad().
156
157static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
158// Key for per-thread JNIEnv* data.  Non-NULL in threads attached to |g_jvm| by
159// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
160// were attached by the JVM because of a Java->native call.
161static pthread_key_t g_jni_ptr;
162
163#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
164// Set in PeerConnectionFactory_initializeAndroidGlobals().
165static bool factory_static_initialized = false;
166#endif
167
168
169// Return thread ID as a string.
170static std::string GetThreadId() {
171  char buf[21];  // Big enough to hold a kuint64max plus terminating NULL.
172  CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
173           sizeof(buf))
174      << "Thread id is bigger than uint64??";
175  return std::string(buf);
176}
177
178// Return the current thread's name.
179static std::string GetThreadName() {
180  char name[17];
181  CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
182  name[16] = '\0';
183  return std::string(name);
184}
185
186// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
187static JNIEnv* GetEnv() {
188  void* env = NULL;
189  jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
190  CHECK(((env != NULL) && (status == JNI_OK)) ||
191        ((env == NULL) && (status == JNI_EDETACHED)))
192      << "Unexpected GetEnv return: " << status << ":" << env;
193  return reinterpret_cast<JNIEnv*>(env);
194}
195
196static void ThreadDestructor(void* prev_jni_ptr) {
197  // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
198  // we were responsible for originally attaching the thread, so are responsible
199  // for detaching it now.  However, because some JVM implementations (notably
200  // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
201  // the JVMs accounting info for this thread may already be wiped out by the
202  // time this is called. Thus it may appear we are already detached even though
203  // it was our responsibility to detach!  Oh well.
204  if (!GetEnv())
205    return;
206
207  CHECK(GetEnv() == prev_jni_ptr)
208      << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
209  jint status = g_jvm->DetachCurrentThread();
210  CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
211  CHECK(!GetEnv()) << "Detaching was a successful no-op???";
212}
213
214static void CreateJNIPtrKey() {
215  CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
216      << "pthread_key_create";
217}
218
219// Return a |JNIEnv*| usable on this thread.  Attaches to |g_jvm| if necessary.
220static JNIEnv* AttachCurrentThreadIfNeeded() {
221  JNIEnv* jni = GetEnv();
222  if (jni)
223    return jni;
224  CHECK(!pthread_getspecific(g_jni_ptr))
225      << "TLS has a JNIEnv* but not attached?";
226
227  char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
228  JavaVMAttachArgs args;
229  args.version = JNI_VERSION_1_6;
230  args.name = name;
231  args.group = NULL;
232  // Deal with difference in signatures between Oracle's jni.h and Android's.
233#ifdef _JAVASOFT_JNI_H_  // Oracle's jni.h violates the JNI spec!
234  void* env = NULL;
235#else
236  JNIEnv* env = NULL;
237#endif
238  CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
239  free(name);
240  CHECK(env) << "AttachCurrentThread handed back NULL!";
241  jni = reinterpret_cast<JNIEnv*>(env);
242  CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
243  return jni;
244}
245
246// Return a |jlong| that will correctly convert back to |ptr|.  This is needed
247// because the alternative (of silently passing a 32-bit pointer to a vararg
248// function expecting a 64-bit param) picks up garbage in the high 32 bits.
249static jlong jlongFromPointer(void* ptr) {
250  COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
251                 Time_to_rethink_the_use_of_jlongs);
252  // Going through intptr_t to be obvious about the definedness of the
253  // conversion from pointer to integral type.  intptr_t to jlong is a standard
254  // widening by the COMPILE_ASSERT above.
255  jlong ret = reinterpret_cast<intptr_t>(ptr);
256  assert(reinterpret_cast<void*>(ret) == ptr);
257  return ret;
258}
259
260// Android's FindClass() is trickier than usual because the app-specific
261// ClassLoader is not consulted when there is no app-specific frame on the
262// stack.  Consequently, we only look up classes once in JNI_OnLoad.
263// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
264class ClassReferenceHolder {
265 public:
266  explicit ClassReferenceHolder(JNIEnv* jni) {
267    LoadClass(jni, "java/nio/ByteBuffer");
268    LoadClass(jni, "org/webrtc/AudioTrack");
269    LoadClass(jni, "org/webrtc/DataChannel");
270    LoadClass(jni, "org/webrtc/DataChannel$Buffer");
271    LoadClass(jni, "org/webrtc/DataChannel$Init");
272    LoadClass(jni, "org/webrtc/DataChannel$State");
273    LoadClass(jni, "org/webrtc/IceCandidate");
274#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
275    LoadClass(jni, "android/graphics/SurfaceTexture");
276    LoadClass(jni, "android/opengl/EGLContext");
277    LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
278    LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
279    LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
280    LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
281#endif
282    LoadClass(jni, "org/webrtc/MediaSource$State");
283    LoadClass(jni, "org/webrtc/MediaStream");
284    LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
285    LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
286    LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
287    LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
288    LoadClass(jni, "org/webrtc/SessionDescription");
289    LoadClass(jni, "org/webrtc/SessionDescription$Type");
290    LoadClass(jni, "org/webrtc/StatsReport");
291    LoadClass(jni, "org/webrtc/StatsReport$Value");
292    LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
293    LoadClass(jni, "org/webrtc/VideoTrack");
294  }
295
296  ~ClassReferenceHolder() {
297    CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
298  }
299
300  void FreeReferences(JNIEnv* jni) {
301    for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
302         it != classes_.end(); ++it) {
303      jni->DeleteGlobalRef(it->second);
304    }
305    classes_.clear();
306  }
307
308  jclass GetClass(const std::string& name) {
309    std::map<std::string, jclass>::iterator it = classes_.find(name);
310    CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
311    return it->second;
312  }
313
314 private:
315  void LoadClass(JNIEnv* jni, const std::string& name) {
316    jclass localRef = jni->FindClass(name.c_str());
317    CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
318    CHECK(localRef) << name;
319    jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
320    CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
321    CHECK(globalRef) << name;
322    bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
323    CHECK(inserted) << "Duplicate class name: " << name;
324  }
325
326  std::map<std::string, jclass> classes_;
327};
328
329// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
330static ClassReferenceHolder* g_class_reference_holder = NULL;
331
332// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
333// object/class/method/field is non-null.
334jmethodID GetMethodID(
335    JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
336  jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
337  CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
338                       << signature;
339  CHECK(m) << name << ", " << signature;
340  return m;
341}
342
343jmethodID GetStaticMethodID(
344    JNIEnv* jni, jclass c, const char* name, const char* signature) {
345  jmethodID m = jni->GetStaticMethodID(c, name, signature);
346  CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
347                       << signature;
348  CHECK(m) << name << ", " << signature;
349  return m;
350}
351
352jfieldID GetFieldID(
353    JNIEnv* jni, jclass c, const char* name, const char* signature) {
354  jfieldID f = jni->GetFieldID(c, name, signature);
355  CHECK_EXCEPTION(jni) << "error during GetFieldID";
356  CHECK(f) << name << ", " << signature;
357  return f;
358}
359
360// Returns a global reference guaranteed to be valid for the lifetime of the
361// process.
362jclass FindClass(JNIEnv* jni, const char* name) {
363  return g_class_reference_holder->GetClass(name);
364}
365
366jclass GetObjectClass(JNIEnv* jni, jobject object) {
367  jclass c = jni->GetObjectClass(object);
368  CHECK_EXCEPTION(jni) << "error during GetObjectClass";
369  CHECK(c) << "GetObjectClass returned NULL";
370  return c;
371}
372
373jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
374  jobject o = jni->GetObjectField(object, id);
375  CHECK_EXCEPTION(jni) << "error during GetObjectField";
376  CHECK(o) << "GetObjectField returned NULL";
377  return o;
378}
379
380jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
381  return static_cast<jstring>(GetObjectField(jni, object, id));
382}
383
384jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
385  jlong l = jni->GetLongField(object, id);
386  CHECK_EXCEPTION(jni) << "error during GetLongField";
387  return l;
388}
389
390jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
391  jint i = jni->GetIntField(object, id);
392  CHECK_EXCEPTION(jni) << "error during GetIntField";
393  return i;
394}
395
396bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
397  jboolean b = jni->GetBooleanField(object, id);
398  CHECK_EXCEPTION(jni) << "error during GetBooleanField";
399  return b;
400}
401
402jobject NewGlobalRef(JNIEnv* jni, jobject o) {
403  jobject ret = jni->NewGlobalRef(o);
404  CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
405  CHECK(ret);
406  return ret;
407}
408
409void DeleteGlobalRef(JNIEnv* jni, jobject o) {
410  jni->DeleteGlobalRef(o);
411  CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
412}
413
414// Given a jweak reference, allocate a (strong) local reference scoped to the
415// lifetime of this object if the weak reference is still valid, or NULL
416// otherwise.
417class WeakRef {
418 public:
419  WeakRef(JNIEnv* jni, jweak ref)
420      : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
421    CHECK_EXCEPTION(jni) << "error during NewLocalRef";
422  }
423  ~WeakRef() {
424    if (obj_) {
425      jni_->DeleteLocalRef(obj_);
426      CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
427    }
428  }
429  jobject obj() { return obj_; }
430
431 private:
432  JNIEnv* const jni_;
433  jobject const obj_;
434};
435
436// Scope Java local references to the lifetime of this object.  Use in all C++
437// callbacks (i.e. entry points that don't originate in a Java callstack
438// through a "native" method call).
439class ScopedLocalRefFrame {
440 public:
441  explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
442    CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
443  }
444  ~ScopedLocalRefFrame() {
445    jni_->PopLocalFrame(NULL);
446  }
447
448 private:
449  JNIEnv* jni_;
450};
451
452// Scoped holder for global Java refs.
453template<class T>  // T is jclass, jobject, jintArray, etc.
454class ScopedGlobalRef {
455 public:
456  ScopedGlobalRef(JNIEnv* jni, T obj)
457      : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
458  ~ScopedGlobalRef() {
459    DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
460  }
461  T operator*() const {
462    return obj_;
463  }
464 private:
465  T obj_;
466};
467
468// Java references to "null" can only be distinguished as such in C++ by
469// creating a local reference, so this helper wraps that logic.
470static bool IsNull(JNIEnv* jni, jobject obj) {
471  ScopedLocalRefFrame local_ref_frame(jni);
472  return jni->NewLocalRef(obj) == NULL;
473}
474
475// Return the (singleton) Java Enum object corresponding to |index|;
476// |state_class_fragment| is something like "MediaSource$State".
477jobject JavaEnumFromIndex(
478    JNIEnv* jni, const std::string& state_class_fragment, int index) {
479  std::string state_class_name = "org/webrtc/" + state_class_fragment;
480  jclass state_class = FindClass(jni, state_class_name.c_str());
481  jmethodID state_values_id = GetStaticMethodID(
482      jni, state_class, "values", ("()[L" + state_class_name  + ";").c_str());
483  jobjectArray state_values = static_cast<jobjectArray>(
484      jni->CallStaticObjectMethod(state_class, state_values_id));
485  CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
486  jobject ret = jni->GetObjectArrayElement(state_values, index);
487  CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
488  return ret;
489}
490
491// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
492static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
493  UnicodeString ustr(UnicodeString::fromUTF8(native));
494  jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
495  CHECK_EXCEPTION(jni) << "error during NewString";
496  return jstr;
497}
498
499// Given a (UTF-16) jstring return a new UTF-8 native string.
500static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
501  const jchar* jchars = jni->GetStringChars(j_string, NULL);
502  CHECK_EXCEPTION(jni) << "Error during GetStringChars";
503  UnicodeString ustr(jchars, jni->GetStringLength(j_string));
504  CHECK_EXCEPTION(jni) << "Error during GetStringLength";
505  jni->ReleaseStringChars(j_string, jchars);
506  CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
507  std::string ret;
508  return ustr.toUTF8String(ret);
509}
510
511static DataChannelInit JavaDataChannelInitToNative(
512    JNIEnv* jni, jobject j_init) {
513  DataChannelInit init;
514
515  jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
516  jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
517  jfieldID max_retransmit_time_id =
518      GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
519  jfieldID max_retransmits_id =
520      GetFieldID(jni, j_init_class, "maxRetransmits", "I");
521  jfieldID protocol_id =
522      GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
523  jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
524  jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
525
526  init.ordered = GetBooleanField(jni, j_init, ordered_id);
527  init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
528  init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
529  init.protocol = JavaToStdString(
530      jni, GetStringField(jni, j_init, protocol_id));
531  init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
532  init.id = GetIntField(jni, j_init, id_id);
533
534  return init;
535}
536
537class ConstraintsWrapper;
538
539// Adapter between the C++ PeerConnectionObserver interface and the Java
540// PeerConnection.Observer interface.  Wraps an instance of the Java interface
541// and dispatches C++ callbacks to Java.
542class PCOJava : public PeerConnectionObserver {
543 public:
544  PCOJava(JNIEnv* jni, jobject j_observer)
545      : j_observer_global_(jni, j_observer),
546        j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
547        j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
548        j_media_stream_ctor_(GetMethodID(
549            jni, *j_media_stream_class_, "<init>", "(J)V")),
550        j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
551        j_audio_track_ctor_(GetMethodID(
552            jni, *j_audio_track_class_, "<init>", "(J)V")),
553        j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
554        j_video_track_ctor_(GetMethodID(
555            jni, *j_video_track_class_, "<init>", "(J)V")),
556        j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
557        j_data_channel_ctor_(GetMethodID(
558            jni, *j_data_channel_class_, "<init>", "(J)V")) {
559  }
560
561  virtual ~PCOJava() {}
562
563  virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
564    ScopedLocalRefFrame local_ref_frame(jni());
565    std::string sdp;
566    CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
567    jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
568    jmethodID ctor = GetMethodID(jni(), candidate_class,
569        "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
570    jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
571    jstring j_sdp = JavaStringFromStdString(jni(), sdp);
572    jobject j_candidate = jni()->NewObject(
573        candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
574    CHECK_EXCEPTION(jni()) << "error during NewObject";
575    jmethodID m = GetMethodID(jni(), *j_observer_class_,
576                              "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
577    jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
578    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
579  }
580
581  virtual void OnError() OVERRIDE {
582    ScopedLocalRefFrame local_ref_frame(jni());
583    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
584    jni()->CallVoidMethod(*j_observer_global_, m);
585    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
586  }
587
588  virtual void OnSignalingChange(
589      PeerConnectionInterface::SignalingState new_state) OVERRIDE {
590    ScopedLocalRefFrame local_ref_frame(jni());
591    jmethodID m = GetMethodID(
592        jni(), *j_observer_class_, "onSignalingChange",
593        "(Lorg/webrtc/PeerConnection$SignalingState;)V");
594    jobject new_state_enum =
595        JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
596    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
597    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
598  }
599
600  virtual void OnIceConnectionChange(
601      PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
602    ScopedLocalRefFrame local_ref_frame(jni());
603    jmethodID m = GetMethodID(
604        jni(), *j_observer_class_, "onIceConnectionChange",
605        "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
606    jobject new_state_enum = JavaEnumFromIndex(
607        jni(), "PeerConnection$IceConnectionState", new_state);
608    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
609    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
610  }
611
612  virtual void OnIceGatheringChange(
613      PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
614    ScopedLocalRefFrame local_ref_frame(jni());
615    jmethodID m = GetMethodID(
616        jni(), *j_observer_class_, "onIceGatheringChange",
617        "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
618    jobject new_state_enum = JavaEnumFromIndex(
619        jni(), "PeerConnection$IceGatheringState", new_state);
620    jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
621    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
622  }
623
624  virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
625    ScopedLocalRefFrame local_ref_frame(jni());
626    jobject j_stream = jni()->NewObject(
627        *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
628    CHECK_EXCEPTION(jni()) << "error during NewObject";
629
630    AudioTrackVector audio_tracks = stream->GetAudioTracks();
631    for (size_t i = 0; i < audio_tracks.size(); ++i) {
632      AudioTrackInterface* track = audio_tracks[i];
633      jstring id = JavaStringFromStdString(jni(), track->id());
634      jobject j_track = jni()->NewObject(
635          *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
636      CHECK_EXCEPTION(jni()) << "error during NewObject";
637      jfieldID audio_tracks_id = GetFieldID(jni(),
638                                            *j_media_stream_class_,
639                                            "audioTracks",
640                                            "Ljava/util/LinkedList;");
641      jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
642      jmethodID add = GetMethodID(jni(),
643                                  GetObjectClass(jni(), audio_tracks),
644                                  "add",
645                                  "(Ljava/lang/Object;)Z");
646      jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
647      CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
648      CHECK(added);
649    }
650
651    VideoTrackVector video_tracks = stream->GetVideoTracks();
652    for (size_t i = 0; i < video_tracks.size(); ++i) {
653      VideoTrackInterface* track = video_tracks[i];
654      jstring id = JavaStringFromStdString(jni(), track->id());
655      jobject j_track = jni()->NewObject(
656          *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
657      CHECK_EXCEPTION(jni()) << "error during NewObject";
658      jfieldID video_tracks_id = GetFieldID(jni(),
659                                            *j_media_stream_class_,
660                                            "videoTracks",
661                                            "Ljava/util/LinkedList;");
662      jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
663      jmethodID add = GetMethodID(jni(),
664                                  GetObjectClass(jni(), video_tracks),
665                                  "add",
666                                  "(Ljava/lang/Object;)Z");
667      jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
668      CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
669      CHECK(added);
670    }
671    streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
672    CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
673
674    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
675                              "(Lorg/webrtc/MediaStream;)V");
676    jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
677    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
678  }
679
680  virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
681    ScopedLocalRefFrame local_ref_frame(jni());
682    NativeToJavaStreamsMap::iterator it = streams_.find(stream);
683    CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
684
685    WeakRef s(jni(), it->second);
686    streams_.erase(it);
687    if (!s.obj())
688      return;
689
690    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
691                              "(Lorg/webrtc/MediaStream;)V");
692    jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
693    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
694  }
695
696  virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
697    ScopedLocalRefFrame local_ref_frame(jni());
698    jobject j_channel = jni()->NewObject(
699        *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
700    CHECK_EXCEPTION(jni()) << "error during NewObject";
701
702    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
703                              "(Lorg/webrtc/DataChannel;)V");
704    jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
705
706    // Channel is now owned by Java object, and will be freed from
707    // DataChannel.dispose().  Important that this be done _after_ the
708    // CallVoidMethod above as Java code might call back into native code and be
709    // surprised to see a refcount of 2.
710    int bumped_count = channel->AddRef();
711    CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
712
713    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
714  }
715
716  virtual void OnRenegotiationNeeded() OVERRIDE {
717    ScopedLocalRefFrame local_ref_frame(jni());
718    jmethodID m =
719        GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
720    jni()->CallVoidMethod(*j_observer_global_, m);
721    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
722  }
723
724  void SetConstraints(ConstraintsWrapper* constraints) {
725    CHECK(!constraints_.get()) << "constraints already set!";
726    constraints_.reset(constraints);
727  }
728
729  const ConstraintsWrapper* constraints() { return constraints_.get(); }
730
731 private:
732  JNIEnv* jni() {
733    return AttachCurrentThreadIfNeeded();
734  }
735
736  const ScopedGlobalRef<jobject> j_observer_global_;
737  const ScopedGlobalRef<jclass> j_observer_class_;
738  const ScopedGlobalRef<jclass> j_media_stream_class_;
739  const jmethodID j_media_stream_ctor_;
740  const ScopedGlobalRef<jclass> j_audio_track_class_;
741  const jmethodID j_audio_track_ctor_;
742  const ScopedGlobalRef<jclass> j_video_track_class_;
743  const jmethodID j_video_track_ctor_;
744  const ScopedGlobalRef<jclass> j_data_channel_class_;
745  const jmethodID j_data_channel_ctor_;
746  typedef std::map<void*, jweak> NativeToJavaStreamsMap;
747  NativeToJavaStreamsMap streams_;  // C++ -> Java streams.
748  scoped_ptr<ConstraintsWrapper> constraints_;
749};
750
751// Wrapper for a Java MediaConstraints object.  Copies all needed data so when
752// the constructor returns the Java object is no longer needed.
753class ConstraintsWrapper : public MediaConstraintsInterface {
754 public:
755  ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
756    PopulateConstraintsFromJavaPairList(
757        jni, j_constraints, "mandatory", &mandatory_);
758    PopulateConstraintsFromJavaPairList(
759        jni, j_constraints, "optional", &optional_);
760  }
761
762  virtual ~ConstraintsWrapper() {}
763
764  // MediaConstraintsInterface.
765  virtual const Constraints& GetMandatory() const OVERRIDE {
766    return mandatory_;
767  }
768
769  virtual const Constraints& GetOptional() const OVERRIDE {
770    return optional_;
771  }
772
773 private:
774  // Helper for translating a List<Pair<String, String>> to a Constraints.
775  static void PopulateConstraintsFromJavaPairList(
776      JNIEnv* jni, jobject j_constraints,
777      const char* field_name, Constraints* field) {
778    jfieldID j_id = GetFieldID(jni,
779        GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
780    jobject j_list = GetObjectField(jni, j_constraints, j_id);
781    jmethodID j_iterator_id = GetMethodID(jni,
782        GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
783    jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
784    CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
785    jmethodID j_has_next = GetMethodID(jni,
786        GetObjectClass(jni, j_iterator), "hasNext", "()Z");
787    jmethodID j_next = GetMethodID(jni,
788        GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
789    while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
790      CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
791      jobject entry = jni->CallObjectMethod(j_iterator, j_next);
792      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
793      jmethodID get_key = GetMethodID(jni,
794          GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
795      jstring j_key = reinterpret_cast<jstring>(
796          jni->CallObjectMethod(entry, get_key));
797      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
798      jmethodID get_value = GetMethodID(jni,
799          GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
800      jstring j_value = reinterpret_cast<jstring>(
801          jni->CallObjectMethod(entry, get_value));
802      CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
803      field->push_back(Constraint(JavaToStdString(jni, j_key),
804                                  JavaToStdString(jni, j_value)));
805    }
806    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
807  }
808
809  Constraints mandatory_;
810  Constraints optional_;
811};
812
813static jobject JavaSdpFromNativeSdp(
814    JNIEnv* jni, const SessionDescriptionInterface* desc) {
815  std::string sdp;
816  CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
817  jstring j_description = JavaStringFromStdString(jni, sdp);
818
819  jclass j_type_class = FindClass(
820      jni, "org/webrtc/SessionDescription$Type");
821  jmethodID j_type_from_canonical = GetStaticMethodID(
822      jni, j_type_class, "fromCanonicalForm",
823      "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
824  jstring j_type_string = JavaStringFromStdString(jni, desc->type());
825  jobject j_type = jni->CallStaticObjectMethod(
826      j_type_class, j_type_from_canonical, j_type_string);
827  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
828
829  jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
830  jmethodID j_sdp_ctor = GetMethodID(
831      jni, j_sdp_class, "<init>",
832      "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
833  jobject j_sdp = jni->NewObject(
834      j_sdp_class, j_sdp_ctor, j_type, j_description);
835  CHECK_EXCEPTION(jni) << "error during NewObject";
836  return j_sdp;
837}
838
839template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
840class SdpObserverWrapper : public T {
841 public:
842  SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
843                     ConstraintsWrapper* constraints)
844      : constraints_(constraints),
845        j_observer_global_(jni, j_observer),
846        j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
847  }
848
849  virtual ~SdpObserverWrapper() {}
850
851  // Can't mark OVERRIDE because of templating.
852  virtual void OnSuccess() {
853    ScopedLocalRefFrame local_ref_frame(jni());
854    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
855    jni()->CallVoidMethod(*j_observer_global_, m);
856    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
857  }
858
859  // Can't mark OVERRIDE because of templating.
860  virtual void OnSuccess(SessionDescriptionInterface* desc) {
861    ScopedLocalRefFrame local_ref_frame(jni());
862    jmethodID m = GetMethodID(
863        jni(), *j_observer_class_, "onCreateSuccess",
864        "(Lorg/webrtc/SessionDescription;)V");
865    jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
866    jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
867    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
868  }
869
870 protected:
871  // Common implementation for failure of Set & Create types, distinguished by
872  // |op| being "Set" or "Create".
873  void OnFailure(const std::string& op, const std::string& error) {
874    jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
875                              "(Ljava/lang/String;)V");
876    jstring j_error_string = JavaStringFromStdString(jni(), error);
877    jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
878    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
879  }
880
881  JNIEnv* jni() {
882    return AttachCurrentThreadIfNeeded();
883  }
884
885 private:
886  scoped_ptr<ConstraintsWrapper> constraints_;
887  const ScopedGlobalRef<jobject> j_observer_global_;
888  const ScopedGlobalRef<jclass> j_observer_class_;
889};
890
891class CreateSdpObserverWrapper
892    : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
893 public:
894  CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
895                           ConstraintsWrapper* constraints)
896      : SdpObserverWrapper(jni, j_observer, constraints) {}
897
898  virtual void OnFailure(const std::string& error) OVERRIDE {
899    ScopedLocalRefFrame local_ref_frame(jni());
900    SdpObserverWrapper::OnFailure(std::string("Create"), error);
901  }
902};
903
904class SetSdpObserverWrapper
905    : public SdpObserverWrapper<SetSessionDescriptionObserver> {
906 public:
907  SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
908                        ConstraintsWrapper* constraints)
909      : SdpObserverWrapper(jni, j_observer, constraints) {}
910
911  virtual void OnFailure(const std::string& error) OVERRIDE {
912    ScopedLocalRefFrame local_ref_frame(jni());
913    SdpObserverWrapper::OnFailure(std::string("Set"), error);
914  }
915};
916
917// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
918// and dispatching the callback from C++ back to Java.
919class DataChannelObserverWrapper : public DataChannelObserver {
920 public:
921  DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
922      : j_observer_global_(jni, j_observer),
923        j_observer_class_(jni, GetObjectClass(jni, j_observer)),
924        j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
925        j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
926                                           "onStateChange", "()V")),
927        j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
928                                      "(Lorg/webrtc/DataChannel$Buffer;)V")),
929        j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
930                                   "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
931  }
932
933  virtual ~DataChannelObserverWrapper() {}
934
935  virtual void OnStateChange() OVERRIDE {
936    ScopedLocalRefFrame local_ref_frame(jni());
937    jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
938    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
939  }
940
941  virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
942    ScopedLocalRefFrame local_ref_frame(jni());
943    jobject byte_buffer =
944        jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
945                                   buffer.data.length());
946    jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
947                                        byte_buffer, buffer.binary);
948    jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
949    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
950  }
951
952 private:
953  JNIEnv* jni() {
954    return AttachCurrentThreadIfNeeded();
955  }
956
957  const ScopedGlobalRef<jobject> j_observer_global_;
958  const ScopedGlobalRef<jclass> j_observer_class_;
959  const ScopedGlobalRef<jclass> j_buffer_class_;
960  const jmethodID j_on_state_change_mid_;
961  const jmethodID j_on_message_mid_;
962  const jmethodID j_buffer_ctor_;
963};
964
965// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
966// dispatching the callback from C++ back to Java.
967class StatsObserverWrapper : public StatsObserver {
968 public:
969  StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
970      : j_observer_global_(jni, j_observer),
971        j_observer_class_(jni, GetObjectClass(jni, j_observer)),
972        j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
973        j_stats_report_ctor_(GetMethodID(
974            jni, *j_stats_report_class_, "<init>",
975            "(Ljava/lang/String;Ljava/lang/String;D"
976            "[Lorg/webrtc/StatsReport$Value;)V")),
977        j_value_class_(jni, FindClass(
978            jni, "org/webrtc/StatsReport$Value")),
979        j_value_ctor_(GetMethodID(
980            jni, *j_value_class_, "<init>",
981            "(Ljava/lang/String;Ljava/lang/String;)V")) {
982  }
983
984  virtual ~StatsObserverWrapper() {}
985
986  virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
987    ScopedLocalRefFrame local_ref_frame(jni());
988    jobjectArray j_reports = ReportsToJava(jni(), reports);
989    jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
990                              "([Lorg/webrtc/StatsReport;)V");
991    jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
992    CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
993  }
994
995 private:
996  jobjectArray ReportsToJava(
997      JNIEnv* jni, const std::vector<StatsReport>& reports) {
998    jobjectArray reports_array = jni->NewObjectArray(
999        reports.size(), *j_stats_report_class_, NULL);
1000    for (int i = 0; i < reports.size(); ++i) {
1001      ScopedLocalRefFrame local_ref_frame(jni);
1002      const StatsReport& report = reports[i];
1003      jstring j_id = JavaStringFromStdString(jni, report.id);
1004      jstring j_type = JavaStringFromStdString(jni, report.type);
1005      jobjectArray j_values = ValuesToJava(jni, report.values);
1006      jobject j_report = jni->NewObject(*j_stats_report_class_,
1007                                        j_stats_report_ctor_,
1008                                        j_id,
1009                                        j_type,
1010                                        report.timestamp,
1011                                        j_values);
1012      jni->SetObjectArrayElement(reports_array, i, j_report);
1013    }
1014    return reports_array;
1015  }
1016
1017  jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1018    jobjectArray j_values = jni->NewObjectArray(
1019        values.size(), *j_value_class_, NULL);
1020    for (int i = 0; i < values.size(); ++i) {
1021      ScopedLocalRefFrame local_ref_frame(jni);
1022      const StatsReport::Value& value = values[i];
1023      jstring j_name = JavaStringFromStdString(jni, value.name);
1024      jstring j_value = JavaStringFromStdString(jni, value.value);
1025      jobject j_element_value =
1026          jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1027      jni->SetObjectArrayElement(j_values, i, j_element_value);
1028    }
1029    return j_values;
1030  }
1031
1032  JNIEnv* jni() {
1033    return AttachCurrentThreadIfNeeded();
1034  }
1035
1036  const ScopedGlobalRef<jobject> j_observer_global_;
1037  const ScopedGlobalRef<jclass> j_observer_class_;
1038  const ScopedGlobalRef<jclass> j_stats_report_class_;
1039  const jmethodID j_stats_report_ctor_;
1040  const ScopedGlobalRef<jclass> j_value_class_;
1041  const jmethodID j_value_ctor_;
1042};
1043
1044// Adapter presenting a cricket::VideoRenderer as a
1045// webrtc::VideoRendererInterface.
1046class VideoRendererWrapper : public VideoRendererInterface {
1047 public:
1048  static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1049    if (renderer)
1050      return new VideoRendererWrapper(renderer);
1051    return NULL;
1052  }
1053
1054  virtual ~VideoRendererWrapper() {}
1055
1056  virtual void SetSize(int width, int height) OVERRIDE {
1057    ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1058    const bool kNotReserved = false;  // What does this param mean??
1059    renderer_->SetSize(width, height, kNotReserved);
1060  }
1061
1062  virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1063    ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1064    renderer_->RenderFrame(frame);
1065  }
1066
1067 private:
1068  explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1069      : renderer_(renderer) {}
1070
1071  scoped_ptr<cricket::VideoRenderer> renderer_;
1072};
1073
1074// Wrapper for texture object in TextureVideoFrame.
1075class NativeHandleImpl : public NativeHandle {
1076 public:
1077  NativeHandleImpl() :
1078    ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1079  virtual ~NativeHandleImpl() {}
1080  virtual int32_t AddRef() {
1081    return ++ref_count_;
1082  }
1083  virtual int32_t Release() {
1084    return --ref_count_;
1085  }
1086  virtual void* GetHandle() {
1087    return texture_object_;
1088  }
1089  int GetTextureId() {
1090    return texture_id_;
1091  }
1092  void SetTextureObject(void *texture_object, int texture_id) {
1093    texture_object_ = reinterpret_cast<jobject>(texture_object);
1094    texture_id_ = texture_id;
1095  }
1096  int32_t ref_count() {
1097    return ref_count_;
1098  }
1099
1100 private:
1101  int32_t ref_count_;
1102  jobject texture_object_;
1103  int32_t texture_id_;
1104};
1105
1106// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1107// instance.
1108class JavaVideoRendererWrapper : public VideoRendererInterface {
1109 public:
1110  JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
1111      : j_callbacks_(jni, j_callbacks),
1112        j_set_size_id_(GetMethodID(
1113            jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1114        j_render_frame_id_(GetMethodID(
1115            jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1116            "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1117        j_frame_class_(jni,
1118                       FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1119        j_i420_frame_ctor_id_(GetMethodID(
1120            jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1121        j_texture_frame_ctor_id_(GetMethodID(
1122            jni, *j_frame_class_, "<init>",
1123            "(IILjava/lang/Object;I)V")),
1124        j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
1125    CHECK_EXCEPTION(jni);
1126  }
1127
1128  virtual ~JavaVideoRendererWrapper() {}
1129
1130  virtual void SetSize(int width, int height) OVERRIDE {
1131    ScopedLocalRefFrame local_ref_frame(jni());
1132    jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1133    CHECK_EXCEPTION(jni());
1134  }
1135
1136  virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1137    ScopedLocalRefFrame local_ref_frame(jni());
1138    if (frame->GetNativeHandle() != NULL) {
1139      jobject j_frame = CricketToJavaTextureFrame(frame);
1140      jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1141      CHECK_EXCEPTION(jni());
1142    } else {
1143      jobject j_frame = CricketToJavaI420Frame(frame);
1144      jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1145      CHECK_EXCEPTION(jni());
1146    }
1147  }
1148
1149 private:
1150  // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1151  jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
1152    jintArray strides = jni()->NewIntArray(3);
1153    jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
1154    strides_array[0] = frame->GetYPitch();
1155    strides_array[1] = frame->GetUPitch();
1156    strides_array[2] = frame->GetVPitch();
1157    jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1158    jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1159    jobject y_buffer = jni()->NewDirectByteBuffer(
1160        const_cast<uint8*>(frame->GetYPlane()),
1161        frame->GetYPitch() * frame->GetHeight());
1162    jobject u_buffer = jni()->NewDirectByteBuffer(
1163        const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1164    jobject v_buffer = jni()->NewDirectByteBuffer(
1165        const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1166    jni()->SetObjectArrayElement(planes, 0, y_buffer);
1167    jni()->SetObjectArrayElement(planes, 1, u_buffer);
1168    jni()->SetObjectArrayElement(planes, 2, v_buffer);
1169    return jni()->NewObject(
1170        *j_frame_class_, j_i420_frame_ctor_id_,
1171        frame->GetWidth(), frame->GetHeight(), strides, planes);
1172  }
1173
1174  // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1175  jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1176    NativeHandleImpl* handle =
1177        reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1178    jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1179    int texture_id = handle->GetTextureId();
1180    return jni()->NewObject(
1181        *j_frame_class_, j_texture_frame_ctor_id_,
1182        frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1183  }
1184
1185  JNIEnv* jni() {
1186    return AttachCurrentThreadIfNeeded();
1187  }
1188
1189  ScopedGlobalRef<jobject> j_callbacks_;
1190  jmethodID j_set_size_id_;
1191  jmethodID j_render_frame_id_;
1192  ScopedGlobalRef<jclass> j_frame_class_;
1193  jmethodID j_i420_frame_ctor_id_;
1194  jmethodID j_texture_frame_ctor_id_;
1195  ScopedGlobalRef<jclass> j_byte_buffer_class_;
1196};
1197
1198#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
1199// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1200// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1201// from this file.
1202
1203//#define TRACK_BUFFER_TIMING
1204#define TAG "MediaCodecVideo"
1205#ifdef TRACK_BUFFER_TIMING
1206#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1207#else
1208#define ALOGV(...)
1209#endif
1210#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1211#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
1212
1213// Color formats supported by encoder - should mirror supportedColorList
1214// from MediaCodecVideoEncoder.java
1215enum COLOR_FORMATTYPE {
1216  COLOR_FormatYUV420Planar = 0x13,
1217  COLOR_FormatYUV420SemiPlanar = 0x15,
1218  COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1219  // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1220  // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1221  // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1222  // but requires some (16, 32?) byte alignment.
1223  COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1224};
1225
1226// Arbitrary interval to poll the codec for new outputs.
1227enum { kMediaCodecPollMs = 10 };
1228// Media codec maximum output buffer ready timeout.
1229enum { kMediaCodecTimeoutMs = 500 };
1230// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1231enum { kMediaCodecStatisticsIntervalMs = 3000 };
1232
1233static int64_t GetCurrentTimeMs() {
1234  return TickTime::Now().Ticks() / 1000000LL;
1235}
1236
1237// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1238// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1239// HW-backed video encode.  This C++ class is implemented as a very thin shim,
1240// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1241// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1242// thread, currently the libjingle Worker thread.
1243class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1244                               public rtc::MessageHandler {
1245 public:
1246  virtual ~MediaCodecVideoEncoder();
1247  explicit MediaCodecVideoEncoder(JNIEnv* jni);
1248
1249  // webrtc::VideoEncoder implementation.  Everything trampolines to
1250  // |codec_thread_| for execution.
1251  virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1252                             int32_t /* number_of_cores */,
1253                             uint32_t /* max_payload_size */) OVERRIDE;
1254  virtual int32_t Encode(
1255      const webrtc::I420VideoFrame& input_image,
1256      const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1257      const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1258  virtual int32_t RegisterEncodeCompleteCallback(
1259      webrtc::EncodedImageCallback* callback) OVERRIDE;
1260  virtual int32_t Release() OVERRIDE;
1261  virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1262                                       int /* rtt */) OVERRIDE;
1263  virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1264
1265  // rtc::MessageHandler implementation.
1266  virtual void OnMessage(rtc::Message* msg) OVERRIDE;
1267
1268 private:
1269  // CHECK-fail if not running on |codec_thread_|.
1270  void CheckOnCodecThread();
1271
1272  // Release() and InitEncode() in an attempt to restore the codec to an
1273  // operable state.  Necessary after all manner of OMX-layer errors.
1274  void ResetCodec();
1275
1276  // Implementation of webrtc::VideoEncoder methods above, all running on the
1277  // codec thread exclusively.
1278  //
1279  // If width==0 then this is assumed to be a re-initialization and the
1280  // previously-current values are reused instead of the passed parameters
1281  // (makes it easier to reason about thread-safety).
1282  int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
1283  int32_t EncodeOnCodecThread(
1284      const webrtc::I420VideoFrame& input_image,
1285      const std::vector<webrtc::VideoFrameType>* frame_types);
1286  int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1287      webrtc::EncodedImageCallback* callback);
1288  int32_t ReleaseOnCodecThread();
1289  int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1290
1291  // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1292  int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1293  jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1294  bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1295  jlong GetOutputBufferInfoPresentationTimestampUs(
1296      JNIEnv* jni,
1297      jobject j_output_buffer_info);
1298
1299  // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1300  // true on success.
1301  bool DeliverPendingOutputs(JNIEnv* jni);
1302
1303  // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1304  // |codec_thread_| synchronously.
1305  webrtc::EncodedImageCallback* callback_;
1306
1307  // State that is constant for the lifetime of this object once the ctor
1308  // returns.
1309  scoped_ptr<Thread> codec_thread_;  // Thread on which to operate MediaCodec.
1310  ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1311  ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1312  jmethodID j_init_encode_method_;
1313  jmethodID j_dequeue_input_buffer_method_;
1314  jmethodID j_encode_method_;
1315  jmethodID j_release_method_;
1316  jmethodID j_set_rates_method_;
1317  jmethodID j_dequeue_output_buffer_method_;
1318  jmethodID j_release_output_buffer_method_;
1319  jfieldID j_color_format_field_;
1320  jfieldID j_info_index_field_;
1321  jfieldID j_info_buffer_field_;
1322  jfieldID j_info_is_key_frame_field_;
1323  jfieldID j_info_presentation_timestamp_us_field_;
1324
1325  // State that is valid only between InitEncode() and the next Release().
1326  // Touched only on codec_thread_ so no explicit synchronization necessary.
1327  int width_;   // Frame width in pixels.
1328  int height_;  // Frame height in pixels.
1329  bool inited_;
1330  enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
1331  int last_set_bitrate_kbps_;  // Last-requested bitrate in kbps.
1332  int last_set_fps_;  // Last-requested frame rate.
1333  int64_t current_timestamp_us_;  // Current frame timestamps in us.
1334  int frames_received_;  // Number of frames received by encoder.
1335  int frames_dropped_;  // Number of frames dropped by encoder.
1336  int frames_resolution_update_;  // Number of frames with new codec resolution.
1337  int frames_in_queue_;  // Number of frames in encoder queue.
1338  int64_t start_time_ms_;  // Start time for statistics.
1339  int current_frames_;  // Number of frames in the current statistics interval.
1340  int current_bytes_;  // Encoded bytes in the current statistics interval.
1341  int current_encoding_time_ms_;  // Overall encoding time in the current second
1342  int64_t last_input_timestamp_ms_;  // Timestamp of last received yuv frame.
1343  int64_t last_output_timestamp_ms_;  // Timestamp of last encoded frame.
1344  std::vector<int32_t> timestamps_;  // Video frames timestamp queue.
1345  std::vector<int64_t> render_times_ms_;  // Video frames render time queue.
1346  std::vector<int64_t> frame_rtc_times_ms_;  // Time when video frame is sent to
1347                                             // encoder input.
1348  // Frame size in bytes fed to MediaCodec.
1349  int yuv_size_;
1350  // True only when between a callback_->Encoded() call return a positive value
1351  // and the next Encode() call being ignored.
1352  bool drop_next_input_frame_;
1353  // Global references; must be deleted in Release().
1354  std::vector<jobject> input_buffers_;
1355};
1356
1357MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1358  // Call Release() to ensure no more callbacks to us after we are deleted.
1359  Release();
1360}
1361
1362MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1363  : callback_(NULL),
1364    inited_(false),
1365    codec_thread_(new Thread()),
1366    j_media_codec_video_encoder_class_(
1367        jni,
1368        FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1369    j_media_codec_video_encoder_(
1370        jni,
1371        jni->NewObject(*j_media_codec_video_encoder_class_,
1372                       GetMethodID(jni,
1373                                   *j_media_codec_video_encoder_class_,
1374                                   "<init>",
1375                                   "()V"))) {
1376  ScopedLocalRefFrame local_ref_frame(jni);
1377  // It would be nice to avoid spinning up a new thread per MediaCodec, and
1378  // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1379  // 2732 means that deadlocks abound.  This class synchronously trampolines
1380  // to |codec_thread_|, so if anything else can be coming to _us_ from
1381  // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1382  // in the bug, we have a problem.  For now work around that with a dedicated
1383  // thread.
1384  codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1385  CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
1386
1387  jclass j_output_buffer_info_class =
1388      FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1389  j_init_encode_method_ = GetMethodID(jni,
1390                                      *j_media_codec_video_encoder_class_,
1391                                      "initEncode",
1392                                      "(IIII)[Ljava/nio/ByteBuffer;");
1393  j_dequeue_input_buffer_method_ = GetMethodID(
1394      jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1395  j_encode_method_ = GetMethodID(
1396      jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1397  j_release_method_ =
1398      GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1399  j_set_rates_method_ = GetMethodID(
1400      jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1401  j_dequeue_output_buffer_method_ =
1402      GetMethodID(jni,
1403                  *j_media_codec_video_encoder_class_,
1404                  "dequeueOutputBuffer",
1405                  "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1406  j_release_output_buffer_method_ = GetMethodID(
1407      jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1408
1409  j_color_format_field_ =
1410      GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
1411  j_info_index_field_ =
1412      GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1413  j_info_buffer_field_ = GetFieldID(
1414      jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1415  j_info_is_key_frame_field_ =
1416      GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1417  j_info_presentation_timestamp_us_field_ = GetFieldID(
1418      jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1419  CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
1420}
1421
1422int32_t MediaCodecVideoEncoder::InitEncode(
1423    const webrtc::VideoCodec* codec_settings,
1424    int32_t /* number_of_cores */,
1425    uint32_t /* max_payload_size */) {
1426  // Factory should guard against other codecs being used with us.
1427  CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
1428
1429  return codec_thread_->Invoke<int32_t>(
1430      Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1431           this,
1432           codec_settings->width,
1433           codec_settings->height,
1434           codec_settings->startBitrate,
1435           codec_settings->maxFramerate));
1436}
1437
1438int32_t MediaCodecVideoEncoder::Encode(
1439    const webrtc::I420VideoFrame& frame,
1440    const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1441    const std::vector<webrtc::VideoFrameType>* frame_types) {
1442  return codec_thread_->Invoke<int32_t>(Bind(
1443      &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1444}
1445
1446int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1447    webrtc::EncodedImageCallback* callback) {
1448  return codec_thread_->Invoke<int32_t>(
1449      Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1450           this,
1451           callback));
1452}
1453
1454int32_t MediaCodecVideoEncoder::Release() {
1455  return codec_thread_->Invoke<int32_t>(
1456      Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1457}
1458
1459int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1460                                                     int /* rtt */) {
1461  return WEBRTC_VIDEO_CODEC_OK;
1462}
1463
1464int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1465                                         uint32_t frame_rate) {
1466  return codec_thread_->Invoke<int32_t>(
1467      Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1468           this,
1469           new_bit_rate,
1470           frame_rate));
1471}
1472
1473void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
1474  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1475  ScopedLocalRefFrame local_ref_frame(jni);
1476
1477  // We only ever send one message to |this| directly (not through a Bind()'d
1478  // functor), so expect no ID/data.
1479  CHECK(!msg->message_id) << "Unexpected message!";
1480  CHECK(!msg->pdata) << "Unexpected message!";
1481  CheckOnCodecThread();
1482  if (!inited_) {
1483    return;
1484  }
1485
1486  // It would be nice to recover from a failure here if one happened, but it's
1487  // unclear how to signal such a failure to the app, so instead we stay silent
1488  // about it and let the next app-called API method reveal the borkedness.
1489  DeliverPendingOutputs(jni);
1490  codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1491}
1492
1493void MediaCodecVideoEncoder::CheckOnCodecThread() {
1494  CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1495      << "Running on wrong thread!";
1496}
1497
1498void MediaCodecVideoEncoder::ResetCodec() {
1499  ALOGE("ResetCodec");
1500  if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1501      codec_thread_->Invoke<int32_t>(Bind(
1502          &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1503          width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
1504    // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1505    // degrade to a SW encoder at this point?  There isn't one AFAICT :(
1506    // https://code.google.com/p/webrtc/issues/detail?id=2920
1507  }
1508}
1509
1510int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
1511    int width, int height, int kbps, int fps) {
1512  CheckOnCodecThread();
1513  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1514  ScopedLocalRefFrame local_ref_frame(jni);
1515
1516  ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1517      width, height, kbps, fps);
1518  if (kbps == 0) {
1519    kbps = last_set_bitrate_kbps_;
1520  }
1521  if (fps == 0) {
1522    fps = last_set_fps_;
1523  }
1524
1525  width_ = width;
1526  height_ = height;
1527  last_set_bitrate_kbps_ = kbps;
1528  last_set_fps_ = fps;
1529  yuv_size_ = width_ * height_ * 3 / 2;
1530  frames_received_ = 0;
1531  frames_dropped_ = 0;
1532  frames_resolution_update_ = 0;
1533  frames_in_queue_ = 0;
1534  current_timestamp_us_ = 0;
1535  start_time_ms_ = GetCurrentTimeMs();
1536  current_frames_ = 0;
1537  current_bytes_ = 0;
1538  current_encoding_time_ms_ = 0;
1539  last_input_timestamp_ms_ = -1;
1540  last_output_timestamp_ms_ = -1;
1541  timestamps_.clear();
1542  render_times_ms_.clear();
1543  frame_rtc_times_ms_.clear();
1544  drop_next_input_frame_ = false;
1545  // We enforce no extra stride/padding in the format creation step.
1546  jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1547      jni->CallObjectMethod(*j_media_codec_video_encoder_,
1548                            j_init_encode_method_,
1549                            width_,
1550                            height_,
1551                            kbps,
1552                            fps));
1553  CHECK_EXCEPTION(jni);
1554  if (IsNull(jni, input_buffers))
1555    return WEBRTC_VIDEO_CODEC_ERROR;
1556
1557  inited_ = true;
1558  switch (GetIntField(jni, *j_media_codec_video_encoder_,
1559      j_color_format_field_)) {
1560    case COLOR_FormatYUV420Planar:
1561      encoder_fourcc_ = libyuv::FOURCC_YU12;
1562      break;
1563    case COLOR_FormatYUV420SemiPlanar:
1564    case COLOR_QCOM_FormatYUV420SemiPlanar:
1565    case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1566      encoder_fourcc_ = libyuv::FOURCC_NV12;
1567      break;
1568    default:
1569      LOG(LS_ERROR) << "Wrong color format.";
1570      return WEBRTC_VIDEO_CODEC_ERROR;
1571  }
1572  size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1573  CHECK(input_buffers_.empty())
1574      << "Unexpected double InitEncode without Release";
1575  input_buffers_.resize(num_input_buffers);
1576  for (size_t i = 0; i < num_input_buffers; ++i) {
1577    input_buffers_[i] =
1578        jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
1579    int64 yuv_buffer_capacity =
1580        jni->GetDirectBufferCapacity(input_buffers_[i]);
1581    CHECK_EXCEPTION(jni);
1582    CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
1583  }
1584  CHECK_EXCEPTION(jni);
1585
1586  codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1587  return WEBRTC_VIDEO_CODEC_OK;
1588}
1589
1590int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1591    const webrtc::I420VideoFrame& frame,
1592    const std::vector<webrtc::VideoFrameType>* frame_types) {
1593  CheckOnCodecThread();
1594  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1595  ScopedLocalRefFrame local_ref_frame(jni);
1596
1597  if (!inited_) {
1598    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1599  }
1600  frames_received_++;
1601  if (!DeliverPendingOutputs(jni)) {
1602    ResetCodec();
1603    // Continue as if everything's fine.
1604  }
1605
1606  if (drop_next_input_frame_) {
1607    ALOGV("Encoder drop frame - failed callback.");
1608    drop_next_input_frame_ = false;
1609    return WEBRTC_VIDEO_CODEC_OK;
1610  }
1611
1612  CHECK(frame_types->size() == 1) << "Unexpected stream count";
1613  if (frame.width() != width_ || frame.height() != height_) {
1614    frames_resolution_update_++;
1615    ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1616        width_, height_, frame.width(), frame.height());
1617    if (frames_resolution_update_ > 3) {
1618      // Reset codec if we received more than 3 frames with new resolution.
1619      width_ = frame.width();
1620      height_ = frame.height();
1621      frames_resolution_update_ = 0;
1622      ResetCodec();
1623    }
1624    return WEBRTC_VIDEO_CODEC_OK;
1625  }
1626  frames_resolution_update_ = 0;
1627
1628  bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1629
1630  // Check if we accumulated too many frames in encoder input buffers
1631  // or the encoder latency exceeds 70 ms and drop frame if so.
1632  if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
1633    int encoder_latency_ms = last_input_timestamp_ms_ -
1634        last_output_timestamp_ms_;
1635    if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
1636      ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1637          encoder_latency_ms, frames_in_queue_);
1638      frames_dropped_++;
1639      return WEBRTC_VIDEO_CODEC_OK;
1640    }
1641  }
1642
1643  int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1644                                                j_dequeue_input_buffer_method_);
1645  CHECK_EXCEPTION(jni);
1646  if (j_input_buffer_index == -1) {
1647    // Video codec falls behind - no input buffer available.
1648    ALOGV("Encoder drop frame - no input buffers available");
1649    frames_dropped_++;
1650    return WEBRTC_VIDEO_CODEC_OK;  // TODO(fischman): see webrtc bug 2887.
1651  }
1652  if (j_input_buffer_index == -2) {
1653    ResetCodec();
1654    return WEBRTC_VIDEO_CODEC_ERROR;
1655  }
1656
1657  ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
1658      frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
1659
1660  jobject j_input_buffer = input_buffers_[j_input_buffer_index];
1661  uint8* yuv_buffer =
1662      reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1663  CHECK_EXCEPTION(jni);
1664  CHECK(yuv_buffer) << "Indirect buffer??";
1665  CHECK(!libyuv::ConvertFromI420(
1666          frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1667          frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1668          frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1669          yuv_buffer, width_,
1670          width_, height_,
1671          encoder_fourcc_))
1672      << "ConvertFromI420 failed";
1673  last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
1674  frames_in_queue_++;
1675
1676  // Save input image timestamps for later output
1677  timestamps_.push_back(frame.timestamp());
1678  render_times_ms_.push_back(frame.render_time_ms());
1679  frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1680
1681  bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1682                                              j_encode_method_,
1683                                              key_frame,
1684                                              j_input_buffer_index,
1685                                              yuv_size_,
1686                                              current_timestamp_us_);
1687  CHECK_EXCEPTION(jni);
1688  current_timestamp_us_ += 1000000 / last_set_fps_;
1689
1690  if (!encode_status || !DeliverPendingOutputs(jni)) {
1691    ResetCodec();
1692    return WEBRTC_VIDEO_CODEC_ERROR;
1693  }
1694
1695  return WEBRTC_VIDEO_CODEC_OK;
1696}
1697
1698int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1699    webrtc::EncodedImageCallback* callback) {
1700  CheckOnCodecThread();
1701  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1702  ScopedLocalRefFrame local_ref_frame(jni);
1703  callback_ = callback;
1704  return WEBRTC_VIDEO_CODEC_OK;
1705}
1706
1707int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1708  if (!inited_) {
1709    return WEBRTC_VIDEO_CODEC_OK;
1710  }
1711  CheckOnCodecThread();
1712  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1713  ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1714      frames_received_,frames_dropped_);
1715  ScopedLocalRefFrame local_ref_frame(jni);
1716  for (size_t i = 0; i < input_buffers_.size(); ++i)
1717    jni->DeleteGlobalRef(input_buffers_[i]);
1718  input_buffers_.clear();
1719  jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1720  CHECK_EXCEPTION(jni);
1721  rtc::MessageQueueManager::Clear(this);
1722  inited_ = false;
1723  return WEBRTC_VIDEO_CODEC_OK;
1724}
1725
1726int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1727                                                      uint32_t frame_rate) {
1728  CheckOnCodecThread();
1729  if (last_set_bitrate_kbps_ == new_bit_rate &&
1730      last_set_fps_ == frame_rate) {
1731    return WEBRTC_VIDEO_CODEC_OK;
1732  }
1733  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1734  ScopedLocalRefFrame local_ref_frame(jni);
1735  if (new_bit_rate > 0) {
1736    last_set_bitrate_kbps_ = new_bit_rate;
1737  }
1738  if (frame_rate > 0) {
1739    last_set_fps_ = frame_rate;
1740  }
1741  bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1742                                       j_set_rates_method_,
1743                                       last_set_bitrate_kbps_,
1744                                       last_set_fps_);
1745  CHECK_EXCEPTION(jni);
1746  if (!ret) {
1747    ResetCodec();
1748    return WEBRTC_VIDEO_CODEC_ERROR;
1749  }
1750  return WEBRTC_VIDEO_CODEC_OK;
1751}
1752
1753int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1754    JNIEnv* jni,
1755    jobject j_output_buffer_info) {
1756  return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1757}
1758
1759jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1760    JNIEnv* jni,
1761    jobject j_output_buffer_info) {
1762  return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1763}
1764
1765bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1766    JNIEnv* jni,
1767    jobject j_output_buffer_info) {
1768  return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1769}
1770
1771jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1772    JNIEnv* jni,
1773    jobject j_output_buffer_info) {
1774  return GetLongField(
1775      jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1776}
1777
1778bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1779  while (true) {
1780    jobject j_output_buffer_info = jni->CallObjectMethod(
1781        *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1782    CHECK_EXCEPTION(jni);
1783    if (IsNull(jni, j_output_buffer_info)) {
1784      break;
1785    }
1786
1787    int output_buffer_index =
1788        GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1789    if (output_buffer_index == -1) {
1790      ResetCodec();
1791      return false;
1792    }
1793
1794    // Get frame timestamps from a queue.
1795    last_output_timestamp_ms_ =
1796        GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1797        1000;
1798    int32_t timestamp = timestamps_.front();
1799    timestamps_.erase(timestamps_.begin());
1800    int64_t render_time_ms = render_times_ms_.front();
1801    render_times_ms_.erase(render_times_ms_.begin());
1802    int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1803        frame_rtc_times_ms_.front();
1804    frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
1805    frames_in_queue_--;
1806
1807    // Extract payload and key frame flag.
1808    int32_t callback_status = 0;
1809    jobject j_output_buffer =
1810        GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1811    bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1812    size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1813    uint8* payload = reinterpret_cast<uint8_t*>(
1814        jni->GetDirectBufferAddress(j_output_buffer));
1815    CHECK_EXCEPTION(jni);
1816
1817    ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1818        " EncTime: %lld",
1819        output_buffer_index, payload_size, last_output_timestamp_ms_,
1820        last_input_timestamp_ms_ - last_output_timestamp_ms_,
1821        frame_encoding_time_ms);
1822
1823    // Calculate and print encoding statistics - every 3 seconds.
1824    current_frames_++;
1825    current_bytes_ += payload_size;
1826    current_encoding_time_ms_ += frame_encoding_time_ms;
1827    int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1828    if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1829        current_frames_ > 0) {
1830      ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1831          " encTime: %d for last %d ms",
1832          current_bytes_ * 8 / statistic_time_ms,
1833          last_set_bitrate_kbps_,
1834          (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1835          current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1836      start_time_ms_ = GetCurrentTimeMs();
1837      current_frames_ = 0;
1838      current_bytes_= 0;
1839      current_encoding_time_ms_ = 0;
1840    }
1841
1842    // Callback - return encoded frame.
1843    if (callback_) {
1844      scoped_ptr<webrtc::EncodedImage> image(
1845          new webrtc::EncodedImage(payload, payload_size, payload_size));
1846      image->_encodedWidth = width_;
1847      image->_encodedHeight = height_;
1848      image->_timeStamp = timestamp;
1849      image->capture_time_ms_ = render_time_ms;
1850      image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1851      image->_completeFrame = true;
1852
1853      webrtc::CodecSpecificInfo info;
1854      memset(&info, 0, sizeof(info));
1855      info.codecType = kVideoCodecVP8;
1856      info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1857      info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1858      info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1859
1860      // Generate a header describing a single fragment.
1861      webrtc::RTPFragmentationHeader header;
1862      memset(&header, 0, sizeof(header));
1863      header.VerifyAndAllocateFragmentationHeader(1);
1864      header.fragmentationOffset[0] = 0;
1865      header.fragmentationLength[0] = image->_length;
1866      header.fragmentationPlType[0] = 0;
1867      header.fragmentationTimeDiff[0] = 0;
1868
1869      callback_status = callback_->Encoded(*image, &info, &header);
1870    }
1871
1872    // Return output buffer back to the encoder.
1873    bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1874                                          j_release_output_buffer_method_,
1875                                          output_buffer_index);
1876    CHECK_EXCEPTION(jni);
1877    if (!success) {
1878      ResetCodec();
1879      return false;
1880    }
1881
1882    if (callback_status > 0) {
1883      drop_next_input_frame_ = true;
1884    // Theoretically could handle callback_status<0 here, but unclear what that
1885    // would mean for us.
1886    }
1887  }
1888
1889  return true;
1890}
1891
1892// Simplest-possible implementation of an encoder factory, churns out
1893// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1894class MediaCodecVideoEncoderFactory
1895    : public cricket::WebRtcVideoEncoderFactory {
1896 public:
1897  MediaCodecVideoEncoderFactory();
1898  virtual ~MediaCodecVideoEncoderFactory();
1899
1900  // WebRtcVideoEncoderFactory implementation.
1901  virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1902      OVERRIDE;
1903  virtual void AddObserver(Observer* observer) OVERRIDE;
1904  virtual void RemoveObserver(Observer* observer) OVERRIDE;
1905  virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1906  virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1907
1908 private:
1909  // Empty if platform support is lacking, const after ctor returns.
1910  std::vector<VideoCodec> supported_codecs_;
1911};
1912
1913MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1914  JNIEnv* jni = AttachCurrentThreadIfNeeded();
1915  ScopedLocalRefFrame local_ref_frame(jni);
1916  jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1917  bool is_platform_supported = jni->CallStaticBooleanMethod(
1918      j_encoder_class,
1919      GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1920  CHECK_EXCEPTION(jni);
1921  if (!is_platform_supported)
1922    return;
1923
1924  // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1925  // encoder?  Sure would be.  Too bad it doesn't.  So we hard-code some
1926  // reasonable defaults.
1927  supported_codecs_.push_back(
1928      VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
1929}
1930
1931MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1932
1933webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1934    webrtc::VideoCodecType type) {
1935  if (type != kVideoCodecVP8 || supported_codecs_.empty())
1936    return NULL;
1937  return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1938}
1939
1940// Since the available codec list is never going to change, we ignore the
1941// Observer-related interface here.
1942void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1943void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1944
1945const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1946MediaCodecVideoEncoderFactory::codecs() const {
1947  return supported_codecs_;
1948}
1949
1950void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1951    webrtc::VideoEncoder* encoder) {
1952  delete encoder;
1953}
1954
1955class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
1956                               public rtc::MessageHandler {
1957 public:
1958  explicit MediaCodecVideoDecoder(JNIEnv* jni);
1959  virtual ~MediaCodecVideoDecoder();
1960
1961  static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1962
1963  virtual int32_t InitDecode(const VideoCodec* codecSettings,
1964      int32_t numberOfCores) OVERRIDE;
1965
1966  virtual int32_t
1967  Decode(const EncodedImage& inputImage, bool missingFrames,
1968         const RTPFragmentationHeader* fragmentation,
1969         const CodecSpecificInfo* codecSpecificInfo = NULL,
1970         int64_t renderTimeMs = -1) OVERRIDE;
1971
1972  virtual int32_t RegisterDecodeCompleteCallback(
1973      DecodedImageCallback* callback) OVERRIDE;
1974
1975  virtual int32_t Release() OVERRIDE;
1976
1977  virtual int32_t Reset() OVERRIDE;
1978  // rtc::MessageHandler implementation.
1979  virtual void OnMessage(rtc::Message* msg) OVERRIDE;
1980
1981 private:
1982  // CHECK-fail if not running on |codec_thread_|.
1983  void CheckOnCodecThread();
1984
1985  int32_t InitDecodeOnCodecThread();
1986  int32_t ReleaseOnCodecThread();
1987  int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
1988  // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1989  // true on success.
1990  bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
1991
1992
1993  bool key_frame_required_;
1994  bool inited_;
1995  bool use_surface_;
1996  VideoCodec codec_;
1997  I420VideoFrame decoded_image_;
1998  NativeHandleImpl native_handle_;
1999  DecodedImageCallback* callback_;
2000  int frames_received_;  // Number of frames received by decoder.
2001  int frames_decoded_;  // Number of frames decoded by decoder
2002  int64_t start_time_ms_;  // Start time for statistics.
2003  int current_frames_;  // Number of frames in the current statistics interval.
2004  int current_bytes_;  // Encoded bytes in the current statistics interval.
2005  int current_decoding_time_ms_;  // Overall decoding time in the current second
2006  uint32_t max_pending_frames_;  // Maximum number of pending input frames
2007  std::vector<int32_t> timestamps_;
2008  std::vector<int64_t> ntp_times_ms_;
2009  std::vector<int64_t> frame_rtc_times_ms_;  // Time when video frame is sent to
2010                                             // decoder input.
2011
2012  // State that is constant for the lifetime of this object once the ctor
2013  // returns.
2014  scoped_ptr<Thread> codec_thread_;  // Thread on which to operate MediaCodec.
2015  ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2016  ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2017  jmethodID j_init_decode_method_;
2018  jmethodID j_release_method_;
2019  jmethodID j_dequeue_input_buffer_method_;
2020  jmethodID j_queue_input_buffer_method_;
2021  jmethodID j_dequeue_output_buffer_method_;
2022  jmethodID j_release_output_buffer_method_;
2023  // MediaCodecVideoDecoder fields.
2024  jfieldID j_input_buffers_field_;
2025  jfieldID j_output_buffers_field_;
2026  jfieldID j_color_format_field_;
2027  jfieldID j_width_field_;
2028  jfieldID j_height_field_;
2029  jfieldID j_stride_field_;
2030  jfieldID j_slice_height_field_;
2031  jfieldID j_surface_texture_field_;
2032  jfieldID j_textureID_field_;
2033  // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2034  jfieldID j_info_index_field_;
2035  jfieldID j_info_offset_field_;
2036  jfieldID j_info_size_field_;
2037  jfieldID j_info_presentation_timestamp_us_field_;
2038
2039  // Global references; must be deleted in Release().
2040  std::vector<jobject> input_buffers_;
2041  jobject surface_texture_;
2042
2043  // Render EGL context.
2044  static jobject render_egl_context_;
2045};
2046
2047jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2048
2049int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2050    jobject render_egl_context) {
2051  if (render_egl_context_) {
2052    jni->DeleteGlobalRef(render_egl_context_);
2053  }
2054  if (IsNull(jni, render_egl_context)) {
2055    render_egl_context_ = NULL;
2056  } else {
2057    render_egl_context_ = jni->NewGlobalRef(render_egl_context);
2058  }
2059  ALOGD("VideoDecoder EGL context set.");
2060  return 0;
2061}
2062
2063MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2064  : key_frame_required_(true),
2065    inited_(false),
2066    codec_thread_(new Thread()),
2067    j_media_codec_video_decoder_class_(
2068        jni,
2069        FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2070          j_media_codec_video_decoder_(
2071              jni,
2072              jni->NewObject(*j_media_codec_video_decoder_class_,
2073                   GetMethodID(jni,
2074                              *j_media_codec_video_decoder_class_,
2075                              "<init>",
2076                              "()V"))) {
2077  ScopedLocalRefFrame local_ref_frame(jni);
2078  codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
2079  CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
2080
2081  j_init_decode_method_ = GetMethodID(
2082      jni, *j_media_codec_video_decoder_class_, "initDecode",
2083      "(IIZLandroid/opengl/EGLContext;)Z");
2084  j_release_method_ =
2085      GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2086  j_dequeue_input_buffer_method_ = GetMethodID(
2087      jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2088  j_queue_input_buffer_method_ = GetMethodID(
2089      jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2090  j_dequeue_output_buffer_method_ = GetMethodID(
2091      jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2092      "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
2093  j_release_output_buffer_method_ = GetMethodID(
2094      jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
2095
2096  j_input_buffers_field_ = GetFieldID(
2097      jni, *j_media_codec_video_decoder_class_,
2098      "inputBuffers", "[Ljava/nio/ByteBuffer;");
2099  j_output_buffers_field_ = GetFieldID(
2100      jni, *j_media_codec_video_decoder_class_,
2101      "outputBuffers", "[Ljava/nio/ByteBuffer;");
2102  j_color_format_field_ = GetFieldID(
2103      jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2104  j_width_field_ = GetFieldID(
2105      jni, *j_media_codec_video_decoder_class_, "width", "I");
2106  j_height_field_ = GetFieldID(
2107      jni, *j_media_codec_video_decoder_class_, "height", "I");
2108  j_stride_field_ = GetFieldID(
2109      jni, *j_media_codec_video_decoder_class_, "stride", "I");
2110  j_slice_height_field_ = GetFieldID(
2111      jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
2112  j_textureID_field_ = GetFieldID(
2113      jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2114  j_surface_texture_field_ = GetFieldID(
2115      jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2116      "Landroid/graphics/SurfaceTexture;");
2117
2118  jclass j_decoder_output_buffer_info_class = FindClass(jni,
2119      "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2120  j_info_index_field_ = GetFieldID(
2121      jni, j_decoder_output_buffer_info_class, "index", "I");
2122  j_info_offset_field_ = GetFieldID(
2123      jni, j_decoder_output_buffer_info_class, "offset", "I");
2124  j_info_size_field_ = GetFieldID(
2125      jni, j_decoder_output_buffer_info_class, "size", "I");
2126  j_info_presentation_timestamp_us_field_ = GetFieldID(
2127      jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
2128
2129  CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
2130  use_surface_ = true;
2131  if (render_egl_context_ == NULL)
2132    use_surface_ = false;
2133  memset(&codec_, 0, sizeof(codec_));
2134}
2135
2136MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
2137  // Call Release() to ensure no more callbacks to us after we are deleted.
2138  Release();
2139}
2140
2141int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2142    int32_t numberOfCores) {
2143  if (inst == NULL) {
2144    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2145  }
2146  int ret_val = Release();
2147  if (ret_val < 0) {
2148    return ret_val;
2149  }
2150  // Save VideoCodec instance for later.
2151  if (&codec_ != inst) {
2152    codec_ = *inst;
2153  }
2154  codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2155
2156  // Always start with a complete key frame.
2157  key_frame_required_ = true;
2158  frames_received_ = 0;
2159  frames_decoded_ = 0;
2160
2161  // Call Java init.
2162  return codec_thread_->Invoke<int32_t>(
2163      Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2164}
2165
2166int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2167  CheckOnCodecThread();
2168  JNIEnv* jni = AttachCurrentThreadIfNeeded();
2169  ScopedLocalRefFrame local_ref_frame(jni);
2170  ALOGD("InitDecodeOnCodecThread: %d x %d. fps: %d",
2171      codec_.width, codec_.height, codec_.maxFramerate);
2172
2173  bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2174                                       j_init_decode_method_,
2175                                       codec_.width,
2176                                       codec_.height,
2177                                       use_surface_,
2178                                       render_egl_context_);
2179  CHECK_EXCEPTION(jni);
2180  if (!success) {
2181    return WEBRTC_VIDEO_CODEC_ERROR;
2182  }
2183  inited_ = true;
2184
2185  max_pending_frames_ = 0;
2186  if (use_surface_) {
2187    max_pending_frames_ = 1;
2188  }
2189  start_time_ms_ = GetCurrentTimeMs();
2190  current_frames_ = 0;
2191  current_bytes_ = 0;
2192  current_decoding_time_ms_ = 0;
2193  timestamps_.clear();
2194  ntp_times_ms_.clear();
2195  frame_rtc_times_ms_.clear();
2196
2197  jobjectArray input_buffers = (jobjectArray)GetObjectField(
2198      jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2199  size_t num_input_buffers = jni->GetArrayLength(input_buffers);
2200  input_buffers_.resize(num_input_buffers);
2201  for (size_t i = 0; i < num_input_buffers; ++i) {
2202    input_buffers_[i] =
2203        jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
2204    CHECK_EXCEPTION(jni);
2205  }
2206
2207  if (use_surface_) {
2208    jobject surface_texture = GetObjectField(
2209        jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
2210    surface_texture_ = jni->NewGlobalRef(surface_texture);
2211  }
2212  codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2213
2214  return WEBRTC_VIDEO_CODEC_OK;
2215}
2216
2217int32_t MediaCodecVideoDecoder::Release() {
2218  return codec_thread_->Invoke<int32_t>(
2219        Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2220}
2221
2222int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
2223  if (!inited_) {
2224    return WEBRTC_VIDEO_CODEC_OK;
2225  }
2226  CheckOnCodecThread();
2227  JNIEnv* jni = AttachCurrentThreadIfNeeded();
2228  ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2229  ScopedLocalRefFrame local_ref_frame(jni);
2230  for (size_t i = 0; i < input_buffers_.size(); i++) {
2231    jni->DeleteGlobalRef(input_buffers_[i]);
2232  }
2233  input_buffers_.clear();
2234  if (use_surface_) {
2235    // Before deleting texture object make sure it is no longer referenced
2236    // by any TextureVideoFrame.
2237    int32_t waitTimeoutUs = 3000000;  // 3 second wait
2238    while (waitTimeoutUs > 0 && native_handle_.ref_count() > 0) {
2239      ALOGD("Current Texture RefCnt: %d", native_handle_.ref_count());
2240      usleep(30000);
2241      waitTimeoutUs -= 30000;
2242    }
2243    ALOGD("TextureRefCnt: %d", native_handle_.ref_count());
2244    jni->DeleteGlobalRef(surface_texture_);
2245  }
2246  jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
2247  CHECK_EXCEPTION(jni);
2248  rtc::MessageQueueManager::Clear(this);
2249  inited_ = false;
2250  return WEBRTC_VIDEO_CODEC_OK;
2251}
2252
2253
2254void MediaCodecVideoDecoder::CheckOnCodecThread() {
2255  CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2256      << "Running on wrong thread!";
2257}
2258
2259int32_t MediaCodecVideoDecoder::Decode(
2260    const EncodedImage& inputImage,
2261    bool missingFrames,
2262    const RTPFragmentationHeader* fragmentation,
2263    const CodecSpecificInfo* codecSpecificInfo,
2264    int64_t renderTimeMs) {
2265  if (!inited_) {
2266    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2267  }
2268  if (callback_ == NULL) {
2269    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2270  }
2271  if (inputImage._buffer == NULL && inputImage._length > 0) {
2272    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2273  }
2274  // Check if encoded frame dimension has changed.
2275  if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2276      (inputImage._encodedWidth != codec_.width ||
2277      inputImage._encodedHeight != codec_.height)) {
2278    codec_.width = inputImage._encodedWidth;
2279    codec_.height = inputImage._encodedHeight;
2280    InitDecode(&codec_, 1);
2281  }
2282
2283  // Always start with a complete key frame.
2284  if (key_frame_required_) {
2285    if (inputImage._frameType != webrtc::kKeyFrame) {
2286      return WEBRTC_VIDEO_CODEC_ERROR;
2287    }
2288    if (!inputImage._completeFrame) {
2289      return WEBRTC_VIDEO_CODEC_ERROR;
2290    }
2291    key_frame_required_ = false;
2292  }
2293  if (inputImage._length == 0) {
2294    return WEBRTC_VIDEO_CODEC_ERROR;
2295  }
2296
2297  return codec_thread_->Invoke<int32_t>(Bind(
2298      &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2299}
2300
2301int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2302    const EncodedImage& inputImage) {
2303  static uint8_t yVal_ = 0x7f;
2304
2305  CheckOnCodecThread();
2306  JNIEnv* jni = AttachCurrentThreadIfNeeded();
2307  ScopedLocalRefFrame local_ref_frame(jni);
2308
2309  // Try to drain the decoder and wait until output is not too
2310  // much behind the input.
2311  if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2312    ALOGV("Wait for output...");
2313    if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
2314      Reset();
2315      return WEBRTC_VIDEO_CODEC_ERROR;
2316    }
2317    if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2318      ALOGE("Output buffer dequeue timeout");
2319      Reset();
2320      return WEBRTC_VIDEO_CODEC_ERROR;
2321    }
2322  }
2323
2324  // Get input buffer.
2325  int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2326                                                j_dequeue_input_buffer_method_);
2327  CHECK_EXCEPTION(jni);
2328  if (j_input_buffer_index < 0) {
2329    ALOGE("dequeueInputBuffer error");
2330    Reset();
2331    return WEBRTC_VIDEO_CODEC_ERROR;
2332  }
2333
2334  // Copy encoded data to Java ByteBuffer.
2335  jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2336  uint8* buffer =
2337      reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
2338  CHECK(buffer) << "Indirect buffer??";
2339  int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
2340  CHECK_EXCEPTION(jni);
2341  if (buffer_capacity < inputImage._length) {
2342    ALOGE("Input frame size %d is bigger than buffer size %d.",
2343        inputImage._length, buffer_capacity);
2344    Reset();
2345    return WEBRTC_VIDEO_CODEC_ERROR;
2346  }
2347  ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
2348      frames_received_, j_input_buffer_index, inputImage._length);
2349  memcpy(buffer, inputImage._buffer, inputImage._length);
2350
2351  // Save input image timestamps for later output.
2352  frames_received_++;
2353  current_bytes_ += inputImage._length;
2354  timestamps_.push_back(inputImage._timeStamp);
2355  ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2356  frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2357
2358  // Feed input to decoder.
2359  jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2360  bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2361                                        j_queue_input_buffer_method_,
2362                                        j_input_buffer_index,
2363                                        inputImage._length,
2364                                        timestamp_us);
2365  CHECK_EXCEPTION(jni);
2366  if (!success) {
2367    ALOGE("queueInputBuffer error");
2368    Reset();
2369    return WEBRTC_VIDEO_CODEC_ERROR;
2370  }
2371
2372  // Try to drain the decoder
2373  if (!DeliverPendingOutputs(jni, 0)) {
2374    ALOGE("DeliverPendingOutputs error");
2375    Reset();
2376    return WEBRTC_VIDEO_CODEC_ERROR;
2377  }
2378
2379  return WEBRTC_VIDEO_CODEC_OK;
2380}
2381
2382bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2383    JNIEnv* jni, int dequeue_timeout_us) {
2384  if (frames_received_ <= frames_decoded_) {
2385    // No need to query for output buffers - decoder is drained.
2386    return true;
2387  }
2388  // Get decoder output.
2389  jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2390      *j_media_codec_video_decoder_,
2391      j_dequeue_output_buffer_method_,
2392      dequeue_timeout_us);
2393
2394  CHECK_EXCEPTION(jni);
2395  if (IsNull(jni, j_decoder_output_buffer_info)) {
2396    return true;
2397  }
2398
2399  // Extract output buffer info from Java DecoderOutputBufferInfo.
2400  int output_buffer_index =
2401      GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2402  if (output_buffer_index < 0) {
2403    ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
2404    Reset();
2405    return false;
2406  }
2407  int output_buffer_offset =
2408      GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2409  int output_buffer_size =
2410      GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2411  CHECK_EXCEPTION(jni);
2412
2413  // Get decoded video frame properties.
2414  int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2415      j_color_format_field_);
2416  int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2417  int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2418  int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2419  int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2420      j_slice_height_field_);
2421  int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2422      j_textureID_field_);
2423
2424  // Extract data from Java ByteBuffer and create output yuv420 frame -
2425  // for non surface decoding only.
2426  if (!use_surface_) {
2427    if (output_buffer_size < width * height * 3 / 2) {
2428      ALOGE("Insufficient output buffer size: %d", output_buffer_size);
2429      Reset();
2430      return false;
2431    }
2432    jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2433        jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2434    jobject output_buffer =
2435        jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2436    uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2437        output_buffer));
2438    CHECK_EXCEPTION(jni);
2439    payload += output_buffer_offset;
2440
2441    // Create yuv420 frame.
2442    if (color_format == COLOR_FormatYUV420Planar) {
2443      decoded_image_.CreateFrame(
2444          stride * slice_height, payload,
2445          (stride * slice_height) / 4, payload + (stride * slice_height),
2446          (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2447          width, height,
2448          stride, stride / 2, stride / 2);
2449    } else {
2450      // All other supported formats are nv12.
2451      decoded_image_.CreateEmptyFrame(width, height, width,
2452          width / 2, width / 2);
2453      libyuv::NV12ToI420(
2454          payload, stride,
2455          payload + stride * slice_height, stride,
2456          decoded_image_.buffer(webrtc::kYPlane),
2457          decoded_image_.stride(webrtc::kYPlane),
2458          decoded_image_.buffer(webrtc::kUPlane),
2459          decoded_image_.stride(webrtc::kUPlane),
2460          decoded_image_.buffer(webrtc::kVPlane),
2461          decoded_image_.stride(webrtc::kVPlane),
2462          width, height);
2463    }
2464  }
2465
2466  // Get frame timestamps from a queue.
2467  int32_t timestamp = timestamps_.front();
2468  timestamps_.erase(timestamps_.begin());
2469  int64_t ntp_time_ms = ntp_times_ms_.front();
2470  ntp_times_ms_.erase(ntp_times_ms_.begin());
2471  int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2472      frame_rtc_times_ms_.front();
2473  frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2474
2475  ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2476      " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2477      color_format, output_buffer_size, frame_decoding_time_ms);
2478
2479  // Return output buffer back to codec.
2480  bool success = jni->CallBooleanMethod(
2481      *j_media_codec_video_decoder_,
2482      j_release_output_buffer_method_,
2483      output_buffer_index,
2484      use_surface_);
2485  CHECK_EXCEPTION(jni);
2486  if (!success) {
2487    ALOGE("releaseOutputBuffer error");
2488    Reset();
2489    return false;
2490  }
2491
2492  // Calculate and print decoding statistics - every 3 seconds.
2493  frames_decoded_++;
2494  current_frames_++;
2495  current_decoding_time_ms_ += frame_decoding_time_ms;
2496  int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2497  if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2498      current_frames_ > 0) {
2499    ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2500        current_bytes_ * 8 / statistic_time_ms,
2501        (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2502        current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2503    start_time_ms_ = GetCurrentTimeMs();
2504    current_frames_ = 0;
2505    current_bytes_= 0;
2506    current_decoding_time_ms_ = 0;
2507  }
2508
2509  // Callback - output decoded frame.
2510  int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2511  if (use_surface_) {
2512    native_handle_.SetTextureObject(surface_texture_, texture_id);
2513    TextureVideoFrame texture_image(
2514        &native_handle_, width, height, timestamp, 0);
2515    texture_image.set_ntp_time_ms(ntp_time_ms);
2516    callback_status = callback_->Decoded(texture_image);
2517  } else {
2518    decoded_image_.set_timestamp(timestamp);
2519    decoded_image_.set_ntp_time_ms(ntp_time_ms);
2520    callback_status = callback_->Decoded(decoded_image_);
2521  }
2522  if (callback_status > 0) {
2523    ALOGE("callback error");
2524  }
2525
2526  return true;
2527}
2528
2529int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2530    DecodedImageCallback* callback) {
2531  callback_ = callback;
2532  return WEBRTC_VIDEO_CODEC_OK;
2533}
2534
2535int32_t MediaCodecVideoDecoder::Reset() {
2536  ALOGD("DecoderReset");
2537  if (!inited_) {
2538    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2539  }
2540  return InitDecode(&codec_, 1);
2541}
2542
2543void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
2544  JNIEnv* jni = AttachCurrentThreadIfNeeded();
2545  ScopedLocalRefFrame local_ref_frame(jni);
2546  if (!inited_) {
2547    return;
2548  }
2549  // We only ever send one message to |this| directly (not through a Bind()'d
2550  // functor), so expect no ID/data.
2551  CHECK(!msg->message_id) << "Unexpected message!";
2552  CHECK(!msg->pdata) << "Unexpected message!";
2553  CheckOnCodecThread();
2554
2555  DeliverPendingOutputs(jni, 0);
2556  codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2557}
2558
2559class MediaCodecVideoDecoderFactory
2560    : public cricket::WebRtcVideoDecoderFactory {
2561 public:
2562  MediaCodecVideoDecoderFactory();
2563  virtual ~MediaCodecVideoDecoderFactory();
2564  // WebRtcVideoDecoderFactory implementation.
2565  virtual webrtc::VideoDecoder* CreateVideoDecoder(
2566      webrtc::VideoCodecType type) OVERRIDE;
2567
2568  virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2569
2570 private:
2571  bool is_platform_supported_;
2572};
2573
2574MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2575  JNIEnv* jni = AttachCurrentThreadIfNeeded();
2576  ScopedLocalRefFrame local_ref_frame(jni);
2577  jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2578  is_platform_supported_ = jni->CallStaticBooleanMethod(
2579      j_decoder_class,
2580      GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
2581  CHECK_EXCEPTION(jni);
2582}
2583
2584MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2585
2586webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2587    webrtc::VideoCodecType type) {
2588  if (type != kVideoCodecVP8 || !is_platform_supported_) {
2589    return NULL;
2590  }
2591  return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2592}
2593
2594
2595void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2596    webrtc::VideoDecoder* decoder) {
2597  delete decoder;
2598}
2599
2600#endif  // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2601
2602}  // anonymous namespace
2603
2604// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2605// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2606#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2607  Java_org_webrtc_##name
2608
2609extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
2610  CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
2611  g_jvm = jvm;
2612  CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
2613
2614  CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
2615
2616  CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
2617
2618  JNIEnv* jni;
2619  if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2620    return -1;
2621  g_class_reference_holder = new ClassReferenceHolder(jni);
2622
2623  return JNI_VERSION_1_6;
2624}
2625
2626extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
2627  g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
2628  delete g_class_reference_holder;
2629  g_class_reference_holder = NULL;
2630  CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
2631  g_jvm = NULL;
2632}
2633
2634static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
2635  jfieldID native_dc_id = GetFieldID(jni,
2636      GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2637  jlong j_d = GetLongField(jni, j_dc, native_dc_id);
2638  return reinterpret_cast<DataChannelInterface*>(j_d);
2639}
2640
2641JOW(jlong, DataChannel_registerObserverNative)(
2642    JNIEnv* jni, jobject j_dc, jobject j_observer) {
2643  scoped_ptr<DataChannelObserverWrapper> observer(
2644      new DataChannelObserverWrapper(jni, j_observer));
2645  ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
2646  return jlongFromPointer(observer.release());
2647}
2648
2649JOW(void, DataChannel_unregisterObserverNative)(
2650    JNIEnv* jni, jobject j_dc, jlong native_observer) {
2651  ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2652  delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2653}
2654
2655JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2656  return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2657}
2658
2659JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2660  return JavaEnumFromIndex(
2661      jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2662}
2663
2664JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2665  uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
2666  CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2667      << "buffered_amount overflowed jlong!";
2668  return static_cast<jlong>(buffered_amount);
2669}
2670
2671JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2672  ExtractNativeDC(jni, j_dc)->Close();
2673}
2674
2675JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2676                                      jbyteArray data, jboolean binary) {
2677  jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2678  bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
2679      rtc::Buffer(bytes, jni->GetArrayLength(data)),
2680      binary));
2681  jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2682  return ret;
2683}
2684
2685JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
2686  CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
2687}
2688
2689JOW(void, Logging_nativeEnableTracing)(
2690    JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2691    jint nativeSeverity) {
2692  std::string path = JavaToStdString(jni, j_path);
2693  if (nativeLevels != webrtc::kTraceNone) {
2694    webrtc::Trace::set_level_filter(nativeLevels);
2695#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2696    if (path != "logcat:") {
2697#endif
2698      CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2699          << "SetTraceFile failed";
2700#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2701    } else {
2702      // Intentionally leak this to avoid needing to reason about its lifecycle.
2703      // It keeps no state and functions only as a dispatch point.
2704      static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2705    }
2706#endif
2707  }
2708  rtc::LogMessage::LogToDebug(nativeSeverity);
2709}
2710
2711JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
2712  CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
2713}
2714
2715JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2716  PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2717  delete p;
2718}
2719
2720JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
2721  CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
2722}
2723
2724JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2725  delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2726}
2727
2728JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2729  delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2730}
2731
2732JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2733  delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2734}
2735
2736JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
2737  CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
2738}
2739
2740JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2741    JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
2742  return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
2743      reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
2744}
2745
2746JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2747    JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
2748  return reinterpret_cast<MediaStreamInterface*>(pointer)
2749      ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
2750}
2751
2752JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2753    JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
2754  return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
2755      reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
2756}
2757
2758JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2759    JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
2760  return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
2761      reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
2762}
2763
2764JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2765  return JavaStringFromStdString(
2766      jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2767}
2768
2769JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
2770  CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
2771}
2772
2773JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2774    JNIEnv * jni, jclass, jobject j_observer) {
2775  return (jlong)new PCOJava(jni, j_observer);
2776}
2777
2778#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2779JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
2780    JNIEnv* jni, jclass, jobject context,
2781    jboolean initialize_audio, jboolean initialize_video,
2782    jobject render_egl_context) {
2783  CHECK(g_jvm) << "JNI_OnLoad failed to run?";
2784  bool failure = false;
2785  if (!factory_static_initialized) {
2786    if (initialize_video) {
2787      failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2788      failure |= webrtc::SetRenderAndroidVM(g_jvm);
2789    }
2790    if (initialize_audio)
2791      failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2792    factory_static_initialized = true;
2793  }
2794  if (initialize_video)
2795    failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2796        render_egl_context);
2797  return !failure;
2798}
2799#endif  // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2800
2801// Helper struct for working around the fact that CreatePeerConnectionFactory()
2802// comes in two flavors: either entirely automagical (constructing its own
2803// threads and deleting them on teardown, but no external codec factory support)
2804// or entirely manual (requires caller to delete threads after factory
2805// teardown).  This struct takes ownership of its ctor's arguments to present a
2806// single thing for Java to hold and eventually free.
2807class OwnedFactoryAndThreads {
2808 public:
2809  OwnedFactoryAndThreads(Thread* worker_thread,
2810                         Thread* signaling_thread,
2811                         PeerConnectionFactoryInterface* factory)
2812      : worker_thread_(worker_thread),
2813        signaling_thread_(signaling_thread),
2814        factory_(factory) {}
2815
2816  ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2817
2818  PeerConnectionFactoryInterface* factory() { return factory_; }
2819
2820 private:
2821  const scoped_ptr<Thread> worker_thread_;
2822  const scoped_ptr<Thread> signaling_thread_;
2823  PeerConnectionFactoryInterface* factory_;  // Const after ctor except dtor.
2824};
2825
2826JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2827    JNIEnv* jni, jclass) {
2828  // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2829  // ThreadManager only WrapCurrentThread()s the thread where it is first
2830  // created.  Since the semantics around when auto-wrapping happens in
2831  // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
2832  // about ramifications of auto-wrapping there.
2833  rtc::ThreadManager::Instance()->WrapCurrentThread();
2834  webrtc::Trace::CreateTrace();
2835  Thread* worker_thread = new Thread();
2836  worker_thread->SetName("worker_thread", NULL);
2837  Thread* signaling_thread = new Thread();
2838  signaling_thread->SetName("signaling_thread", NULL);
2839  CHECK(worker_thread->Start() && signaling_thread->Start())
2840      << "Failed to start threads";
2841  scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
2842  scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
2843#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
2844  encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2845  decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2846#endif
2847  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2848      webrtc::CreatePeerConnectionFactory(worker_thread,
2849                                          signaling_thread,
2850                                          NULL,
2851                                          encoder_factory.release(),
2852                                          decoder_factory.release()));
2853  OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2854      worker_thread, signaling_thread, factory.release());
2855  return jlongFromPointer(owned_factory);
2856}
2857
2858JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
2859  delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
2860  webrtc::Trace::ReturnTrace();
2861}
2862
2863static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2864  return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2865}
2866
2867JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2868    JNIEnv* jni, jclass, jlong native_factory, jstring label) {
2869  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2870      factoryFromJava(native_factory));
2871  rtc::scoped_refptr<MediaStreamInterface> stream(
2872      factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2873  return (jlong)stream.release();
2874}
2875
2876JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2877    JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2878    jobject j_constraints) {
2879  scoped_ptr<ConstraintsWrapper> constraints(
2880      new ConstraintsWrapper(jni, j_constraints));
2881  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2882      factoryFromJava(native_factory));
2883  rtc::scoped_refptr<VideoSourceInterface> source(
2884      factory->CreateVideoSource(
2885          reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2886          constraints.get()));
2887  return (jlong)source.release();
2888}
2889
2890JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2891    JNIEnv* jni, jclass, jlong native_factory, jstring id,
2892    jlong native_source) {
2893  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2894      factoryFromJava(native_factory));
2895  rtc::scoped_refptr<VideoTrackInterface> track(
2896      factory->CreateVideoTrack(
2897          JavaToStdString(jni, id),
2898          reinterpret_cast<VideoSourceInterface*>(native_source)));
2899  return (jlong)track.release();
2900}
2901
2902JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2903    JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2904  scoped_ptr<ConstraintsWrapper> constraints(
2905      new ConstraintsWrapper(jni, j_constraints));
2906  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2907      factoryFromJava(native_factory));
2908  rtc::scoped_refptr<AudioSourceInterface> source(
2909      factory->CreateAudioSource(constraints.get()));
2910  return (jlong)source.release();
2911}
2912
2913JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2914    JNIEnv* jni, jclass, jlong native_factory, jstring id,
2915    jlong native_source) {
2916  rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2917      factoryFromJava(native_factory));
2918  rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
2919      JavaToStdString(jni, id),
2920      reinterpret_cast<AudioSourceInterface*>(native_source)));
2921  return (jlong)track.release();
2922}
2923
2924static void JavaIceServersToJsepIceServers(
2925    JNIEnv* jni, jobject j_ice_servers,
2926    PeerConnectionInterface::IceServers* ice_servers) {
2927  jclass list_class = GetObjectClass(jni, j_ice_servers);
2928  jmethodID iterator_id = GetMethodID(
2929      jni, list_class, "iterator", "()Ljava/util/Iterator;");
2930  jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2931  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
2932  jmethodID iterator_has_next = GetMethodID(
2933      jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2934  jmethodID iterator_next = GetMethodID(
2935      jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2936  while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2937    CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
2938    jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2939    CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
2940    jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2941    jfieldID j_ice_server_uri_id =
2942        GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2943    jfieldID j_ice_server_username_id =
2944        GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2945    jfieldID j_ice_server_password_id =
2946        GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2947    jstring uri = reinterpret_cast<jstring>(
2948        GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2949    jstring username = reinterpret_cast<jstring>(
2950        GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2951    jstring password = reinterpret_cast<jstring>(
2952        GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2953    PeerConnectionInterface::IceServer server;
2954    server.uri = JavaToStdString(jni, uri);
2955    server.username = JavaToStdString(jni, username);
2956    server.password = JavaToStdString(jni, password);
2957    ice_servers->push_back(server);
2958  }
2959  CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
2960}
2961
2962JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2963    JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2964    jobject j_constraints, jlong observer_p) {
2965  rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
2966      reinterpret_cast<PeerConnectionFactoryInterface*>(
2967          factoryFromJava(factory)));
2968  PeerConnectionInterface::IceServers servers;
2969  JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2970  PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2971  observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2972  rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
2973      servers, observer->constraints(), NULL, NULL, observer));
2974  return (jlong)pc.release();
2975}
2976
2977static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2978    JNIEnv* jni, jobject j_pc) {
2979  jfieldID native_pc_id = GetFieldID(jni,
2980      GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2981  jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2982  return rtc::scoped_refptr<PeerConnectionInterface>(
2983      reinterpret_cast<PeerConnectionInterface*>(j_p));
2984}
2985
2986JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2987  const SessionDescriptionInterface* sdp =
2988      ExtractNativePC(jni, j_pc)->local_description();
2989  return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2990}
2991
2992JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2993  const SessionDescriptionInterface* sdp =
2994      ExtractNativePC(jni, j_pc)->remote_description();
2995  return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2996}
2997
2998JOW(jobject, PeerConnection_createDataChannel)(
2999    JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3000  DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
3001  rtc::scoped_refptr<DataChannelInterface> channel(
3002      ExtractNativePC(jni, j_pc)->CreateDataChannel(
3003          JavaToStdString(jni, j_label), &init));
3004  // Mustn't pass channel.get() directly through NewObject to avoid reading its
3005  // vararg parameter as 64-bit and reading memory that doesn't belong to the
3006  // 32-bit parameter.
3007  jlong nativeChannelPtr = jlongFromPointer(channel.get());
3008  CHECK(nativeChannelPtr) << "Failed to create DataChannel";
3009  jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3010  jmethodID j_data_channel_ctor = GetMethodID(
3011      jni, j_data_channel_class, "<init>", "(J)V");
3012  jobject j_channel = jni->NewObject(
3013      j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
3014  CHECK_EXCEPTION(jni) << "error during NewObject";
3015  // Channel is now owned by Java object, and will be freed from there.
3016  int bumped_count = channel->AddRef();
3017  CHECK(bumped_count == 2) << "Unexpected refcount";
3018  return j_channel;
3019}
3020
3021JOW(void, PeerConnection_createOffer)(
3022    JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3023  ConstraintsWrapper* constraints =
3024      new ConstraintsWrapper(jni, j_constraints);
3025  rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3026      new rtc::RefCountedObject<CreateSdpObserverWrapper>(
3027          jni, j_observer, constraints));
3028  ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3029}
3030
3031JOW(void, PeerConnection_createAnswer)(
3032    JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3033  ConstraintsWrapper* constraints =
3034      new ConstraintsWrapper(jni, j_constraints);
3035  rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3036      new rtc::RefCountedObject<CreateSdpObserverWrapper>(
3037          jni, j_observer, constraints));
3038  ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3039}
3040
3041// Helper to create a SessionDescriptionInterface from a SessionDescription.
3042static SessionDescriptionInterface* JavaSdpToNativeSdp(
3043    JNIEnv* jni, jobject j_sdp) {
3044  jfieldID j_type_id = GetFieldID(
3045      jni, GetObjectClass(jni, j_sdp), "type",
3046      "Lorg/webrtc/SessionDescription$Type;");
3047  jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3048  jmethodID j_canonical_form_id = GetMethodID(
3049      jni, GetObjectClass(jni, j_type), "canonicalForm",
3050      "()Ljava/lang/String;");
3051  jstring j_type_string = (jstring)jni->CallObjectMethod(
3052      j_type, j_canonical_form_id);
3053  CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
3054  std::string std_type = JavaToStdString(jni, j_type_string);
3055
3056  jfieldID j_description_id = GetFieldID(
3057      jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3058  jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3059  std::string std_description = JavaToStdString(jni, j_description);
3060
3061  return webrtc::CreateSessionDescription(
3062      std_type, std_description, NULL);
3063}
3064
3065JOW(void, PeerConnection_setLocalDescription)(
3066    JNIEnv* jni, jobject j_pc,
3067    jobject j_observer, jobject j_sdp) {
3068  rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3069      new rtc::RefCountedObject<SetSdpObserverWrapper>(
3070          jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3071  ExtractNativePC(jni, j_pc)->SetLocalDescription(
3072      observer, JavaSdpToNativeSdp(jni, j_sdp));
3073}
3074
3075JOW(void, PeerConnection_setRemoteDescription)(
3076    JNIEnv* jni, jobject j_pc,
3077    jobject j_observer, jobject j_sdp) {
3078  rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3079      new rtc::RefCountedObject<SetSdpObserverWrapper>(
3080          jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3081  ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3082      observer, JavaSdpToNativeSdp(jni, j_sdp));
3083}
3084
3085JOW(jboolean, PeerConnection_updateIce)(
3086    JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3087  PeerConnectionInterface::IceServers ice_servers;
3088  JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
3089  scoped_ptr<ConstraintsWrapper> constraints(
3090      new ConstraintsWrapper(jni, j_constraints));
3091  return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3092}
3093
3094JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3095    JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3096    jint j_sdp_mline_index, jstring j_candidate_sdp) {
3097  std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3098  std::string sdp = JavaToStdString(jni, j_candidate_sdp);
3099  scoped_ptr<IceCandidateInterface> candidate(
3100      webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3101  return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3102}
3103
3104JOW(jboolean, PeerConnection_nativeAddLocalStream)(
3105    JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
3106  scoped_ptr<ConstraintsWrapper> constraints(
3107      new ConstraintsWrapper(jni, j_constraints));
3108  return ExtractNativePC(jni, j_pc)->AddStream(
3109      reinterpret_cast<MediaStreamInterface*>(native_stream),
3110      constraints.get());
3111}
3112
3113JOW(void, PeerConnection_nativeRemoveLocalStream)(
3114    JNIEnv* jni, jobject j_pc, jlong native_stream) {
3115  ExtractNativePC(jni, j_pc)->RemoveStream(
3116      reinterpret_cast<MediaStreamInterface*>(native_stream));
3117}
3118
3119JOW(bool, PeerConnection_nativeGetStats)(
3120    JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
3121  rtc::scoped_refptr<StatsObserverWrapper> observer(
3122      new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
3123  return ExtractNativePC(jni, j_pc)->GetStats(
3124      observer,
3125      reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3126      PeerConnectionInterface::kStatsOutputLevelStandard);
3127}
3128
3129JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3130  PeerConnectionInterface::SignalingState state =
3131      ExtractNativePC(jni, j_pc)->signaling_state();
3132  return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3133}
3134
3135JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3136  PeerConnectionInterface::IceConnectionState state =
3137      ExtractNativePC(jni, j_pc)->ice_connection_state();
3138  return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3139}
3140
3141JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
3142  PeerConnectionInterface::IceGatheringState state =
3143      ExtractNativePC(jni, j_pc)->ice_gathering_state();
3144  return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
3145}
3146
3147JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3148  ExtractNativePC(jni, j_pc)->Close();
3149  return;
3150}
3151
3152JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
3153  rtc::scoped_refptr<MediaSourceInterface> p(
3154      reinterpret_cast<MediaSourceInterface*>(j_p));
3155  return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3156}
3157
3158JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3159    JNIEnv* jni, jclass, jstring j_device_name) {
3160  std::string device_name = JavaToStdString(jni, j_device_name);
3161  scoped_ptr<cricket::DeviceManagerInterface> device_manager(
3162      cricket::DeviceManagerFactory::Create());
3163  CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
3164  cricket::Device device;
3165  if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
3166    LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
3167    return 0;
3168  }
3169  scoped_ptr<cricket::VideoCapturer> capturer(
3170      device_manager->CreateVideoCapturer(device));
3171  return (jlong)capturer.release();
3172}
3173
3174JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3175    JNIEnv* jni, jclass, int x, int y) {
3176  scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3177      cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
3178  return (jlong)renderer.release();
3179}
3180
3181JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3182    JNIEnv* jni, jclass, jobject j_callbacks) {
3183  scoped_ptr<JavaVideoRendererWrapper> renderer(
3184      new JavaVideoRendererWrapper(jni, j_callbacks));
3185  return (jlong)renderer.release();
3186}
3187
3188JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3189  cricket::VideoCapturer* capturer =
3190      reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
3191  scoped_ptr<cricket::VideoFormatPod> format(
3192      new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3193  capturer->Stop();
3194  return jlongFromPointer(format.release());
3195}
3196
3197JOW(void, VideoSource_restart)(
3198    JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
3199  CHECK(j_p_source);
3200  CHECK(j_p_format);
3201  scoped_ptr<cricket::VideoFormatPod> format(
3202      reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3203  reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3204      StartCapturing(cricket::VideoFormat(*format));
3205}
3206
3207JOW(void, VideoSource_freeNativeVideoFormat)(
3208    JNIEnv* jni, jclass, jlong j_p) {
3209  delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3210}
3211
3212JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
3213  return JavaStringFromStdString(
3214      jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
3215}
3216
3217JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
3218  return JavaStringFromStdString(
3219      jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
3220}
3221
3222JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
3223  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
3224}
3225
3226JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
3227  return JavaEnumFromIndex(
3228      jni,
3229      "MediaStreamTrack$State",
3230      reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
3231}
3232
3233JOW(jboolean, MediaStreamTrack_nativeSetState)(
3234    JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
3235  MediaStreamTrackInterface::TrackState new_state =
3236      (MediaStreamTrackInterface::TrackState)j_new_state;
3237  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3238      ->set_state(new_state);
3239}
3240
3241JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3242    JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
3243  return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3244      ->set_enabled(enabled);
3245}
3246
3247JOW(void, VideoTrack_nativeAddRenderer)(
3248    JNIEnv* jni, jclass,
3249    jlong j_video_track_pointer, jlong j_renderer_pointer) {
3250  reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
3251      reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3252}
3253
3254JOW(void, VideoTrack_nativeRemoveRenderer)(
3255    JNIEnv* jni, jclass,
3256    jlong j_video_track_pointer, jlong j_renderer_pointer) {
3257  reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
3258      reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3259}
3260