Home | History | Annotate | Download | only in jni
      1 /*
      2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 // This file contains JNI for the video engine interfaces.
     12 // The native functions are found using jni's auto discovery.
     13 
     14 #include "webrtc/examples/android/media_demo/jni/video_engine_jni.h"
     15 
     16 #include <map>
     17 #include <string>
     18 
     19 #include "webrtc/common_types.h"
     20 #include "webrtc/examples/android/media_demo/jni/jni_helpers.h"
     21 #include "webrtc/examples/android/media_demo/jni/media_codec_video_decoder.h"
     22 #include "webrtc/examples/android/media_demo/jni/voice_engine_jni.h"
     23 #include "webrtc/modules/utility/interface/helpers_android.h"
     24 #include "webrtc/test/channel_transport/include/channel_transport.h"
     25 #include "webrtc/video_engine/include/vie_base.h"
     26 #include "webrtc/video_engine/include/vie_capture.h"
     27 #include "webrtc/video_engine/include/vie_codec.h"
     28 #include "webrtc/video_engine/include/vie_external_codec.h"
     29 #include "webrtc/video_engine/include/vie_network.h"
     30 #include "webrtc/video_engine/include/vie_render.h"
     31 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
     32 
     33 // Macro for native functions that can be found by way of jni-auto discovery.
     34 // Note extern "C" is needed for "discovery" of native methods to work.
     35 #define JOWW(rettype, name)                                             \
     36   extern "C" rettype JNIEXPORT JNICALL Java_org_webrtc_webrtcdemo_##name
     37 
     38 namespace {
     39 
     40 static JavaVM* g_vm = NULL;
     41 static ClassReferenceHolder* g_class_reference_holder = NULL;
     42 
     43 jclass GetClass(const char* name) {
     44   CHECK(g_class_reference_holder, "Class reference holder NULL");
     45   return g_class_reference_holder->GetClass(name);
     46 }
     47 
     48 // C(++) description of a camera. This class is created by Java native calls
     49 // and associated with the CameraDesc Java class. The Java class is used in the
     50 // Java code but it is just a thin wrapper of the C(++) class that contain the
     51 // actual information. The information is stored in C(++) as it is used to
     52 // call video engine APIs.
     53 struct CameraDesc {
     54   // The name and id corresponds to ViECapture's |device_nameUTF8| and
     55   // |unique_idUTF8|.
     56   char name[64];
     57   char unique_id[64];
     58 };
     59 
     60 // C++ callback class that can be used to register for callbacks from the
     61 // video engine. It further propagates the callbacks to
     62 // VideoDecodeEncodeObserver.java interface. The memory associated with this
     63 // class is managed globally by the VideoEngineData class when registering and
     64 // unregistering VideoDecodeEncodeObserver.java to receive callbacks.
     65 class VideoDecodeEncodeObserver : public webrtc::ViEDecoderObserver,
     66                                   public webrtc::ViEEncoderObserver {
     67  public:
     68   explicit VideoDecodeEncodeObserver(jobject j_observer)
     69       : j_observer_(j_observer) {
     70     webrtc::AttachThreadScoped ats(g_vm);
     71     JNIEnv* jni = ats.env();
     72     jclass j_observer_class = jni->GetObjectClass(j_observer_);
     73     incoming_rate_ =
     74         GetMethodID(jni, j_observer_class, "incomingRate", "(III)V");
     75     incoming_codec_changed_ =
     76         GetMethodID(jni, j_observer_class, "incomingCodecChanged",
     77                     "(ILorg/webrtc/webrtcdemo/VideoCodecInst;)V");
     78     request_new_keyframe_ =
     79         GetMethodID(jni, j_observer_class, "requestNewKeyFrame", "(I)V");
     80     outgoing_rate_ =
     81         GetMethodID(jni, j_observer_class, "outgoingRate", "(III)V");
     82     j_observer_ = jni->NewGlobalRef(j_observer_);
     83   }
     84 
     85   ~VideoDecodeEncodeObserver() {
     86     webrtc::AttachThreadScoped ats(g_vm);
     87     JNIEnv* jni = ats.env();
     88     jni->DeleteGlobalRef(j_observer_);
     89   }
     90 
     91   virtual void IncomingRate(const int video_channel,
     92                             const unsigned int framerate,
     93                             const unsigned int bitrate) {
     94     webrtc::AttachThreadScoped ats(g_vm);
     95     JNIEnv* jni = ats.env();
     96     jni->CallVoidMethod(j_observer_, incoming_rate_, video_channel,
     97                         static_cast<int>(framerate), static_cast<int>(bitrate));
     98   }
     99 
    100   virtual void DecoderTiming(int decode_ms, int max_decode_ms,
    101                              int current_delay_ms, int target_delay_ms,
    102                              int jitter_buffer_ms, int min_playout_delay_ms,
    103                              int render_delay_ms) {
    104     // TODO(fischman): consider plumbing this through to Java.
    105   }
    106 
    107   virtual void IncomingCodecChanged(const int video_channel,
    108                                     const webrtc::VideoCodec& video_codec) {
    109     webrtc::AttachThreadScoped ats(g_vm);
    110     JNIEnv* jni = ats.env();
    111     webrtc::VideoCodec* codec = new webrtc::VideoCodec(video_codec);
    112     jclass j_codec_class =
    113         GetClass("org/webrtc/webrtcdemo/VideoCodecInst");
    114     jmethodID j_codec_ctor = GetMethodID(jni, j_codec_class, "<init>", "(J)V");
    115     jobject j_codec =
    116         jni->NewObject(j_codec_class, j_codec_ctor, jlongFromPointer(codec));
    117     CHECK_EXCEPTION(jni, "error during NewObject");
    118     jni->CallVoidMethod(j_observer_, incoming_codec_changed_, video_channel,
    119                         j_codec);
    120   }
    121 
    122   virtual void RequestNewKeyFrame(const int video_channel) {
    123     webrtc::AttachThreadScoped ats(g_vm);
    124     JNIEnv* jni = ats.env();
    125     jni->CallVoidMethod(j_observer_, request_new_keyframe_, video_channel);
    126   }
    127 
    128   virtual void OutgoingRate(const int video_channel,
    129                             const unsigned int framerate,
    130                             const unsigned int bitrate) {
    131     webrtc::AttachThreadScoped ats(g_vm);
    132     JNIEnv* jni = ats.env();
    133     jni->CallVoidMethod(j_observer_, outgoing_rate_, video_channel,
    134                         static_cast<int>(framerate), static_cast<int>(bitrate));
    135   }
    136 
    137   virtual void SuspendChange(int video_channel, bool is_suspended) {}
    138 
    139  private:
    140   jobject j_observer_;
    141   jmethodID incoming_rate_;
    142   jmethodID incoming_codec_changed_;
    143   jmethodID request_new_keyframe_;
    144   jmethodID outgoing_rate_;
    145 };
    146 
    147 template<typename T>
    148 void ReleaseSubApi(T instance) {
    149   CHECK(instance->Release() == 0, "failed to release instance")
    150 }
    151 
    152 class VideoEngineData {
    153  public:
    154   VideoEngineData()
    155       : vie(webrtc::VideoEngine::Create()),
    156         base(webrtc::ViEBase::GetInterface(vie)),
    157         codec(webrtc::ViECodec::GetInterface(vie)),
    158         network(webrtc::ViENetwork::GetInterface(vie)),
    159         rtp(webrtc::ViERTP_RTCP::GetInterface(vie)),
    160         render(webrtc::ViERender::GetInterface(vie)),
    161         capture(webrtc::ViECapture::GetInterface(vie)),
    162         externalCodec(webrtc::ViEExternalCodec::GetInterface(vie)) {
    163     CHECK(vie != NULL, "Video engine instance failed to be created");
    164     CHECK(base != NULL, "Failed to acquire base interface");
    165     CHECK(codec != NULL, "Failed to acquire codec interface");
    166     CHECK(network != NULL, "Failed to acquire network interface");
    167     CHECK(rtp != NULL, "Failed to acquire rtp interface");
    168     CHECK(render != NULL, "Failed to acquire render interface");
    169     CHECK(capture != NULL, "Failed to acquire capture interface");
    170     CHECK(externalCodec != NULL, "Failed to acquire externalCodec interface");
    171   }
    172 
    173   ~VideoEngineData() {
    174     CHECK(channel_transports_.empty(),
    175           "ViE transports must be deleted before terminating");
    176     CHECK(observers_.empty(),
    177           "ViE observers must be deleted before terminating");
    178     CHECK(external_decoders_.empty(),
    179           "ViE external decoders must be deleted before terminating");
    180     ReleaseSubApi(externalCodec);
    181     ReleaseSubApi(capture);
    182     ReleaseSubApi(render);
    183     ReleaseSubApi(rtp);
    184     ReleaseSubApi(network);
    185     ReleaseSubApi(codec);
    186     ReleaseSubApi(base);
    187     webrtc::VideoEngine* vie_pointer = vie;
    188     CHECK(webrtc::VideoEngine::Delete(vie_pointer), "ViE failed to be deleted");
    189   }
    190 
    191   int CreateChannel() {
    192     int channel;
    193     CHECK(base->CreateChannel(channel) == 0, "Failed to create channel");
    194     CreateTransport(channel);
    195     return channel;
    196   }
    197 
    198   int DeleteChannel(int channel) {
    199     if (base->DeleteChannel(channel) != 0) {
    200       return -1;
    201     }
    202     DeleteTransport(channel);
    203     return 0;
    204   }
    205 
    206   webrtc::test::VideoChannelTransport* GetTransport(int channel) {
    207     ChannelTransports::iterator found = channel_transports_.find(channel);
    208     if (found == channel_transports_.end()) {
    209       return NULL;
    210     }
    211     return found->second;
    212   }
    213 
    214   int RegisterObserver(int channel, jobject j_observer) {
    215     CHECK(observers_.find(channel) == observers_.end(),
    216           "Observer already created for channel, inconsistent state");
    217     observers_[channel] = new VideoDecodeEncodeObserver(j_observer);
    218     int ret_val = codec->RegisterDecoderObserver(channel, *observers_[channel]);
    219     ret_val |= codec->RegisterEncoderObserver(channel, *observers_[channel]);
    220     return ret_val;
    221   }
    222 
    223   int DeregisterObserver(int channel) {
    224     Observers::iterator found = observers_.find(channel);
    225     if (observers_.find(channel) == observers_.end()) {
    226       return -1;
    227     }
    228     int ret_val = codec->DeregisterDecoderObserver(channel);
    229     ret_val |= codec->DeregisterEncoderObserver(channel);
    230     delete found->second;
    231     observers_.erase(found);
    232     return ret_val;
    233   }
    234 
    235   int RegisterExternalReceiveCodec(jint channel, jint pl_type, jobject decoder,
    236                                    bool internal_source) {
    237     CHECK(external_decoders_.find(channel) == external_decoders_.end(),
    238           "External decoder already created for channel, inconsistent state");
    239     external_decoders_[channel] =
    240         new webrtc::MediaCodecVideoDecoder(g_vm, decoder);
    241     return externalCodec->RegisterExternalReceiveCodec(
    242         channel, pl_type, external_decoders_[channel], internal_source);
    243   }
    244 
    245   int DeRegisterExternalReceiveCodec(jint channel, jint pl_type) {
    246     ExternalDecoders::iterator found = external_decoders_.find(channel);
    247     CHECK(found != external_decoders_.end(),
    248           "ViE channel missing external decoder, inconsistent state");
    249     CHECK(externalCodec->DeRegisterExternalReceiveCodec(channel, pl_type) == 0,
    250           "Failed to register external receive decoder");
    251     delete found->second;
    252     external_decoders_.erase(found);
    253     return 0;
    254   }
    255 
    256   webrtc::VideoEngine* const vie;
    257   webrtc::ViEBase* const base;
    258   webrtc::ViECodec* const codec;
    259   webrtc::ViENetwork* const network;
    260   webrtc::ViERTP_RTCP* const rtp;
    261   webrtc::ViERender* const render;
    262   webrtc::ViECapture* const capture;
    263   webrtc::ViEExternalCodec* const externalCodec;
    264 
    265  private:
    266   // Video engine no longer provides a socket implementation. There is,
    267   // however, a socket implementation in webrtc::test.
    268   typedef std::map<int, webrtc::test::VideoChannelTransport*>
    269   ChannelTransports;
    270   typedef std::map<int, VideoDecodeEncodeObserver*> Observers;
    271   typedef std::map<int, webrtc::MediaCodecVideoDecoder*> ExternalDecoders;
    272 
    273   void CreateTransport(int channel) {
    274     CHECK(GetTransport(channel) == NULL,
    275           "Transport already created for ViE channel, inconsistent state");
    276     channel_transports_[channel] =
    277         new webrtc::test::VideoChannelTransport(network, channel);
    278   }
    279   void DeleteTransport(int channel) {
    280     CHECK(GetTransport(channel) != NULL,
    281           "ViE channel missing transport, inconsistent state");
    282     delete channel_transports_[channel];
    283     channel_transports_.erase(channel);
    284   }
    285 
    286   ChannelTransports channel_transports_;
    287   Observers observers_;
    288   ExternalDecoders external_decoders_;
    289 };
    290 
    291 webrtc::VideoCodec* GetCodecInst(JNIEnv* jni, jobject j_codec) {
    292   jclass j_codec_class = jni->GetObjectClass(j_codec);
    293   jfieldID native_codec_id =
    294       jni->GetFieldID(j_codec_class, "nativeCodecInst", "J");
    295   jlong j_p = jni->GetLongField(j_codec, native_codec_id);
    296   return reinterpret_cast<webrtc::VideoCodec*>(j_p);
    297 }
    298 
    299 CameraDesc* GetCameraDesc(JNIEnv* jni, jobject j_camera) {
    300   jclass j_camera_class = jni->GetObjectClass(j_camera);
    301   jfieldID native_camera_id =
    302       jni->GetFieldID(j_camera_class, "nativeCameraDesc", "J");
    303   jlong j_p = jni->GetLongField(j_camera, native_camera_id);
    304   return reinterpret_cast<CameraDesc*>(j_p);
    305 }
    306 
    307 VideoEngineData* GetVideoEngineData(JNIEnv* jni, jobject j_vie) {
    308   jclass j_vie_class = jni->GetObjectClass(j_vie);
    309   jfieldID native_vie_id =
    310       jni->GetFieldID(j_vie_class, "nativeVideoEngine", "J");
    311   jlong j_p = jni->GetLongField(j_vie, native_vie_id);
    312   return reinterpret_cast<VideoEngineData*>(j_p);
    313 }
    314 
    315 }  // namespace
    316 
    317 namespace webrtc_examples {
    318 
    319 static const char* g_classes[] = {
    320   "org/webrtc/webrtcdemo/CameraDesc",
    321   "org/webrtc/webrtcdemo/RtcpStatistics",
    322   "org/webrtc/webrtcdemo/VideoCodecInst",
    323   "org/webrtc/webrtcdemo/VideoDecodeEncodeObserver",
    324   "org/webrtc/webrtcdemo/MediaCodecVideoDecoder"};
    325 
    326 void SetVieDeviceObjects(JavaVM* vm) {
    327   CHECK(vm, "Trying to register NULL vm");
    328   CHECK(!g_vm, "Trying to re-register vm");
    329   g_vm = vm;
    330   webrtc::AttachThreadScoped ats(g_vm);
    331   JNIEnv* jni = ats.env();
    332   g_class_reference_holder = new ClassReferenceHolder(
    333       jni, g_classes, ARRAYSIZE(g_classes));
    334 }
    335 
    336 void ClearVieDeviceObjects() {
    337   CHECK(g_vm, "Clearing vm without it being set");
    338   {
    339     webrtc::AttachThreadScoped ats(g_vm);
    340     g_class_reference_holder->FreeReferences(ats.env());
    341   }
    342   g_vm = NULL;
    343   delete g_class_reference_holder;
    344   g_class_reference_holder = NULL;
    345 }
    346 
    347 }  // namespace webrtc_examples
    348 
    349 JOWW(jlong, VideoEngine_create)(JNIEnv* jni, jclass) {
    350   VideoEngineData* vie_data = new VideoEngineData();
    351   return jlongFromPointer(vie_data);
    352 }
    353 
    354 JOWW(jint, VideoEngine_init)(JNIEnv* jni, jobject j_vie) {
    355   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    356   return vie_data->base->Init();
    357 }
    358 
    359 JOWW(jint, VideoEngine_setVoiceEngine)(JNIEnv* jni, jobject j_vie,
    360                                        jobject j_voe) {
    361   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    362   webrtc::VoiceEngine* voe = GetVoiceEngine(jni, j_voe);
    363   return vie_data->base->SetVoiceEngine(voe);
    364 }
    365 
    366 JOWW(void, VideoEngine_dispose)(JNIEnv* jni, jobject j_vie) {
    367   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    368   delete vie_data;
    369 }
    370 
    371 JOWW(jint, VideoEngine_startSend)(JNIEnv* jni, jobject j_vie, jint channel) {
    372   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    373   return vie_data->base->StartSend(channel);
    374 }
    375 
    376 JOWW(jint, VideoEngine_stopRender)(JNIEnv* jni, jobject j_vie, jint channel) {
    377   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    378   return vie_data->render->StopRender(channel);
    379 }
    380 
    381 JOWW(jint, VideoEngine_stopSend)(JNIEnv* jni, jobject j_vie, jint channel) {
    382   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    383   return vie_data->base->StopSend(channel);
    384 }
    385 
    386 JOWW(jint, VideoEngine_startReceive)(JNIEnv* jni, jobject j_vie, jint channel) {
    387   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    388   return vie_data->base->StartReceive(channel);
    389 }
    390 
    391 JOWW(jint, VideoEngine_stopReceive)(JNIEnv* jni, jobject j_vie, jint channel) {
    392   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    393   return vie_data->base->StopReceive(channel);
    394 }
    395 
    396 JOWW(jint, VideoEngine_createChannel)(JNIEnv* jni, jobject j_vie) {
    397   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    398   return vie_data->CreateChannel();
    399 }
    400 
    401 JOWW(jint, VideoEngine_deleteChannel)(JNIEnv* jni, jobject j_vie,
    402                                       jint channel) {
    403   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    404   return vie_data->DeleteChannel(channel);
    405 }
    406 
    407 JOWW(jint,
    408      VideoEngine_connectAudioChannel(JNIEnv* jni, jobject j_vie,
    409                                      jint video_channel, jint audio_channel)) {
    410   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    411   return vie_data->base->ConnectAudioChannel(video_channel, audio_channel);
    412 }
    413 
    414 JOWW(jint, VideoEngine_setLocalReceiver)(JNIEnv* jni, jobject j_vie,
    415                                          jint channel, jint port) {
    416   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    417   return vie_data->GetTransport(channel)->SetLocalReceiver(port);
    418 }
    419 
    420 JOWW(jint, VideoEngine_setSendDestination)(JNIEnv* jni, jobject j_vie,
    421                                            jint channel, jint port,
    422                                            jstring j_addr) {
    423   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    424   std::string addr = JavaToStdString(jni, j_addr);
    425   webrtc::test::VideoChannelTransport* transport =
    426       vie_data->GetTransport(channel);
    427   return transport->SetSendDestination(addr.c_str(), port);
    428 }
    429 
    430 JOWW(jint, VideoEngine_setReceiveCodec)(JNIEnv* jni, jobject j_vie,
    431                                         jint channel, jobject j_codec) {
    432   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    433   webrtc::VideoCodec* codec = GetCodecInst(jni, j_codec);
    434   return vie_data->codec->SetReceiveCodec(channel, *codec);
    435 }
    436 
    437 JOWW(jint, VideoEngine_setSendCodec)(JNIEnv* jni, jobject j_vie, jint channel,
    438                                      jobject j_codec) {
    439   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    440   webrtc::VideoCodec* codec = GetCodecInst(jni, j_codec);
    441   return vie_data->codec->SetSendCodec(channel, *codec);
    442 }
    443 
    444 JOWW(jint, VideoEngine_numberOfCodecs)(JNIEnv* jni, jobject j_vie) {
    445   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    446   return vie_data->codec->NumberOfCodecs();
    447 }
    448 
    449 JOWW(jobject, VideoEngine_getCodec)(JNIEnv* jni, jobject j_vie, jint index) {
    450   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    451   webrtc::VideoCodec* codec = new webrtc::VideoCodec();
    452   CHECK(vie_data->codec->GetCodec(index, *codec) == 0,
    453         "getCodec must be called with valid index");
    454   jclass j_codec_class = GetClass("org/webrtc/webrtcdemo/VideoCodecInst");
    455   jmethodID j_codec_ctor = GetMethodID(jni, j_codec_class, "<init>", "(J)V");
    456   jobject j_codec =
    457       jni->NewObject(j_codec_class, j_codec_ctor, jlongFromPointer(codec));
    458   CHECK_EXCEPTION(jni, "error during NewObject");
    459   return j_codec;
    460 }
    461 
    462 JOWW(jint, VideoEngine_addRenderer)(JNIEnv* jni, jobject j_vie, jint channel,
    463                                     jobject gl_surface, jint z_order,
    464                                     jfloat left, jfloat top, jfloat right,
    465                                     jfloat bottom) {
    466   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    467   return vie_data->render->AddRenderer(channel, gl_surface, z_order, left, top,
    468                                        right, bottom);
    469 }
    470 
    471 JOWW(jint, VideoEngine_removeRenderer)(JNIEnv* jni, jobject j_vie,
    472                                        jint channel) {
    473   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    474   return vie_data->render->RemoveRenderer(channel);
    475 }
    476 
    477 JOWW(jint, VideoEngine_registerExternalReceiveCodec)(JNIEnv* jni, jobject j_vie,
    478                                                      jint channel, jint pl_type,
    479                                                      jobject decoder,
    480                                                      bool internal_source) {
    481   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    482   return vie_data->RegisterExternalReceiveCodec(channel, pl_type, decoder,
    483                                                 true);
    484 }
    485 
    486 JOWW(jint,
    487      VideoEngine_deRegisterExternalReceiveCodec)(JNIEnv* jni, jobject j_vie,
    488                                                  jint channel, jint pl_type) {
    489   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    490   return vie_data->DeRegisterExternalReceiveCodec(channel, pl_type);
    491 }
    492 
    493 JOWW(jint, VideoEngine_startRender)(JNIEnv* jni, jobject j_vie, jint channel) {
    494   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    495   return vie_data->render->StartRender(channel);
    496 }
    497 
    498 JOWW(jint, VideoEngine_numberOfCaptureDevices)(JNIEnv* jni, jobject j_vie) {
    499   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    500   return vie_data->capture->NumberOfCaptureDevices();
    501 }
    502 
    503 JOWW(jobject,
    504      VideoEngine_getCaptureDevice(JNIEnv* jni, jobject j_vie, jint index)) {
    505   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    506   CameraDesc* camera_info = new CameraDesc();
    507   if (vie_data->capture->GetCaptureDevice(
    508           index, camera_info->name, sizeof(camera_info->name),
    509           camera_info->unique_id, sizeof(camera_info->unique_id)) != 0) {
    510     delete camera_info;
    511     return NULL;
    512   }
    513   jclass j_camera_class = GetClass("org/webrtc/webrtcdemo/CameraDesc");
    514   jmethodID j_camera_ctor = GetMethodID(jni, j_camera_class, "<init>", "(J)V");
    515   jobject j_camera = jni->NewObject(j_camera_class, j_camera_ctor,
    516                                     jlongFromPointer(camera_info));
    517   CHECK_EXCEPTION(jni, "error during NewObject");
    518   return j_camera;
    519 }
    520 
    521 JOWW(jint, VideoEngine_allocateCaptureDevice)(JNIEnv* jni, jobject j_vie,
    522                                               jobject j_camera) {
    523   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    524   CameraDesc* camera_info = GetCameraDesc(jni, j_camera);
    525   jint capture_id;
    526   if (vie_data->capture->AllocateCaptureDevice(camera_info->unique_id,
    527                                                sizeof(camera_info->unique_id),
    528                                                capture_id) != 0) {
    529     return -1;
    530   }
    531   return capture_id;
    532 }
    533 
    534 JOWW(jint, VideoEngine_connectCaptureDevice)(JNIEnv* jni, jobject j_vie,
    535                                              jint camera_num, jint channel) {
    536   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    537   return vie_data->capture->ConnectCaptureDevice(camera_num, channel);
    538 }
    539 
    540 JOWW(jint, VideoEngine_startCapture)(JNIEnv* jni, jobject j_vie,
    541                                      jint camera_num) {
    542   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    543   return vie_data->capture->StartCapture(camera_num);
    544 }
    545 
    546 JOWW(jint, VideoEngine_stopCapture)(JNIEnv* jni, jobject j_vie,
    547                                     jint camera_id) {
    548   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    549   return vie_data->capture->StopCapture(camera_id);
    550 }
    551 
    552 JOWW(jint, VideoEngine_releaseCaptureDevice)(JNIEnv* jni, jobject j_vie,
    553                                              jint camera_id) {
    554   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    555   return vie_data->capture->ReleaseCaptureDevice(camera_id);
    556 }
    557 
    558 JOWW(jint, VideoEngine_getOrientation)(JNIEnv* jni, jobject j_vie,
    559                                        jobject j_camera) {
    560   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    561   CameraDesc* camera_info = GetCameraDesc(jni, j_camera);
    562   webrtc::RotateCapturedFrame orientation;
    563   if (vie_data->capture->GetOrientation(camera_info->unique_id, orientation) !=
    564       0) {
    565     return -1;
    566   }
    567   return static_cast<jint>(orientation);
    568 }
    569 
    570 JOWW(jint, VideoEngine_setRotateCapturedFrames)(JNIEnv* jni, jobject j_vie,
    571                                                 jint capture_id, jint degrees) {
    572   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    573   return vie_data->capture->SetRotateCapturedFrames(
    574       capture_id, static_cast<webrtc::RotateCapturedFrame>(degrees));
    575 }
    576 
    577 JOWW(jint, VideoEngine_setNackStatus)(JNIEnv* jni, jobject j_vie, jint channel,
    578                                       jboolean enable) {
    579   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    580   return vie_data->rtp->SetNACKStatus(channel, enable);
    581 }
    582 
    583 JOWW(jint, VideoEngine_setKeyFrameRequestMethod)(JNIEnv* jni, jobject j_vie,
    584                                                  jint channel,
    585                                                  jint request_method) {
    586   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    587   return vie_data->rtp->SetKeyFrameRequestMethod(
    588       channel, static_cast<webrtc::ViEKeyFrameRequestMethod>(request_method));
    589 }
    590 
    591 JOWW(jobject, VideoEngine_getReceivedRtcpStatistics)(JNIEnv* jni, jobject j_vie,
    592                                                      jint channel) {
    593   unsigned short fraction_lost;  // NOLINT
    594   unsigned int cumulative_lost;  // NOLINT
    595   unsigned int extended_max;     // NOLINT
    596   unsigned int jitter;           // NOLINT
    597   int rtt_ms;
    598   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    599   if (vie_data->rtp->GetReceivedRTCPStatistics(channel, fraction_lost,
    600                                                cumulative_lost, extended_max,
    601                                                jitter, rtt_ms) != 0) {
    602     return NULL;
    603   }
    604   jclass j_rtcp_statistics_class =
    605       GetClass("org/webrtc/webrtcdemo/RtcpStatistics");
    606   jmethodID j_rtcp_statistics_ctor =
    607       GetMethodID(jni, j_rtcp_statistics_class, "<init>", "(IIIII)V");
    608   jobject j_rtcp_statistics =
    609       jni->NewObject(j_rtcp_statistics_class, j_rtcp_statistics_ctor,
    610                      fraction_lost, cumulative_lost, extended_max, jitter,
    611                      rtt_ms);
    612   CHECK_EXCEPTION(jni, "error during NewObject");
    613   return j_rtcp_statistics;
    614 }
    615 
    616 JOWW(jint, VideoEngine_registerObserver)(JNIEnv* jni, jobject j_vie,
    617                                          jint channel, jobject callback) {
    618   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    619   return vie_data->RegisterObserver(channel, callback);
    620 }
    621 
    622 JOWW(jint, VideoEngine_deregisterObserver)(JNIEnv* jni, jobject j_vie,
    623                                            jint channel) {
    624   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    625   return vie_data->DeregisterObserver(channel);
    626 }
    627 
    628 JOWW(jint, VideoEngine_setTraceFile)(JNIEnv* jni, jobject, jstring j_filename,
    629                                      jboolean file_counter) {
    630   std::string filename = JavaToStdString(jni, j_filename);
    631   return webrtc::VideoEngine::SetTraceFile(filename.c_str(), file_counter);
    632 }
    633 
    634 JOWW(jint, VideoEngine_nativeSetTraceFilter)(JNIEnv* jni, jobject,
    635                                              jint filter) {
    636   return webrtc::VideoEngine::SetTraceFilter(filter);
    637 }
    638 
    639 JOWW(jint, VideoEngine_startRtpDump)(JNIEnv* jni, jobject j_vie, jint channel,
    640                                      jstring j_filename, jint direction) {
    641   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    642   std::string filename = JavaToStdString(jni, j_filename);
    643   return vie_data->rtp->StartRTPDump(
    644       channel, filename.c_str(), static_cast<webrtc::RTPDirections>(direction));
    645 }
    646 
    647 JOWW(jint, VideoEngine_stopRtpDump)(JNIEnv* jni, jobject j_vie, jint channel,
    648                                     jint direction) {
    649   VideoEngineData* vie_data = GetVideoEngineData(jni, j_vie);
    650   return vie_data->rtp->StopRTPDump(
    651       channel, static_cast<webrtc::RTPDirections>(direction));
    652 }
    653 
    654 JOWW(void, VideoCodecInst_dispose)(JNIEnv* jni, jobject j_codec) {
    655   delete GetCodecInst(jni, j_codec);
    656 }
    657 
    658 JOWW(jint, VideoCodecInst_plType)(JNIEnv* jni, jobject j_codec) {
    659   return GetCodecInst(jni, j_codec)->plType;
    660 }
    661 
    662 JOWW(jstring, VideoCodecInst_name)(JNIEnv* jni, jobject j_codec) {
    663   return jni->NewStringUTF(GetCodecInst(jni, j_codec)->plName);
    664 }
    665 
    666 JOWW(jint, VideoCodecInst_width)(JNIEnv* jni, jobject j_codec) {
    667   return GetCodecInst(jni, j_codec)->width;
    668 }
    669 
    670 JOWW(void, VideoCodecInst_setWidth)(JNIEnv* jni, jobject j_codec, jint width) {
    671   GetCodecInst(jni, j_codec)->width = width;
    672 }
    673 
    674 JOWW(jint, VideoCodecInst_height)(JNIEnv* jni, jobject j_codec) {
    675   return GetCodecInst(jni, j_codec)->height;
    676 }
    677 
    678 JOWW(void, VideoCodecInst_setHeight)(JNIEnv* jni, jobject j_codec,
    679                                      jint height) {
    680   GetCodecInst(jni, j_codec)->height = height;
    681 }
    682 
    683 JOWW(jint, VideoCodecInst_startBitRate)(JNIEnv* jni, jobject j_codec) {
    684   return GetCodecInst(jni, j_codec)->startBitrate;
    685 }
    686 
    687 JOWW(void, VideoCodecInst_setStartBitRate)(JNIEnv* jni, jobject j_codec,
    688                                            jint bitrate) {
    689   GetCodecInst(jni, j_codec)->startBitrate = bitrate;
    690 }
    691 
    692 JOWW(jint, VideoCodecInst_maxBitRate)(JNIEnv* jni, jobject j_codec) {
    693   return GetCodecInst(jni, j_codec)->maxBitrate;
    694 }
    695 
    696 JOWW(void, VideoCodecInst_setMaxBitRate)(JNIEnv* jni, jobject j_codec,
    697                                          jint bitrate) {
    698   GetCodecInst(jni, j_codec)->maxBitrate = bitrate;
    699 }
    700 
    701 JOWW(jint, VideoCodecInst_maxFrameRate)(JNIEnv* jni, jobject j_codec) {
    702   return GetCodecInst(jni, j_codec)->maxFramerate;
    703 }
    704 
    705 JOWW(void, VideoCodecInst_setMaxFrameRate)(JNIEnv* jni, jobject j_codec,
    706                                            jint framerate) {
    707   GetCodecInst(jni, j_codec)->maxFramerate = framerate;
    708 }
    709 
    710 JOWW(void, CameraDesc_dispose)(JNIEnv* jni, jobject j_camera) {
    711   delete GetCameraDesc(jni, j_camera);
    712 }
    713