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