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 |