1/*
2 *  Copyright (c) 2011 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#include <android/log.h>
12#include <stdio.h>
13#include <string.h>
14#include <unistd.h>
15
16#include "webrtc/voice_engine/test/android/android_test/jni/org_webrtc_voiceengine_test_AndroidTest.h"
17
18#include "webrtc/system_wrappers/interface/thread_wrapper.h"
19
20#include "webrtc/voice_engine/include/voe_audio_processing.h"
21#include "webrtc/voice_engine/include/voe_base.h"
22#include "webrtc/voice_engine/include/voe_codec.h"
23#include "webrtc/voice_engine/include/voe_file.h"
24#include "webrtc/voice_engine/include/voe_hardware.h"
25#include "webrtc/voice_engine/include/voe_network.h"
26#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
27#include "webrtc/voice_engine/include/voe_volume_control.h"
28
29#include "webrtc/voice_engine/test/auto_test/voe_test_interface.h"
30
31//#define INIT_FROM_THREAD
32//#define START_CALL_FROM_THREAD
33
34#define WEBRTC_LOG_TAG "*WEBRTCN*" // As in WEBRTC Native...
35#define VALIDATE_BASE_POINTER \
36    if (!veData1.base) \
37    { \
38        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
39                            "Base pointer doesn't exist"); \
40        return -1; \
41    }
42#define VALIDATE_CODEC_POINTER \
43    if (!veData1.codec) \
44    { \
45        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
46                            "Codec pointer doesn't exist"); \
47        return -1; \
48    }
49#define VALIDATE_FILE_POINTER \
50    if (!veData1.file) \
51    { \
52        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
53                            "File pointer doesn't exist"); \
54        return -1; \
55    }
56#define VALIDATE_NETWORK_POINTER \
57    if (!veData1.netw) \
58    { \
59        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
60                            "Network pointer doesn't exist"); \
61        return -1; \
62    }
63#define VALIDATE_APM_POINTER \
64    if (!veData1.codec) \
65    { \
66        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
67                            "Apm pointer doesn't exist"); \
68        return -1; \
69    }
70#define VALIDATE_VOLUME_POINTER \
71    if (!veData1.volume) \
72    { \
73        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
74                            "Volume pointer doesn't exist"); \
75        return -1; \
76    }
77#define VALIDATE_HARDWARE_POINTER \
78    if (!veData1.hardware) \
79    { \
80        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
81                            "Hardware pointer doesn't exist"); \
82        return -1; \
83    }
84#define VALIDATE_RTP_RTCP_POINTER \
85    if (!veData1.rtp_rtcp) \
86    { \
87        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, \
88                            "RTP / RTCP pointer doesn't exist"); \
89        return -1; \
90    }
91
92// Register functions in JNI_OnLoad()
93// How do we ensure that VoE is deleted? JNI_OnUnload?
94// What happens if class is unloaded? When loaded again, NativeInit will be
95// called again. Keep what we have?
96// Should we do something in JNI_OnUnload?
97// General design: create a class or keep global struct with "C" functions?
98// Otherwise make sure symbols are as unique as possible.
99
100// TestType enumerator
101enum TestType
102{
103  Invalid = -1,
104  Standard = 0,
105  Extended = 1,
106  Stress   = 2,
107  Unit     = 3,
108  CPU      = 4
109};
110
111using namespace webrtc;
112
113class my_transportation;
114
115// VoiceEngine data struct
116typedef struct
117{
118    // VoiceEngine
119    VoiceEngine* ve;
120    // Sub-APIs
121    VoEBase* base;
122    VoECodec* codec;
123    VoEFile* file;
124    VoENetwork* netw;
125    VoEAudioProcessing* apm;
126    VoEVolumeControl* volume;
127    VoEHardware* hardware;
128    VoERTP_RTCP* rtp_rtcp;
129    // Other
130    my_transportation* extTrans;
131    JavaVM* jvm;
132} VoiceEngineData;
133
134// my_transportation is used when useExtTrans is enabled
135class my_transportation : public Transport
136{
137 public:
138  my_transportation(VoENetwork * network) :
139      netw(network) {
140  }
141
142  int SendPacket(int channel,const void *data,int len);
143  int SendRTCPPacket(int channel, const void *data, int len);
144 private:
145  VoENetwork * netw;
146};
147
148int my_transportation::SendPacket(int channel,const void *data,int len)
149{
150  netw->ReceivedRTPPacket(channel, data, len);
151  return len;
152}
153
154int my_transportation::SendRTCPPacket(int channel, const void *data, int len)
155{
156  netw->ReceivedRTCPPacket(channel, data, len);
157  return len;
158}
159
160//Global variables visible in this file
161static VoiceEngineData veData1;
162static VoiceEngineData veData2;
163
164// "Local" functions (i.e. not Java accessible)
165static bool GetSubApis(VoiceEngineData &veData);
166static bool ReleaseSubApis(VoiceEngineData &veData);
167
168class ThreadTest
169{
170public:
171    ThreadTest();
172    ~ThreadTest();
173    int RunTest();
174    int CloseTest();
175private:
176    static bool Run(void* ptr);
177    bool Process();
178private:
179    ThreadWrapper* _thread;
180};
181
182ThreadTest::~ThreadTest()
183{
184    if (_thread)
185    {
186        _thread->SetNotAlive();
187        if (_thread->Stop())
188        {
189            delete _thread;
190            _thread = NULL;
191        }
192    }
193}
194
195ThreadTest::ThreadTest() :
196    _thread(NULL)
197{
198    _thread = ThreadWrapper::CreateThread(Run, this, kNormalPriority,
199                                          "ThreadTest thread");
200}
201
202bool ThreadTest::Run(void* ptr)
203{
204    return static_cast<ThreadTest*> (ptr)->Process();
205}
206
207bool ThreadTest::Process()
208{
209    // Attach this thread to JVM
210    /*JNIEnv* env = NULL;
211     jint res = veData1.jvm->AttachCurrentThread(&env, NULL);
212     char msg[32];
213     sprintf(msg, "res=%d, env=%d", res, env);
214     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG, msg);*/
215
216#ifdef INIT_FROM_THREAD
217    VALIDATE_BASE_POINTER;
218    veData1.base->Init();
219#endif
220
221#ifdef START_CALL_FROM_THREAD
222    // receiving instance
223    veData2.ve = VoiceEngine::Create();
224    GetSubApis(veData2);
225    veData2.base->Init();
226    veData2.base->CreateChannel();
227    if(veData2.base->SetLocalReceiver(0, 1234) < 0)
228    {
229        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
230                "set local receiver 2 failed");
231    }
232    veData2.hardware->SetLoudspeakerStatus(false);
233    veData2.volume->SetSpeakerVolume(204);
234    veData2.base->StartReceive(0);
235    if(veData2.base->StartPlayout(0) < 0)
236    {
237        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
238                "start playout failed");
239    }
240
241    __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
242            "receiving instance started from thread");
243
244    // sending instance
245    veData1.ve = VoiceEngine::Create();
246    GetSubApis(veData1);
247    veData1.base->Init();
248    if(veData1.base->CreateChannel() < 0)
249    {
250        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
251                "create channel failed");
252    }
253    if(veData1.base->SetLocalReceiver(0, 1256) < 0)
254    {
255        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
256                "set local receiver failed");
257    }
258    if(veData1.base->SetSendDestination(0, 1234, "127.0.0.1") < 0)
259    {
260        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
261                "set send destination failed");
262    }
263    if(veData1.base->StartSend(0) < 0)
264    {
265        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
266                "start send failed");
267    }
268
269    __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
270            "sending instance started from thread");
271#endif
272
273    _thread->SetNotAlive();
274    _thread->Stop();
275
276    //res = veData1.jvm->DetachCurrentThread();
277
278    return true;
279}
280
281int ThreadTest::RunTest()
282{
283    if (_thread)
284    {
285        unsigned int id;
286        _thread->Start(id);
287    }
288    return 0;
289}
290
291int ThreadTest::CloseTest()
292{
293    VALIDATE_BASE_POINTER
294
295    veData1.base->DeleteChannel(0);
296    veData2.base->DeleteChannel(0);
297    veData1.base->Terminate();
298    veData2.base->Terminate();
299
300    // Release sub-APIs
301    ReleaseSubApis(veData1);
302    ReleaseSubApis(veData2);
303
304    // Delete
305    VoiceEngine::Delete(veData1.ve);
306    VoiceEngine::Delete(veData2.ve);
307    veData2.ve = NULL;
308    veData2.ve = NULL;
309
310    return 0;
311}
312
313ThreadTest threadTest;
314
315//////////////////////////////////////////////////////////////////
316// General functions
317//////////////////////////////////////////////////////////////////
318
319/////////////////////////////////////////////
320// JNI_OnLoad
321//
322jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
323{
324    if (!vm)
325    {
326        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
327                            "JNI_OnLoad did not receive a valid VM pointer");
328        return -1;
329    }
330
331    // Get JNI
332    JNIEnv* env;
333    if (JNI_OK != vm->GetEnv(reinterpret_cast<void**> (&env),
334                             JNI_VERSION_1_4))
335    {
336        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
337                            "JNI_OnLoad could not get JNI env");
338        return -1;
339    }
340
341    // Get class to register the native functions with
342    // jclass regClass = env->FindClass("webrtc/android/AndroidTest");
343    // if (!regClass) {
344    // return -1; // Exception thrown
345    // }
346
347    // Register native functions
348    // JNINativeMethod methods[1];
349    // methods[0].name = NULL;
350    // methods[0].signature = NULL;
351    // methods[0].fnPtr = NULL;
352    // if (JNI_OK != env->RegisterNatives(regClass, methods, 1))
353    // {
354    // return -1;
355    // }
356
357    // Init VoiceEngine data
358    memset(&veData1, 0, sizeof(veData1));
359    memset(&veData2, 0, sizeof(veData2));
360
361    // Store the JVM
362    veData1.jvm = vm;
363    veData2.jvm = vm;
364
365    return JNI_VERSION_1_4;
366}
367
368/////////////////////////////////////////////
369// Native initialization
370//
371JNIEXPORT jboolean JNICALL
372Java_org_webrtc_voiceengine_test_AndroidTest_NativeInit(
373        JNIEnv * env,
374        jclass)
375{
376    // Look up and cache any interesting class, field and method IDs for
377    // any used java class here
378
379    return true;
380}
381
382/////////////////////////////////////////////
383// Run auto standard test
384//
385JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_RunAutoTest(
386        JNIEnv *env,
387        jobject context,
388        jint testType,
389        jint extendedSel)
390{
391    TestType tType(Invalid);
392
393    switch (testType)
394    {
395        case 0:
396            return 0;
397        case 1:
398            tType = Standard;
399            break;
400        case 2:
401            tType = Extended;
402            break;
403        case 3:
404            tType = Stress;
405            break;
406        case 4:
407            tType = Unit;
408            break;
409        default:
410            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
411                                "RunAutoTest - Invalid TestType");
412            return -1;
413    }
414
415    // Set instance independent Java objects
416    VoiceEngine::SetAndroidObjects(veData1.jvm, env, context);
417
418    // Call voe test interface function
419    // TODO(leozwang) add autotest setAndroidObjects(veData1.jvm, context);
420    // jint retVal = runAutoTest(tType);
421
422    // Clear instance independent Java objects
423    VoiceEngine::SetAndroidObjects(NULL, NULL, NULL);
424
425    return 0;
426}
427
428//////////////////////////////////////////////////////////////////
429// VoiceEngine API wrapper functions
430//////////////////////////////////////////////////////////////////
431
432/////////////////////////////////////////////
433// Create VoiceEngine instance
434//
435JNIEXPORT jboolean JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_Create(
436        JNIEnv *env,
437        jobject context)
438{
439    // Check if already created
440    if (veData1.ve)
441    {
442        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
443                            "VoE already created");
444        return false;
445    }
446
447    // Set instance independent Java objects
448    VoiceEngine::SetAndroidObjects(veData1.jvm, env, context);
449
450#ifdef START_CALL_FROM_THREAD
451    threadTest.RunTest();
452#else
453    // Create
454    veData1.ve = VoiceEngine::Create();
455    if (!veData1.ve)
456    {
457        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
458                            "Create VoE failed");
459        return false;
460    }
461
462    // Get sub-APIs
463    if (!GetSubApis(veData1))
464    {
465        // If not OK, release all sub-APIs and delete VoE
466        ReleaseSubApis(veData1);
467        if (!VoiceEngine::Delete(veData1.ve))
468        {
469            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
470                                "Delete VoE failed");
471        }
472        return false;
473    }
474#endif
475
476    return true;
477}
478
479/////////////////////////////////////////////
480// Delete VoiceEngine instance
481//
482JNIEXPORT jboolean JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_Delete(
483        JNIEnv *,
484        jobject)
485{
486#ifdef START_CALL_FROM_THREAD
487    threadTest.CloseTest();
488#else
489    // Check if exists
490    if (!veData1.ve)
491    {
492        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
493                            "VoE does not exist");
494        return false;
495    }
496
497    // Release sub-APIs
498    ReleaseSubApis(veData1);
499
500    // Delete
501    if (!VoiceEngine::Delete(veData1.ve))
502    {
503        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
504                            "Delete VoE failed");
505        return false;
506    }
507
508    veData1.ve = NULL;
509#endif
510
511    // Clear instance independent Java objects
512    VoiceEngine::SetAndroidObjects(NULL, NULL, NULL);
513
514    return true;
515}
516
517/////////////////////////////////////////////
518// [Base] Initialize VoiceEngine
519//
520JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_Init(
521        JNIEnv *,
522        jobject,
523        jboolean enableTrace,
524        jboolean useExtTrans)
525{
526    VALIDATE_BASE_POINTER;
527
528    if (enableTrace)
529    {
530        if (0 != VoiceEngine::SetTraceFile("/sdcard/trace.txt"))
531        {
532            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
533                                "Could not enable trace");
534        }
535        if (0 != VoiceEngine::SetTraceFilter(kTraceAll))
536        {
537            __android_log_write(ANDROID_LOG_WARN, WEBRTC_LOG_TAG,
538                                "Could not set trace filter");
539        }
540    }
541
542    if (useExtTrans)
543    {
544        VALIDATE_NETWORK_POINTER;
545        veData1.extTrans = new my_transportation(veData1.netw);
546    }
547
548    int retVal = 0;
549#ifdef INIT_FROM_THREAD
550    threadTest.RunTest();
551    usleep(200000);
552#else
553    retVal = veData1.base->Init();
554#endif
555    return retVal;
556}
557
558/////////////////////////////////////////////
559// [Base] Terminate VoiceEngine
560//
561JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_Terminate(
562        JNIEnv *,
563        jobject)
564{
565    VALIDATE_BASE_POINTER;
566
567    jint retVal = veData1.base->Terminate();
568
569    delete veData1.extTrans;
570    veData1.extTrans = NULL;
571
572    return retVal;
573}
574
575/////////////////////////////////////////////
576// [Base] Create channel
577//
578JNIEXPORT jint JNICALL
579Java_org_webrtc_voiceengine_test_AndroidTest_CreateChannel(
580        JNIEnv *,
581        jobject)
582{
583    VALIDATE_BASE_POINTER;
584    jint channel = veData1.base->CreateChannel();
585
586    if (veData1.extTrans)
587    {
588        VALIDATE_NETWORK_POINTER;
589        __android_log_print(ANDROID_LOG_DEBUG, WEBRTC_LOG_TAG,
590                            "Enabling external transport on channel %d",
591                            channel);
592        if (veData1.netw->RegisterExternalTransport(channel, *veData1.extTrans)
593                < 0)
594        {
595            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
596                                "Could not set external transport");
597            return -1;
598        }
599    }
600
601    return channel;
602}
603
604/////////////////////////////////////////////
605// [Base] Delete channel
606//
607JNIEXPORT jint JNICALL
608Java_org_webrtc_voiceengine_test_AndroidTest_DeleteChannel(
609        JNIEnv *,
610        jobject,
611        jint channel)
612{
613    VALIDATE_BASE_POINTER;
614    return veData1.base->DeleteChannel(channel);
615}
616
617/////////////////////////////////////////////
618// [Base] SetLocalReceiver
619JNIEXPORT jint JNICALL
620Java_org_webrtc_voiceengine_test_AndroidTest_SetLocalReceiver(
621        JNIEnv *,
622        jobject,
623        jint channel,
624        jint port)
625{
626    VALIDATE_BASE_POINTER;
627    return veData1.base->SetLocalReceiver(channel, port);
628}
629
630/////////////////////////////////////////////
631// [Base] SetSendDestination
632//
633JNIEXPORT jint JNICALL
634Java_org_webrtc_voiceengine_test_AndroidTest_SetSendDestination(
635        JNIEnv *env,
636        jobject,
637        jint channel,
638        jint port,
639        jstring ipaddr)
640{
641    VALIDATE_BASE_POINTER;
642
643    const char* ipaddrNative = env->GetStringUTFChars(ipaddr, NULL);
644    if (!ipaddrNative)
645    {
646        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
647                            "Could not get UTF string");
648        return -1;
649    }
650
651    jint retVal = veData1.base->SetSendDestination(channel, port, ipaddrNative);
652
653    env->ReleaseStringUTFChars(ipaddr, ipaddrNative);
654
655    return retVal;
656}
657
658/////////////////////////////////////////////
659// [Base] StartListen
660//
661JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_StartListen(
662        JNIEnv *,
663        jobject,
664        jint channel)
665{
666    VALIDATE_BASE_POINTER;
667    int retVal = veData1.base->StartReceive(channel);
668
669    return retVal;
670}
671
672/////////////////////////////////////////////
673// [Base] Start playout
674//
675JNIEXPORT jint JNICALL
676Java_org_webrtc_voiceengine_test_AndroidTest_StartPlayout(
677        JNIEnv *,
678        jobject,
679        jint channel)
680{
681    VALIDATE_BASE_POINTER;
682    int retVal = veData1.base->StartPlayout(channel);
683
684    return retVal;
685}
686
687/////////////////////////////////////////////
688// [Base] Start send
689//
690JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_StartSend(
691        JNIEnv *,
692        jobject,
693        jint channel)
694{
695    /*    int dscp(0), serviceType(-1), overrideDscp(0), res(0);
696     bool gqosEnabled(false), useSetSockOpt(false);
697
698     if (veData1.netw->SetSendTOS(channel, 13, useSetSockOpt) != 0)
699     {
700     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
701         "Failed to set TOS");
702     return -1;
703     }
704
705     res = veData1.netw->GetSendTOS(channel, dscp, useSetSockOpt);
706     if (res != 0 || dscp != 13 || useSetSockOpt != true)
707     {
708     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
709         "Failed to get TOS");
710     return -1;
711     } */
712
713    /* if (veData1.rtp_rtcp->SetREDStatus(channel, 1) != 0)
714     {
715     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
716         "Failed to enable RED");
717     return -1;
718     } */
719
720    VALIDATE_BASE_POINTER;
721    int retVal = veData1.base->StartSend(channel);
722
723    return retVal;
724}
725
726/////////////////////////////////////////////
727// [Base] Stop listen
728//
729JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_StopListen(
730        JNIEnv *,
731        jobject,
732        jint channel)
733{
734    VALIDATE_BASE_POINTER;
735    return veData1.base->StopReceive(channel);
736}
737
738/////////////////////////////////////////////
739// [Base] Stop playout
740//
741JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_StopPlayout(
742        JNIEnv *,
743        jobject,
744        jint channel)
745{
746    VALIDATE_BASE_POINTER;
747    return veData1.base->StopPlayout(channel);
748}
749
750/////////////////////////////////////////////
751// [Base] Stop send
752//
753JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_StopSend(
754        JNIEnv *,
755        jobject,
756        jint channel)
757{
758    /* if (veData1.rtp_rtcp->SetREDStatus(channel, 0) != 0)
759     {
760     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
761         "Failed to disable RED");
762     return -1;
763     } */
764
765    VALIDATE_BASE_POINTER;
766    return veData1.base->StopSend(channel);
767}
768
769/////////////////////////////////////////////
770// [codec] Number of codecs
771//
772JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_NumOfCodecs(
773        JNIEnv *,
774        jobject)
775{
776    VALIDATE_CODEC_POINTER;
777    return veData1.codec->NumOfCodecs();
778}
779
780/////////////////////////////////////////////
781// [codec] Set send codec
782//
783JNIEXPORT jint JNICALL
784Java_org_webrtc_voiceengine_test_AndroidTest_SetSendCodec(
785        JNIEnv *,
786        jobject,
787        jint channel,
788        jint index)
789{
790    VALIDATE_CODEC_POINTER;
791
792    CodecInst codec;
793
794    if (veData1.codec->GetCodec(index, codec) != 0)
795    {
796        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
797                            "Failed to get codec");
798        return -1;
799    }
800
801    return veData1.codec->SetSendCodec(channel, codec);
802}
803
804/////////////////////////////////////////////
805// [codec] Set VAD status
806//
807JNIEXPORT jint JNICALL
808Java_org_webrtc_voiceengine_test_AndroidTest_SetVADStatus(
809        JNIEnv *,
810        jobject,
811        jint channel,
812        jboolean enable,
813        jint mode)
814{
815    VALIDATE_CODEC_POINTER;
816
817    VadModes VADmode = kVadConventional;
818
819    switch (mode)
820    {
821        case 0:
822            break; // already set
823        case 1:
824            VADmode = kVadAggressiveLow;
825            break;
826        case 2:
827            VADmode = kVadAggressiveMid;
828            break;
829        case 3:
830            VADmode = kVadAggressiveHigh;
831            break;
832        default:
833            VADmode = (VadModes) 17; // force error
834            break;
835    }
836
837    return veData1.codec->SetVADStatus(channel, enable, VADmode);
838}
839
840/////////////////////////////////////////////
841// [apm] SetNSStatus
842//
843JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_SetNSStatus(
844        JNIEnv *,
845        jobject,
846        jboolean enable,
847        jint mode)
848{
849    VALIDATE_APM_POINTER;
850
851    NsModes NSmode = kNsDefault;
852
853    switch (mode)
854    {
855        case 0:
856            NSmode = kNsUnchanged;
857            break;
858        case 1:
859            break; // already set
860        case 2:
861            NSmode = kNsConference;
862            break;
863        case 3:
864            NSmode = kNsLowSuppression;
865            break;
866        case 4:
867            NSmode = kNsModerateSuppression;
868            break;
869        case 5:
870            NSmode = kNsHighSuppression;
871            break;
872        case 6:
873            NSmode = kNsVeryHighSuppression;
874            break;
875        default:
876            NSmode = (NsModes) 17; // force error
877            break;
878    }
879
880    return veData1.apm->SetNsStatus(enable, NSmode);
881}
882
883/////////////////////////////////////////////
884// [apm] SetAGCStatus
885//
886JNIEXPORT jint JNICALL
887Java_org_webrtc_voiceengine_test_AndroidTest_SetAGCStatus(
888        JNIEnv *,
889        jobject,
890        jboolean enable,
891        jint mode)
892{
893    VALIDATE_APM_POINTER;
894
895    AgcModes AGCmode = kAgcDefault;
896
897    switch (mode)
898    {
899        case 0:
900            AGCmode = kAgcUnchanged;
901            break;
902        case 1:
903            break; // already set
904        case 2:
905            AGCmode = kAgcAdaptiveAnalog;
906            break;
907        case 3:
908            AGCmode = kAgcAdaptiveDigital;
909            break;
910        case 4:
911            AGCmode = kAgcFixedDigital;
912            break;
913        default:
914            AGCmode = (AgcModes) 17; // force error
915            break;
916    }
917
918    /* AgcConfig agcConfig;
919     agcConfig.targetLeveldBOv = 3;
920     agcConfig.digitalCompressionGaindB = 50;
921     agcConfig.limiterEnable = 0;
922
923     if (veData1.apm->SetAGCConfig(agcConfig) != 0)
924     {
925     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
926         "Failed to set AGC config");
927     return -1;
928     } */
929
930    return veData1.apm->SetAgcStatus(enable, AGCmode);
931}
932
933/////////////////////////////////////////////
934// [apm] SetECStatus
935//
936JNIEXPORT jint JNICALL Java_org_webrtc_voiceengine_test_AndroidTest_SetECStatus(
937        JNIEnv *,
938        jobject,
939        jboolean enable,
940        jint mode)
941{
942    VALIDATE_APM_POINTER;
943
944    EcModes ECmode = kEcDefault;
945
946    switch (mode)
947    {
948        case 0:
949            ECmode = kEcDefault;
950            break;
951        case 1:
952            break; // already set
953        case 2:
954            ECmode = kEcConference;
955            break;
956        case 3:
957            ECmode = kEcAec;
958            break;
959        case 4:
960            ECmode = kEcAecm;
961            break;
962        default:
963            ECmode = (EcModes) 17; // force error
964            break;
965    }
966
967    return veData1.apm->SetEcStatus(enable, ECmode);
968}
969
970/////////////////////////////////////////////
971// [File] Start play file locally
972//
973JNIEXPORT jint JNICALL
974Java_org_webrtc_voiceengine_test_AndroidTest_StartPlayingFileLocally(
975        JNIEnv * env,
976        jobject,
977        jint channel,
978        jstring fileName,
979        jboolean loop)
980{
981    VALIDATE_FILE_POINTER;
982
983    const char* fileNameNative = env->GetStringUTFChars(fileName, NULL);
984    if (!fileNameNative)
985    {
986        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
987                            "Could not get UTF string");
988        return -1;
989    }
990
991    jint retVal = veData1.file->StartPlayingFileLocally(channel,
992                                                        fileNameNative, loop);
993
994    env->ReleaseStringUTFChars(fileName, fileNameNative);
995
996    return retVal;
997}
998
999/////////////////////////////////////////////
1000// [File] Stop play file locally
1001//
1002JNIEXPORT jint JNICALL
1003Java_org_webrtc_voiceengine_test_AndroidTest_StopPlayingFileLocally(
1004        JNIEnv *,
1005        jobject,
1006        jint channel)
1007{
1008    VALIDATE_FILE_POINTER;
1009    return veData1.file->StopPlayingFileLocally(channel);
1010}
1011
1012/*
1013 * Class:     org_webrtc_voiceengine_test_AndroidTest
1014 * Method:    StartRecordingPlayout
1015 * Signature: (ILjava/lang/String;Z)I
1016 */
1017JNIEXPORT jint JNICALL
1018Java_org_webrtc_voiceengine_test_AndroidTest_StartRecordingPlayout(
1019        JNIEnv * env,
1020        jobject,
1021        jint channel,
1022        jstring fileName,
1023        jboolean)
1024{
1025    VALIDATE_FILE_POINTER;
1026
1027    const char* fileNameNative = env->GetStringUTFChars(fileName, NULL);
1028    if (!fileNameNative)
1029    {
1030        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1031                            "Could not get UTF string");
1032        return -1;
1033    }
1034
1035    jint retVal = veData1.file->StartRecordingPlayout(channel, fileNameNative,
1036                                                      0);
1037
1038    env->ReleaseStringUTFChars(fileName, fileNameNative);
1039
1040    return retVal;
1041}
1042
1043/////////////////////////////////////////////
1044// [File] Stop Recording Playout
1045//
1046JNIEXPORT jint JNICALL
1047Java_org_webrtc_voiceengine_test_AndroidTest_StopRecordingPlayout(
1048        JNIEnv *,
1049        jobject,
1050        jint channel)
1051{
1052    VALIDATE_FILE_POINTER;
1053    return veData1.file->StopRecordingPlayout(channel);
1054}
1055
1056/////////////////////////////////////////////
1057// [File] Start playing file as microphone
1058//
1059JNIEXPORT jint JNICALL
1060Java_org_webrtc_voiceengine_test_AndroidTest_StartPlayingFileAsMicrophone(
1061        JNIEnv *env,
1062        jobject,
1063        jint channel,
1064        jstring fileName,
1065        jboolean loop)
1066{
1067    VALIDATE_FILE_POINTER;
1068
1069    const char* fileNameNative = env->GetStringUTFChars(fileName, NULL);
1070    if (!fileNameNative)
1071    {
1072        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1073                            "Could not get UTF string");
1074        return -1;
1075    }
1076
1077    jint retVal = veData1.file->StartPlayingFileAsMicrophone(channel,
1078                                                             fileNameNative,
1079                                                             loop);
1080
1081    env->ReleaseStringUTFChars(fileName, fileNameNative);
1082
1083    return retVal;
1084}
1085
1086/////////////////////////////////////////////
1087// [File] Stop playing file as microphone
1088//
1089JNIEXPORT jint JNICALL
1090Java_org_webrtc_voiceengine_test_AndroidTest_StopPlayingFileAsMicrophone(
1091        JNIEnv *,
1092        jobject,
1093        jint channel)
1094{
1095    VALIDATE_FILE_POINTER;
1096    return veData1.file->StopPlayingFileAsMicrophone(channel);
1097}
1098
1099/////////////////////////////////////////////
1100// [Volume] Set speaker volume
1101//
1102JNIEXPORT jint JNICALL
1103Java_org_webrtc_voiceengine_test_AndroidTest_SetSpeakerVolume(
1104        JNIEnv *,
1105        jobject,
1106        jint level)
1107{
1108    VALIDATE_VOLUME_POINTER;
1109    if (veData1.volume->SetSpeakerVolume(level) != 0)
1110    {
1111        return -1;
1112    }
1113
1114    unsigned int storedVolume = 0;
1115    if (veData1.volume->GetSpeakerVolume(storedVolume) != 0)
1116    {
1117        return -1;
1118    }
1119
1120    if (storedVolume != level)
1121    {
1122        return -1;
1123    }
1124
1125    return 0;
1126}
1127
1128/////////////////////////////////////////////
1129// [Hardware] Set loudspeaker status
1130//
1131JNIEXPORT jint JNICALL
1132Java_org_webrtc_voiceengine_test_AndroidTest_SetLoudspeakerStatus(
1133        JNIEnv *,
1134        jobject,
1135        jboolean enable)
1136{
1137    VALIDATE_HARDWARE_POINTER;
1138    if (veData1.hardware->SetLoudspeakerStatus(enable) != 0)
1139    {
1140        return -1;
1141    }
1142
1143    /*VALIDATE_RTP_RTCP_POINTER;
1144
1145     if (veData1.rtp_rtcp->SetREDStatus(0, enable, -1) != 0)
1146     {
1147     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1148         "Could not set RED");
1149     return -1;
1150     }
1151     else if(enable)
1152     {
1153     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1154         "Could enable RED");
1155     }
1156     else
1157     {
1158     __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1159         "Could disable RED");
1160     }*/
1161
1162    return 0;
1163}
1164
1165//////////////////////////////////////////////////////////////////
1166// "Local" functions (i.e. not Java accessible)
1167//////////////////////////////////////////////////////////////////
1168
1169/////////////////////////////////////////////
1170// Get all sub-APIs
1171//
1172bool GetSubApis(VoiceEngineData &veData)
1173{
1174    bool getOK = true;
1175
1176    // Base
1177    veData.base = VoEBase::GetInterface(veData.ve);
1178    if (!veData.base)
1179    {
1180        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1181                            "Get base sub-API failed");
1182        getOK = false;
1183    }
1184
1185    // Codec
1186    veData.codec = VoECodec::GetInterface(veData.ve);
1187    if (!veData.codec)
1188    {
1189        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1190                            "Get codec sub-API failed");
1191        getOK = false;
1192    }
1193
1194    // File
1195    veData.file = VoEFile::GetInterface(veData.ve);
1196    if (!veData.file)
1197    {
1198        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1199                            "Get file sub-API failed");
1200        getOK = false;
1201    }
1202
1203    // Network
1204    veData.netw = VoENetwork::GetInterface(veData.ve);
1205    if (!veData.netw)
1206    {
1207        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1208                            "Get network sub-API failed");
1209        getOK = false;
1210    }
1211
1212    // AudioProcessing module
1213    veData.apm = VoEAudioProcessing::GetInterface(veData.ve);
1214    if (!veData.apm)
1215    {
1216        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1217                            "Get apm sub-API failed");
1218        getOK = false;
1219    }
1220
1221    // Volume
1222    veData.volume = VoEVolumeControl::GetInterface(veData.ve);
1223    if (!veData.volume)
1224    {
1225        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1226                            "Get volume sub-API failed");
1227        getOK = false;
1228    }
1229
1230    // Hardware
1231    veData.hardware = VoEHardware::GetInterface(veData.ve);
1232    if (!veData.hardware)
1233    {
1234        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1235                            "Get hardware sub-API failed");
1236        getOK = false;
1237    }
1238
1239    // RTP / RTCP
1240    veData.rtp_rtcp = VoERTP_RTCP::GetInterface(veData.ve);
1241    if (!veData.rtp_rtcp)
1242    {
1243        __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1244                            "Get rtp_rtcp sub-API failed");
1245        getOK = false;
1246    }
1247
1248    return getOK;
1249}
1250
1251/////////////////////////////////////////////
1252// Release all sub-APIs
1253//
1254bool ReleaseSubApis(VoiceEngineData &veData)
1255{
1256    bool releaseOK = true;
1257
1258    // Base
1259    if (veData.base)
1260    {
1261        if (0 != veData.base->Release())
1262        {
1263            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1264                                "Release base sub-API failed");
1265            releaseOK = false;
1266        }
1267        else
1268        {
1269            veData.base = NULL;
1270        }
1271    }
1272
1273    // Codec
1274    if (veData.codec)
1275    {
1276        if (0 != veData.codec->Release())
1277        {
1278            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1279                                "Release codec sub-API failed");
1280            releaseOK = false;
1281        }
1282        else
1283        {
1284            veData.codec = NULL;
1285        }
1286    }
1287
1288    // File
1289    if (veData.file)
1290    {
1291        if (0 != veData.file->Release())
1292        {
1293            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1294                                "Release file sub-API failed");
1295            releaseOK = false;
1296        }
1297        else
1298        {
1299            veData.file = NULL;
1300        }
1301    }
1302
1303    // Network
1304    if (veData.netw)
1305    {
1306        if (0 != veData.netw->Release())
1307        {
1308            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1309                                "Release network sub-API failed");
1310            releaseOK = false;
1311        }
1312        else
1313        {
1314            veData.netw = NULL;
1315        }
1316    }
1317
1318    // apm
1319    if (veData.apm)
1320    {
1321        if (0 != veData.apm->Release())
1322        {
1323            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1324                                "Release apm sub-API failed");
1325            releaseOK = false;
1326        }
1327        else
1328        {
1329            veData.apm = NULL;
1330        }
1331    }
1332
1333    // Volume
1334    if (veData.volume)
1335    {
1336        if (0 != veData.volume->Release())
1337        {
1338            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1339                                "Release volume sub-API failed");
1340            releaseOK = false;
1341        }
1342        else
1343        {
1344            veData.volume = NULL;
1345        }
1346    }
1347
1348    // Hardware
1349    if (veData.hardware)
1350    {
1351        if (0 != veData.hardware->Release())
1352        {
1353            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1354                                "Release hardware sub-API failed");
1355            releaseOK = false;
1356        }
1357        else
1358        {
1359            veData.hardware = NULL;
1360        }
1361    }
1362
1363    // RTP RTCP
1364    if (veData.rtp_rtcp)
1365    {
1366        if (0 != veData.rtp_rtcp->Release())
1367        {
1368            __android_log_write(ANDROID_LOG_ERROR, WEBRTC_LOG_TAG,
1369                                "Release rtp_rtcp sub-API failed");
1370            releaseOK = false;
1371        }
1372        else
1373        {
1374            veData.rtp_rtcp = NULL;
1375        }
1376    }
1377
1378    return releaseOK;
1379}
1380