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 voice engine interfaces.
     12 // The native functions are found using jni's auto discovery.
     13 
     14 #include "webrtc/examples/android/media_demo/jni/voice_engine_jni.h"
     15 
     16 #include <map>
     17 #include <string>
     18 
     19 #include "webrtc/examples/android/media_demo/jni/jni_helpers.h"
     20 #include "webrtc/modules/utility/interface/helpers_android.h"
     21 #include "webrtc/test/channel_transport/include/channel_transport.h"
     22 #include "webrtc/voice_engine/include/voe_audio_processing.h"
     23 #include "webrtc/voice_engine/include/voe_base.h"
     24 #include "webrtc/voice_engine/include/voe_codec.h"
     25 #include "webrtc/voice_engine/include/voe_file.h"
     26 #include "webrtc/voice_engine/include/voe_hardware.h"
     27 #include "webrtc/voice_engine/include/voe_network.h"
     28 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
     29 #include "webrtc/voice_engine/include/voe_volume_control.h"
     30 
     31 // Macro for native functions that can be found by way of jni-auto discovery.
     32 // Note extern "C" is needed for "discovery" of native methods to work.
     33 #define JOWW(rettype, name)                                             \
     34   extern "C" rettype JNIEXPORT JNICALL Java_org_webrtc_webrtcdemo_##name
     35 
     36 namespace {
     37 
     38 static JavaVM* g_vm = NULL;
     39 static ClassReferenceHolder* g_class_reference_holder = NULL;
     40 
     41 jclass GetClass(JNIEnv* jni, const char* name) {
     42   CHECK(g_class_reference_holder, "Class reference holder NULL");
     43   return g_class_reference_holder->GetClass(name);
     44 }
     45 
     46 static const char* g_classes[] = {"org/webrtc/webrtcdemo/CodecInst"};
     47 
     48 template<typename T>
     49 void ReleaseSubApi(T instance) {
     50   CHECK(instance->Release() >= 0, "failed to release instance")
     51 }
     52 
     53 class VoiceEngineData {
     54  public:
     55   VoiceEngineData()
     56       : ve(webrtc::VoiceEngine::Create()),
     57         base(webrtc::VoEBase::GetInterface(ve)),
     58         codec(webrtc::VoECodec::GetInterface(ve)),
     59         file(webrtc::VoEFile::GetInterface(ve)),
     60         netw(webrtc::VoENetwork::GetInterface(ve)),
     61         apm(webrtc::VoEAudioProcessing::GetInterface(ve)),
     62         volume(webrtc::VoEVolumeControl::GetInterface(ve)),
     63         hardware(webrtc::VoEHardware::GetInterface(ve)),
     64         rtp(webrtc::VoERTP_RTCP::GetInterface(ve)) {
     65     CHECK(ve != NULL, "Voice engine instance failed to be created");
     66     CHECK(base != NULL, "Failed to acquire base interface");
     67     CHECK(codec != NULL, "Failed to acquire codec interface");
     68     CHECK(file != NULL, "Failed to acquire file interface");
     69     CHECK(netw != NULL, "Failed to acquire netw interface");
     70     CHECK(apm != NULL, "Failed to acquire apm interface");
     71     CHECK(volume != NULL, "Failed to acquire volume interface");
     72     CHECK(hardware != NULL, "Failed to acquire hardware interface");
     73     CHECK(rtp != NULL, "Failed to acquire rtp interface");
     74   }
     75 
     76   ~VoiceEngineData() {
     77     CHECK(channel_transports_.empty(),
     78           "VoE transports must be deleted before terminating");
     79     CHECK(base->Terminate() == 0, "VoE failed to terminate");
     80     ReleaseSubApi(base);
     81     ReleaseSubApi(codec);
     82     ReleaseSubApi(file);
     83     ReleaseSubApi(netw);
     84     ReleaseSubApi(apm);
     85     ReleaseSubApi(volume);
     86     ReleaseSubApi(hardware);
     87     ReleaseSubApi(rtp);
     88     webrtc::VoiceEngine* ve_instance = ve;
     89     CHECK(webrtc::VoiceEngine::Delete(ve_instance), "VoE failed to be deleted");
     90   }
     91 
     92   int CreateChannel() {
     93     int channel = base->CreateChannel();
     94     if (channel == -1) {
     95       return -1;
     96     }
     97     CreateTransport(channel);
     98     return channel;
     99   }
    100 
    101   int DeleteChannel(int channel) {
    102     if (base->DeleteChannel(channel) != 0) {
    103       return -1;
    104     }
    105     DeleteTransport(channel);
    106     return 0;
    107   }
    108 
    109   webrtc::test::VoiceChannelTransport* GetTransport(int channel) {
    110     ChannelTransports::iterator found = channel_transports_.find(channel);
    111     if (found == channel_transports_.end()) {
    112       return NULL;
    113     }
    114     return found->second;
    115   }
    116 
    117   webrtc::VoiceEngine* const ve;
    118   webrtc::VoEBase* const base;
    119   webrtc::VoECodec* const codec;
    120   webrtc::VoEFile* const file;
    121   webrtc::VoENetwork* const netw;
    122   webrtc::VoEAudioProcessing* const apm;
    123   webrtc::VoEVolumeControl* const volume;
    124   webrtc::VoEHardware* const hardware;
    125   webrtc::VoERTP_RTCP* const rtp;
    126 
    127  private:
    128   // Voice engine no longer provides a socket implementation. There is,
    129   // however, a socket implementation in webrtc::test.
    130   typedef std::map<int, webrtc::test::VoiceChannelTransport*>
    131   ChannelTransports;
    132 
    133   void CreateTransport(int channel) {
    134     CHECK(GetTransport(channel) == NULL,
    135           "Transport already created for VoE channel, inconsistent state");
    136     channel_transports_[channel] =
    137         new webrtc::test::VoiceChannelTransport(netw, channel);
    138   }
    139   void DeleteTransport(int channel) {
    140     CHECK(GetTransport(channel) != NULL,
    141           "VoE channel missing transport, inconsistent state");
    142     delete channel_transports_[channel];
    143     channel_transports_.erase(channel);
    144   }
    145 
    146   ChannelTransports channel_transports_;
    147 };
    148 
    149 webrtc::CodecInst* GetCodecInst(JNIEnv* jni, jobject j_codec) {
    150   jclass j_codec_class = jni->GetObjectClass(j_codec);
    151   jfieldID native_codec_id =
    152       jni->GetFieldID(j_codec_class, "nativeCodecInst", "J");
    153   jlong j_p = jni->GetLongField(j_codec, native_codec_id);
    154   return reinterpret_cast<webrtc::CodecInst*>(j_p);
    155 }
    156 
    157 }  // namespace
    158 
    159 namespace webrtc_examples {
    160 
    161 void SetVoeDeviceObjects(JavaVM* vm) {
    162   CHECK(vm, "Trying to register NULL vm");
    163   g_vm = vm;
    164   webrtc::AttachThreadScoped ats(g_vm);
    165   JNIEnv* jni = ats.env();
    166   g_class_reference_holder = new ClassReferenceHolder(
    167       jni, g_classes, ARRAYSIZE(g_classes));
    168 }
    169 
    170 void ClearVoeDeviceObjects() {
    171   CHECK(g_vm, "Clearing vm without it being set");
    172   {
    173     webrtc::AttachThreadScoped ats(g_vm);
    174     g_class_reference_holder->FreeReferences(ats.env());
    175   }
    176   g_vm = NULL;
    177   delete g_class_reference_holder;
    178   g_class_reference_holder = NULL;
    179 }
    180 
    181 }  // namespace webrtc_examples
    182 
    183 VoiceEngineData* GetVoiceEngineData(JNIEnv* jni, jobject j_voe) {
    184   jclass j_voe_class = jni->GetObjectClass(j_voe);
    185   jfieldID native_voe_id =
    186       jni->GetFieldID(j_voe_class, "nativeVoiceEngine", "J");
    187   jlong j_p = jni->GetLongField(j_voe, native_voe_id);
    188   return reinterpret_cast<VoiceEngineData*>(j_p);
    189 }
    190 
    191 webrtc::VoiceEngine* GetVoiceEngine(JNIEnv* jni, jobject j_voe) {
    192   return GetVoiceEngineData(jni, j_voe)->ve;
    193 }
    194 
    195 JOWW(jlong, VoiceEngine_create)(JNIEnv* jni, jclass) {
    196   VoiceEngineData* voe_data = new VoiceEngineData();
    197   return jlongFromPointer(voe_data);
    198 }
    199 
    200 JOWW(void, VoiceEngine_dispose)(JNIEnv* jni, jobject j_voe) {
    201   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    202   delete voe_data;
    203 }
    204 
    205 JOWW(jint, VoiceEngine_init)(JNIEnv* jni, jobject j_voe) {
    206   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    207   return voe_data->base->Init();
    208 }
    209 
    210 JOWW(jint, VoiceEngine_createChannel)(JNIEnv* jni, jobject j_voe) {
    211   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    212   return voe_data->CreateChannel();
    213 }
    214 
    215 JOWW(jint, VoiceEngine_deleteChannel)(JNIEnv* jni, jobject j_voe,
    216                                       jint channel) {
    217   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    218   return voe_data->DeleteChannel(channel);
    219 }
    220 
    221 JOWW(jint, VoiceEngine_setLocalReceiver)(JNIEnv* jni, jobject j_voe,
    222                                          jint channel, jint port) {
    223   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    224   webrtc::test::VoiceChannelTransport* transport =
    225       voe_data->GetTransport(channel);
    226   return transport->SetLocalReceiver(port);
    227 }
    228 
    229 JOWW(jint, VoiceEngine_setSendDestination)(JNIEnv* jni, jobject j_voe,
    230                                            jint channel, jint port,
    231                                            jstring j_addr) {
    232   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    233   std::string addr = JavaToStdString(jni, j_addr);
    234   webrtc::test::VoiceChannelTransport* transport =
    235       voe_data->GetTransport(channel);
    236   return transport->SetSendDestination(addr.c_str(), port);
    237 }
    238 
    239 JOWW(jint, VoiceEngine_startListen)(JNIEnv* jni, jobject j_voe, jint channel) {
    240   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    241   return voe_data->base->StartReceive(channel);
    242 }
    243 
    244 JOWW(jint, VoiceEngine_startPlayout)(JNIEnv* jni, jobject j_voe, jint channel) {
    245   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    246   return voe_data->base->StartPlayout(channel);
    247 }
    248 
    249 JOWW(jint, VoiceEngine_startSend)(JNIEnv* jni, jobject j_voe, jint channel) {
    250   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    251   return voe_data->base->StartSend(channel);
    252 }
    253 
    254 JOWW(jint, VoiceEngine_stopListen)(JNIEnv* jni, jobject j_voe, jint channel) {
    255   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    256   return voe_data->base->StartReceive(channel);
    257 }
    258 
    259 JOWW(jint, VoiceEngine_stopPlayout)(JNIEnv* jni, jobject j_voe, jint channel) {
    260   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    261   return voe_data->base->StopPlayout(channel);
    262 }
    263 
    264 JOWW(jint, VoiceEngine_stopSend)(JNIEnv* jni, jobject j_voe, jint channel) {
    265   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    266   return voe_data->base->StopSend(channel);
    267 }
    268 
    269 JOWW(jint, VoiceEngine_setSpeakerVolume)(JNIEnv* jni, jobject j_voe,
    270                                          jint level) {
    271   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    272   return voe_data->volume->SetSpeakerVolume(level);
    273 }
    274 
    275 JOWW(jint, VoiceEngine_setLoudspeakerStatus)(JNIEnv* jni, jobject j_voe,
    276                                              jboolean enable) {
    277   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    278   return voe_data->hardware->SetLoudspeakerStatus(enable);
    279 }
    280 
    281 JOWW(jint, VoiceEngine_startPlayingFileLocally)(JNIEnv* jni, jobject j_voe,
    282                                                 jint channel,
    283                                                 jstring j_filename,
    284                                                 jboolean loop) {
    285   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    286   std::string filename = JavaToStdString(jni, j_filename);
    287   return voe_data->file->StartPlayingFileLocally(channel,
    288                                                  filename.c_str(),
    289                                                  loop);
    290 }
    291 
    292 JOWW(jint, VoiceEngine_stopPlayingFileLocally)(JNIEnv* jni, jobject j_voe,
    293                                                jint channel) {
    294   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    295   return voe_data->file->StopPlayingFileLocally(channel);
    296 }
    297 
    298 JOWW(jint, VoiceEngine_startPlayingFileAsMicrophone)(JNIEnv* jni, jobject j_voe,
    299                                                      jint channel,
    300                                                      jstring j_filename,
    301                                                      jboolean loop) {
    302   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    303   std::string filename = JavaToStdString(jni, j_filename);
    304   return voe_data->file->StartPlayingFileAsMicrophone(channel,
    305                                                       filename.c_str(),
    306                                                       loop);
    307 }
    308 
    309 JOWW(jint, VoiceEngine_stopPlayingFileAsMicrophone)(JNIEnv* jni, jobject j_voe,
    310                                                     jint channel) {
    311   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    312   return voe_data->file->StopPlayingFileAsMicrophone(channel);
    313 }
    314 
    315 JOWW(jint, VoiceEngine_numOfCodecs)(JNIEnv* jni, jobject j_voe) {
    316   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    317   return voe_data->codec->NumOfCodecs();
    318 }
    319 
    320 JOWW(jobject, VoiceEngine_getCodec)(JNIEnv* jni, jobject j_voe, jint index) {
    321   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    322   webrtc::CodecInst* codec = new webrtc::CodecInst();
    323   CHECK(voe_data->codec->GetCodec(index, *codec) == 0,
    324         "getCodec must be called with valid index");
    325   jclass j_codec_class = GetClass(jni, "org/webrtc/webrtcdemo/CodecInst");
    326   jmethodID j_codec_ctor = GetMethodID(jni, j_codec_class, "<init>", "(J)V");
    327   jobject j_codec =
    328       jni->NewObject(j_codec_class, j_codec_ctor, jlongFromPointer(codec));
    329   CHECK_EXCEPTION(jni, "error during NewObject");
    330   return j_codec;
    331 }
    332 
    333 JOWW(jint, VoiceEngine_setSendCodec)(JNIEnv* jni, jobject j_voe, jint channel,
    334                                      jobject j_codec) {
    335   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    336   webrtc::CodecInst* inst = GetCodecInst(jni, j_codec);
    337   return voe_data->codec->SetSendCodec(channel, *inst);
    338 }
    339 
    340 JOWW(jint, VoiceEngine_setEcStatus)(JNIEnv* jni, jobject j_voe, jboolean enable,
    341                                     jint ec_mode) {
    342   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    343   return voe_data->apm->SetEcStatus(enable,
    344                                     static_cast<webrtc::EcModes>(ec_mode));
    345 }
    346 
    347 JOWW(jint, VoiceEngine_setAecmMode)(JNIEnv* jni, jobject j_voe, jint aecm_mode,
    348                                     jboolean cng) {
    349   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    350   return voe_data->apm->SetAecmMode(static_cast<webrtc::AecmModes>(aecm_mode),
    351                                     cng);
    352 }
    353 
    354 JOWW(jint, VoiceEngine_setAgcStatus)(JNIEnv* jni, jobject j_voe,
    355                                      jboolean enable, jint agc_mode) {
    356   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    357   return voe_data->apm->SetAgcStatus(enable,
    358                                      static_cast<webrtc::AgcModes>(agc_mode));
    359 }
    360 
    361 // Returns the native AgcConfig object associated with the Java object
    362 // |j_codec|.
    363 void GetNativeAgcConfig(JNIEnv* jni, jobject j_codec,
    364                         webrtc::AgcConfig* agc_config) {
    365   jclass j_codec_class = jni->GetObjectClass(j_codec);
    366   jfieldID dBOv_id = jni->GetFieldID(j_codec_class, "targetLevelDbOv", "I");
    367   agc_config->targetLeveldBOv = jni->GetIntField(j_codec, dBOv_id);
    368   jfieldID gain_id =
    369       jni->GetFieldID(j_codec_class, "digitalCompressionGaindB", "I");
    370   agc_config->digitalCompressionGaindB = jni->GetIntField(j_codec, gain_id);
    371   jfieldID limiter_id = jni->GetFieldID(j_codec_class, "limiterEnable", "Z");
    372   agc_config->limiterEnable = jni->GetBooleanField(j_codec, limiter_id);
    373 }
    374 
    375 JOWW(jint, VoiceEngine_setAgcConfig)(JNIEnv* jni, jobject j_voe,
    376                                      jobject j_config) {
    377   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    378   webrtc::AgcConfig config;
    379   GetNativeAgcConfig(jni, j_config, &config);
    380   return voe_data->apm->SetAgcConfig(config);
    381 }
    382 
    383 JOWW(jint, VoiceEngine_setNsStatus)(JNIEnv* jni, jobject j_voe, jboolean enable,
    384                                     jint ns_mode) {
    385   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    386   return voe_data->apm->SetNsStatus(enable,
    387                                     static_cast<webrtc::NsModes>(ns_mode));
    388 }
    389 
    390 JOWW(jint, VoiceEngine_startDebugRecording)(JNIEnv* jni, jobject j_voe,
    391                                             jstring j_filename) {
    392   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    393   std::string filename = JavaToStdString(jni, j_filename);
    394   return voe_data->apm->StartDebugRecording(filename.c_str());
    395 }
    396 
    397 JOWW(jint, VoiceEngine_stopDebugRecording)(JNIEnv* jni, jobject j_voe) {
    398   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    399   return voe_data->apm->StopDebugRecording();
    400 }
    401 
    402 JOWW(jint, VoiceEngine_startRtpDump)(JNIEnv* jni, jobject j_voe, jint channel,
    403                                      jstring j_filename, jint direction) {
    404   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    405   std::string filename = JavaToStdString(jni, j_filename);
    406   return voe_data->rtp->StartRTPDump(
    407       channel, filename.c_str(),
    408       static_cast<webrtc::RTPDirections>(direction));
    409 }
    410 
    411 JOWW(jint, VoiceEngine_stopRtpDump)(JNIEnv* jni, jobject j_voe, jint channel,
    412                                     jint direction) {
    413   VoiceEngineData* voe_data = GetVoiceEngineData(jni, j_voe);
    414   return voe_data->rtp->StopRTPDump(
    415       channel, static_cast<webrtc::RTPDirections>(direction));
    416 }
    417 
    418 JOWW(void, CodecInst_dispose)(JNIEnv* jni, jobject j_codec) {
    419   delete GetCodecInst(jni, j_codec);
    420 }
    421 
    422 JOWW(jint, CodecInst_plType)(JNIEnv* jni, jobject j_codec) {
    423   return GetCodecInst(jni, j_codec)->pltype;
    424 }
    425 
    426 JOWW(jstring, CodecInst_name)(JNIEnv* jni, jobject j_codec) {
    427   return jni->NewStringUTF(GetCodecInst(jni, j_codec)->plname);
    428 }
    429 
    430 JOWW(jint, CodecInst_plFrequency)(JNIEnv* jni, jobject j_codec) {
    431   return GetCodecInst(jni, j_codec)->plfreq;
    432 }
    433 
    434 JOWW(jint, CodecInst_pacSize)(JNIEnv* jni, jobject j_codec) {
    435   return GetCodecInst(jni, j_codec)->pacsize;
    436 }
    437 
    438 JOWW(jint, CodecInst_channels)(JNIEnv* jni, jobject j_codec) {
    439   return GetCodecInst(jni, j_codec)->channels;
    440 }
    441 
    442 JOWW(jint, CodecInst_rate)(JNIEnv* jni, jobject j_codec) {
    443   return GetCodecInst(jni, j_codec)->rate;
    444 }
    445