• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 that can be found
5  * in the LICENSE file in the root of the source tree. An additional
6  * intellectual property rights grant can be found in the file PATENTS. All
7  * contributing project authors may be found in the AUTHORS file in the root of
8  * the source tree.
9  */
10 
11 /*
12  * VoiceEngine Android test application. It starts either auto test or acts like
13  * a GUI test.
14  */
15 
16 package org.webrtc.voiceengine.test;
17 
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.FileNotFoundException;
21 import java.io.FileOutputStream;
22 import java.io.FileReader;
23 import java.io.IOException;
24 
25 import android.app.Activity;
26 import android.content.Context;
27 import android.media.AudioFormat;
28 import android.media.AudioManager;
29 import android.media.AudioRecord;
30 import android.media.AudioTrack;
31 import android.media.MediaRecorder;
32 import android.os.Bundle;
33 import android.util.Log;
34 import android.view.View;
35 import android.widget.AdapterView;
36 import android.widget.ArrayAdapter;
37 import android.widget.Button;
38 import android.widget.EditText;
39 import android.widget.Spinner;
40 import android.widget.TextView;
41 
42 public class AndroidTest extends Activity {
43     private byte[] _playBuffer = null;
44     private short[] _circBuffer = new short[8000]; // can hold 50 frames
45 
46     private int _recIndex = 0;
47     private int _playIndex = 0;
48     // private int _streamVolume = 4;
49     private int _maxVolume = 0; // Android max level (commonly 5)
50     // VoE level (0-255), corresponds to level 4 out of 5
51     private int _volumeLevel = 204;
52 
53     private Thread _playThread;
54     private Thread _recThread;
55     private Thread _autotestThread;
56 
57     private static AudioTrack _at;
58     private static AudioRecord _ar;
59 
60     private File _fr = null;
61     private FileInputStream _in = null;
62 
63     private boolean _isRunningPlay = false;
64     private boolean _isRunningRec = false;
65     private boolean _settingSet = true;
66     private boolean _isCallActive = false;
67     private boolean _runAutotest = false; // ENABLE AUTOTEST HERE!
68 
69     private int _channel = -1;
70     private int _codecIndex = 0;
71     private int _ecIndex = 0;
72     private int _nsIndex = 0;
73     private int _agcIndex = 0;
74     private int _vadIndex = 0;
75     private int _audioIndex = 3;
76     private int _settingMenu = 0;
77     private int _receivePort = 1234;
78     private int _destinationPort = 1234;
79     private String _destinationIP = "127.0.0.1";
80 
81     // "Build" settings
82     private final boolean _playFromFile = false;
83     // Set to true to send data to native code and back
84     private final boolean _runThroughNativeLayer = true;
85     private final boolean enableSend = true;
86     private final boolean enableReceive = true;
87     private final boolean useNativeThread = false;
88 
89     /** Called when the activity is first created. */
onCreate(Bundle savedInstanceState)90     public void onCreate(Bundle savedInstanceState) {
91         super.onCreate(savedInstanceState);
92         setContentView(R.layout.main);
93 
94         TextView tv = (TextView) findViewById(R.id.TextView01);
95         tv.setText("");
96 
97         final EditText ed = (EditText) findViewById(R.id.EditText01);
98         ed.setWidth(200);
99         ed.setText(_destinationIP);
100 
101         final Button buttonStart = (Button) findViewById(R.id.Button01);
102         buttonStart.setWidth(200);
103         if (_runAutotest) {
104             buttonStart.setText("Run test");
105         } else {
106             buttonStart.setText("Start Call");
107         }
108         // button.layout(50, 50, 100, 40);
109         buttonStart.setOnClickListener(new View.OnClickListener() {
110             public void onClick(View v) {
111 
112                 if (_runAutotest) {
113                     startAutoTest();
114                 } else {
115                     if (_isCallActive) {
116 
117                         if (stopCall() != -1) {
118                             _isCallActive = false;
119                             buttonStart.setText("Start Call");
120                         }
121                     } else {
122 
123                         _destinationIP = ed.getText().toString();
124                         if (startCall() != -1) {
125                             _isCallActive = true;
126                             buttonStart.setText("Stop Call");
127                         }
128                     }
129                 }
130 
131                 // displayTextFromFile();
132                 // recordAudioToFile();
133                 // if(!_playFromFile)
134                 // {
135                 // recAudioInThread();
136                 // }
137                 // playAudioInThread();
138             }
139         });
140 
141         final Button buttonStop = (Button) findViewById(R.id.Button02);
142         buttonStop.setWidth(200);
143         buttonStop.setText("Close app");
144         buttonStop.setOnClickListener(new View.OnClickListener() {
145             public void onClick(View v) {
146 
147                 if (!_runAutotest) {
148                     ShutdownVoE();
149                 }
150 
151                 // This call terminates and should close the activity
152                 finish();
153 
154                 // playAudioFromFile();
155                 // if(!_playFromFile)
156                 // {
157                 // stopRecAudio();
158                 // }
159                 // stopPlayAudio();
160             }
161         });
162 
163 
164         String ap1[] = {"EC off", "AECM"};
165         final ArrayAdapter<String> adapterAp1 = new ArrayAdapter<String>(
166                         this,
167                         android.R.layout.simple_spinner_dropdown_item,
168                         ap1);
169         String ap2[] =
170                         {"NS off", "NS low", "NS moderate", "NS high",
171                                         "NS very high"};
172         final ArrayAdapter<String> adapterAp2 = new ArrayAdapter<String>(
173                         this,
174                         android.R.layout.simple_spinner_dropdown_item,
175                         ap2);
176         String ap3[] = {"AGC off", "AGC adaptive", "AGC fixed"};
177         final ArrayAdapter<String> adapterAp3 = new ArrayAdapter<String>(
178                         this,
179                         android.R.layout.simple_spinner_dropdown_item,
180                         ap3);
181         String ap4[] =
182                         {"VAD off", "VAD conventional", "VAD high rate",
183                                         "VAD mid rate", "VAD low rate"};
184         final ArrayAdapter<String> adapterAp4 = new ArrayAdapter<String>(
185                         this,
186                         android.R.layout.simple_spinner_dropdown_item,
187                         ap4);
188         String codecs[] = {"iSAC", "PCMU", "PCMA", "iLBC"};
189         final ArrayAdapter<String> adapterCodecs = new ArrayAdapter<String>(
190                         this,
191                         android.R.layout.simple_spinner_dropdown_item,
192                         codecs);
193 
194         final Spinner spinnerSettings1 = (Spinner) findViewById(R.id.Spinner01);
195         final Spinner spinnerSettings2 = (Spinner) findViewById(R.id.Spinner02);
196         spinnerSettings1.setMinimumWidth(200);
197         String settings[] =
198                         {"Codec", "Echo Control", "Noise Suppression",
199                          "Automatic Gain Control",
200                          "Voice Activity Detection"};
201         ArrayAdapter<String> adapterSettings1 = new ArrayAdapter<String>(
202                         this,
203                         android.R.layout.simple_spinner_dropdown_item,
204                         settings);
205         spinnerSettings1.setAdapter(adapterSettings1);
206         spinnerSettings1.setOnItemSelectedListener(
207                         new AdapterView.OnItemSelectedListener() {
208             public void onItemSelected(AdapterView adapterView, View view,
209                             int position, long id) {
210 
211                 _settingMenu = position;
212                 _settingSet = false;
213                 if (position == 0) {
214                     spinnerSettings2.setAdapter(adapterCodecs);
215                     spinnerSettings2.setSelection(_codecIndex);
216                 }
217                 if (position == 1) {
218                     spinnerSettings2.setAdapter(adapterAp1);
219                     spinnerSettings2.setSelection(_ecIndex);
220                 }
221                 if (position == 2) {
222                     spinnerSettings2.setAdapter(adapterAp2);
223                     spinnerSettings2.setSelection(_nsIndex);
224                 }
225                 if (position == 3) {
226                     spinnerSettings2.setAdapter(adapterAp3);
227                     spinnerSettings2.setSelection(_agcIndex);
228                 }
229                 if (position == 4) {
230                     spinnerSettings2.setAdapter(adapterAp4);
231                     spinnerSettings2.setSelection(_vadIndex);
232                 }
233             }
234 
235             public void onNothingSelected(AdapterView adapterView) {
236                 WebrtcLog("No setting1 selected");
237             }
238         });
239 
240         spinnerSettings2.setMinimumWidth(200);
241         ArrayAdapter<String> adapterSettings2 = new ArrayAdapter<String>(
242                         this,
243                         android.R.layout.simple_spinner_dropdown_item,
244                         codecs);
245         spinnerSettings2.setAdapter(adapterSettings2);
246         spinnerSettings2.setOnItemSelectedListener(
247                         new AdapterView.OnItemSelectedListener() {
248             public void onItemSelected(AdapterView adapterView, View view,
249                             int position, long id) {
250 
251                 // avoid unintentional setting
252                 if (_settingSet == false) {
253                     _settingSet = true;
254                     return;
255                 }
256 
257                 // Change volume
258                 if (_settingMenu == 0) {
259                     WebrtcLog("Selected audio " + position);
260                     setAudioProperties(position);
261                     spinnerSettings2.setSelection(_audioIndex);
262                 }
263 
264                 // Change codec
265                 if (_settingMenu == 1) {
266                     _codecIndex = position;
267                     WebrtcLog("Selected codec " + position);
268                     if (0 != SetSendCodec(_channel, _codecIndex)) {
269                         WebrtcLog("VoE set send codec failed");
270                     }
271                 }
272 
273                 // Change EC
274                 if (_settingMenu == 2) {
275                     boolean enable = true;
276                     int ECmode = 5; // AECM
277                     int AESmode = 0;
278 
279                     _ecIndex = position;
280                     WebrtcLog("Selected EC " + position);
281 
282                     if (position == 0) {
283                         enable = false;
284                     }
285                     if (position > 1) {
286                         ECmode = 4; // AES
287                         AESmode = position - 1;
288                     }
289 
290                     if (0 != SetECStatus(enable, ECmode)) {
291                         WebrtcLog("VoE set EC status failed");
292                     }
293                 }
294 
295                 // Change NS
296                 if (_settingMenu == 3) {
297                     boolean enable = true;
298 
299                     _nsIndex = position;
300                     WebrtcLog("Selected NS " + position);
301 
302                     if (position == 0) {
303                         enable = false;
304                     }
305                     if (0 != SetNSStatus(enable, position + 2)) {
306                         WebrtcLog("VoE set NS status failed");
307                     }
308                 }
309 
310                 // Change AGC
311                 if (_settingMenu == 4) {
312                     boolean enable = true;
313 
314                     _agcIndex = position;
315                     WebrtcLog("Selected AGC " + position);
316 
317                     if (position == 0) {
318                         enable = false;
319                         position = 1; // default
320                     }
321                     if (0 != SetAGCStatus(enable, position + 2)) {
322                         WebrtcLog("VoE set AGC status failed");
323                     }
324                 }
325 
326                 // Change VAD
327                 if (_settingMenu == 5) {
328                     boolean enable = true;
329 
330                     _vadIndex = position;
331                     WebrtcLog("Selected VAD " + position);
332 
333                     if (position == 0) {
334                         enable = false;
335                         position++;
336                     }
337                     if (0 != SetVADStatus(_channel, enable, position - 1)) {
338                         WebrtcLog("VoE set VAD status failed");
339                     }
340                 }
341             }
342 
343             public void onNothingSelected(AdapterView adapterView) {
344             }
345         });
346 
347         // Setup VoiceEngine
348         if (!_runAutotest && !useNativeThread) SetupVoE();
349 
350         // Suggest to use the voice call audio stream for hardware volume
351         // controls
352         setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
353 
354         // Get max Android volume and adjust default volume to map exactly to an
355         // Android level
356         AudioManager am =
357                         (AudioManager) getSystemService(Context.AUDIO_SERVICE);
358         _maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
359         if (_maxVolume <= 0) {
360             WebrtcLog("Could not get max volume!");
361         } else {
362             int androidVolumeLevel = (_volumeLevel * _maxVolume) / 255;
363             _volumeLevel = (androidVolumeLevel * 255) / _maxVolume;
364         }
365 
366         WebrtcLog("Started Webrtc Android Test");
367     }
368 
369     // Will be called when activity is shutdown.
370     // NOTE: Activity may be killed without this function being called,
371     // but then we should not need to clean up.
onDestroy()372     protected void onDestroy() {
373         super.onDestroy();
374         // ShutdownVoE();
375     }
376 
SetupVoE()377     private void SetupVoE() {
378         // Create VoiceEngine
379         Create(); // Error logging is done in native API wrapper
380 
381         // Initialize
382         if (0 != Init(false, false)) {
383             WebrtcLog("VoE init failed");
384         }
385 
386         // Create channel
387         _channel = CreateChannel();
388         if (0 != _channel) {
389             WebrtcLog("VoE create channel failed");
390         }
391 
392     }
393 
ShutdownVoE()394     private void ShutdownVoE() {
395         // Delete channel
396         if (0 != DeleteChannel(_channel)) {
397             WebrtcLog("VoE delete channel failed");
398         }
399 
400         // Terminate
401         if (0 != Terminate()) {
402             WebrtcLog("VoE terminate failed");
403         }
404 
405         // Delete VoiceEngine
406         Delete(); // Error logging is done in native API wrapper
407     }
408 
startCall()409     int startCall() {
410 
411         if (useNativeThread == true) {
412 
413             Create();
414             return 0;
415         }
416 
417         if (enableReceive == true) {
418             // Set local receiver
419             if (0 != SetLocalReceiver(_channel, _receivePort)) {
420                 WebrtcLog("VoE set local receiver failed");
421             }
422 
423             if (0 != StartListen(_channel)) {
424                 WebrtcLog("VoE start listen failed");
425                 return -1;
426             }
427 
428             // Route audio to earpiece
429             if (0 != SetLoudspeakerStatus(false)) {
430                 WebrtcLog("VoE set louspeaker status failed");
431                 return -1;
432             }
433 
434             /*
435              * WebrtcLog("VoE start record now"); if (0 !=
436              * StartRecordingPlayout(_channel, "/sdcard/singleUserDemoOut.pcm",
437              * false)) { WebrtcLog("VoE Recording Playout failed"); }
438              * WebrtcLog("VoE start Recording Playout end");
439              */
440             // Start playout
441             if (0 != StartPlayout(_channel)) {
442                 WebrtcLog("VoE start playout failed");
443                 return -1;
444             }
445 
446             // Start playout file
447             // if (0 != StartPlayingFileLocally(_channel,
448             // "/sdcard/singleUserDemo.pcm", true)) {
449             // WebrtcLog("VoE start playout file failed");
450             // return -1;
451             // }
452         }
453 
454         if (enableSend == true) {
455             if (0 != SetSendDestination(_channel, _destinationPort,
456                             _destinationIP)) {
457                 WebrtcLog("VoE set send  destination failed");
458                 return -1;
459             }
460 
461             if (0 != SetSendCodec(_channel, _codecIndex)) {
462                 WebrtcLog("VoE set send codec failed");
463                 return -1;
464             }
465 
466             /*
467              * if (0 != StartPlayingFileAsMicrophone(_channel,
468              * "/sdcard/singleUserDemo.pcm", true)) {
469              * WebrtcLog("VoE start playing file as microphone failed"); }
470              */
471             if (0 != StartSend(_channel)) {
472                 WebrtcLog("VoE start send failed");
473                 return -1;
474             }
475 
476             // if (0 != StartPlayingFileAsMicrophone(_channel,
477             // "/sdcard/singleUserDemo.pcm", true)) {
478             // WebrtcLog("VoE start playing file as microphone failed");
479             // return -1;
480             // }
481         }
482 
483         return 0;
484     }
485 
stopCall()486     int stopCall() {
487 
488         if (useNativeThread == true) {
489 
490             Delete();
491             return 0;
492         }
493 
494         if (enableSend == true) {
495             // Stop playing file as microphone
496             /*
497              * if (0 != StopPlayingFileAsMicrophone(_channel)) {
498              * WebrtcLog("VoE stop playing file as microphone failed"); return
499              * -1; }
500              */
501             // Stop send
502             if (0 != StopSend(_channel)) {
503                 WebrtcLog("VoE stop send failed");
504                 return -1;
505             }
506         }
507 
508         if (enableReceive == true) {
509             // if (0 != StopRecordingPlayout(_channel)) {
510             // WebrtcLog("VoE stop Recording Playout failed");
511             // }
512             // WebrtcLog("VoE stop Recording Playout ended");
513 
514             // Stop listen
515             if (0 != StopListen(_channel)) {
516                 WebrtcLog("VoE stop listen failed");
517                 return -1;
518             }
519 
520             // Stop playout file
521             // if (0 != StopPlayingFileLocally(_channel)) {
522             // WebrtcLog("VoE stop playout file failed");
523             // return -1;
524             // }
525 
526             // Stop playout
527             if (0 != StopPlayout(_channel)) {
528                 WebrtcLog("VoE stop playout failed");
529                 return -1;
530             }
531 
532             // Route audio to loudspeaker
533             if (0 != SetLoudspeakerStatus(true)) {
534                 WebrtcLog("VoE set louspeaker status failed");
535                 return -1;
536             }
537         }
538 
539         return 0;
540     }
541 
startAutoTest()542     int startAutoTest() {
543 
544         _autotestThread = new Thread(_autotestProc);
545         _autotestThread.start();
546 
547         return 0;
548     }
549 
550     private Runnable _autotestProc = new Runnable() {
551         public void run() {
552             // TODO(xians): choose test from GUI
553             // 1 = standard, not used
554             // 2 = extended, 2 = base
555             RunAutoTest(1, 2);
556         }
557     };
558 
setAudioProperties(int val)559     int setAudioProperties(int val) {
560 
561         // AudioManager am = (AudioManager)
562         // getSystemService(Context.AUDIO_SERVICE);
563 
564         if (val == 0) {
565             // _streamVolume =
566             // am.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
567             // am.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
568             // (_streamVolume+1), 0);
569 
570             int androidVolumeLevel = (_volumeLevel * _maxVolume) / 255;
571             if (androidVolumeLevel < _maxVolume) {
572                 _volumeLevel = ((androidVolumeLevel + 1) * 255) / _maxVolume;
573                 if (0 != SetSpeakerVolume(_volumeLevel)) {
574                     WebrtcLog("VoE set speaker volume failed");
575                 }
576             }
577         } else if (val == 1) {
578             // _streamVolume =
579             // am.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
580             // am.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
581             // (_streamVolume-1), 0);
582 
583             int androidVolumeLevel = (_volumeLevel * _maxVolume) / 255;
584             if (androidVolumeLevel > 0) {
585                 _volumeLevel = ((androidVolumeLevel - 1) * 255) / _maxVolume;
586                 if (0 != SetSpeakerVolume(_volumeLevel)) {
587                     WebrtcLog("VoE set speaker volume failed");
588                 }
589             }
590         } else if (val == 2) {
591             // route audio to back speaker
592             if (0 != SetLoudspeakerStatus(true)) {
593                 WebrtcLog("VoE set loudspeaker status failed");
594             }
595             _audioIndex = 2;
596         } else if (val == 3) {
597             // route audio to earpiece
598             if (0 != SetLoudspeakerStatus(false)) {
599                 WebrtcLog("VoE set loudspeaker status failed");
600             }
601             _audioIndex = 3;
602         }
603 
604         return 0;
605     }
606 
displayTextFromFile()607     int displayTextFromFile() {
608 
609         TextView tv = (TextView) findViewById(R.id.TextView01);
610         FileReader fr = null;
611         char[] fileBuffer = new char[64];
612 
613         try {
614             fr = new FileReader("/sdcard/test.txt");
615         } catch (FileNotFoundException e) {
616             e.printStackTrace();
617             tv.setText("File not found!");
618         }
619 
620         try {
621             fr.read(fileBuffer);
622         } catch (IOException e) {
623             e.printStackTrace();
624         }
625 
626         String readString = new String(fileBuffer);
627         tv.setText(readString);
628         // setContentView(tv);
629 
630         return 0;
631     }
632 
recordAudioToFile()633     int recordAudioToFile() {
634         File fr = null;
635         // final to be reachable within onPeriodicNotification
636         byte[] recBuffer = new byte[320];
637 
638         int recBufSize =
639                         AudioRecord.getMinBufferSize(16000,
640                                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
641                                         AudioFormat.ENCODING_PCM_16BIT);
642         AudioRecord rec =
643                         new AudioRecord(MediaRecorder.AudioSource.MIC, 16000,
644                                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
645                                         AudioFormat.ENCODING_PCM_16BIT,
646                                         recBufSize);
647 
648         fr = new File("/sdcard/record.pcm");
649         FileOutputStream out = null;
650         try {
651             out = new FileOutputStream(fr);
652         } catch (FileNotFoundException e1) {
653             e1.printStackTrace();
654         }
655 
656         // start recording
657         try {
658             rec.startRecording();
659         } catch (IllegalStateException e) {
660             e.printStackTrace();
661         }
662 
663         for (int i = 0; i < 550; i++) {
664             // note, there is a short version of write as well!
665             int wrBytes = rec.read(recBuffer, 0, 320);
666 
667             try {
668                 out.write(recBuffer);
669             } catch (IOException e) {
670                 e.printStackTrace();
671             }
672         }
673 
674         // stop playout
675         try {
676             rec.stop();
677         } catch (IllegalStateException e) {
678             e.printStackTrace();
679         }
680 
681         return 0;
682     }
683 
playAudioFromFile()684     int playAudioFromFile() {
685 
686         File fr = null;
687         // final to be reachable within onPeriodicNotification
688         // final byte[] playBuffer = new byte [320000];
689         // final to be reachable within onPeriodicNotification
690         final byte[] playBuffer = new byte[320];
691 
692         final int playBufSize =
693                         AudioTrack.getMinBufferSize(16000,
694                                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
695                                         AudioFormat.ENCODING_PCM_16BIT);
696         // final int playBufSize = 1920; // 100 ms buffer
697         // byte[] playBuffer = new byte [playBufSize];
698         final AudioTrack play =
699                         new AudioTrack(AudioManager.STREAM_VOICE_CALL, 16000,
700                                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
701                                         AudioFormat.ENCODING_PCM_16BIT,
702                                         playBufSize, AudioTrack.MODE_STREAM);
703 
704         // implementation of the playpos callback functions
705         play.setPlaybackPositionUpdateListener(
706                         new AudioTrack.OnPlaybackPositionUpdateListener() {
707 
708             int count = 0;
709 
710             public void onPeriodicNotification(AudioTrack track) {
711                 // int wrBytes = play.write(playBuffer, count, 320);
712                 count += 320;
713             }
714 
715             public void onMarkerReached(AudioTrack track) {
716 
717             }
718         });
719 
720         // set the notification period = 160 samples
721         // int ret = play.setPositionNotificationPeriod(160);
722 
723         fr = new File("/sdcard/record.pcm");
724         FileInputStream in = null;
725         try {
726             in = new FileInputStream(fr);
727         } catch (FileNotFoundException e1) {
728             e1.printStackTrace();
729         }
730 
731         // try {
732         // in.read(playBuffer);
733         // } catch (IOException e) {
734         // e.printStackTrace();
735         // }
736 
737         // play all at once
738         // int wrBytes = play.write(playBuffer, 0, 320000);
739 
740 
741         // start playout
742         try {
743             play.play();
744         } catch (IllegalStateException e) {
745             e.printStackTrace();
746         }
747 
748         // returns the number of samples that has been written
749         // int headPos = play.getPlaybackHeadPosition();
750 
751         // play with multiple writes
752         for (int i = 0; i < 500; i++) {
753             try {
754                 in.read(playBuffer);
755             } catch (IOException e) {
756                 e.printStackTrace();
757             }
758 
759 
760             // note, there is a short version of write as well!
761             int wrBytes = play.write(playBuffer, 0, 320);
762 
763             Log.d("testWrite", "wrote");
764         }
765 
766         // stop playout
767         try {
768             play.stop();
769         } catch (IllegalStateException e) {
770             e.printStackTrace();
771         }
772 
773         return 0;
774     }
775 
playAudioInThread()776     int playAudioInThread() {
777 
778         if (_isRunningPlay) {
779             return 0;
780         }
781 
782         // File fr = null;
783         // final byte[] playBuffer = new byte[320];
784         if (_playFromFile) {
785             _playBuffer = new byte[320];
786         } else {
787             // reset index
788             _playIndex = 0;
789         }
790         // within
791         // onPeriodicNotification
792 
793         // Log some info (static)
794         WebrtcLog("Creating AudioTrack object");
795         final int minPlayBufSize =
796                         AudioTrack.getMinBufferSize(16000,
797                                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
798                                         AudioFormat.ENCODING_PCM_16BIT);
799         WebrtcLog("Min play buf size = " + minPlayBufSize);
800         WebrtcLog("Min volume = " + AudioTrack.getMinVolume());
801         WebrtcLog("Max volume = " + AudioTrack.getMaxVolume());
802         WebrtcLog("Native sample rate = "
803                         + AudioTrack.getNativeOutputSampleRate(
804                                         AudioManager.STREAM_VOICE_CALL));
805 
806         final int playBufSize = minPlayBufSize; // 3200; // 100 ms buffer
807         // byte[] playBuffer = new byte [playBufSize];
808         try {
809             _at = new AudioTrack(
810                             AudioManager.STREAM_VOICE_CALL,
811                             16000,
812                             AudioFormat.CHANNEL_CONFIGURATION_MONO,
813                             AudioFormat.ENCODING_PCM_16BIT,
814                             playBufSize, AudioTrack.MODE_STREAM);
815         } catch (Exception e) {
816             WebrtcLog(e.getMessage());
817         }
818 
819         // Log some info (non-static)
820         WebrtcLog("Notification marker pos = "
821                         + _at.getNotificationMarkerPosition());
822         WebrtcLog("Play head pos = " + _at.getPlaybackHeadPosition());
823         WebrtcLog("Pos notification dt = "
824                         + _at.getPositionNotificationPeriod());
825         WebrtcLog("Playback rate = " + _at.getPlaybackRate());
826         WebrtcLog("Sample rate = " + _at.getSampleRate());
827 
828         // implementation of the playpos callback functions
829         // _at.setPlaybackPositionUpdateListener(
830         // new AudioTrack.OnPlaybackPositionUpdateListener() {
831         //
832         // int count = 3200;
833         //
834         // public void onPeriodicNotification(AudioTrack track) {
835         // // int wrBytes = play.write(playBuffer, count, 320);
836         // count += 320;
837         // }
838         //
839         // public void onMarkerReached(AudioTrack track) {
840         // }
841         // });
842 
843         // set the notification period = 160 samples
844         // int ret = _at.setPositionNotificationPeriod(160);
845 
846         if (_playFromFile) {
847             _fr = new File("/sdcard/singleUserDemo.pcm");
848             try {
849                 _in = new FileInputStream(_fr);
850             } catch (FileNotFoundException e1) {
851                 e1.printStackTrace();
852             }
853         }
854 
855         // try {
856         // in.read(playBuffer);
857         // } catch (IOException e) {
858         // e.printStackTrace();
859         // }
860 
861         _isRunningPlay = true;
862 
863         // buffer = new byte[3200];
864         _playThread = new Thread(_playProc);
865         // ar.startRecording();
866         // bytesRead = 3200;
867         // recording = true;
868         _playThread.start();
869 
870         return 0;
871     }
872 
stopPlayAudio()873     int stopPlayAudio() {
874         if (!_isRunningPlay) {
875             return 0;
876         }
877 
878         _isRunningPlay = false;
879 
880         return 0;
881     }
882 
883     private Runnable _playProc = new Runnable() {
884         public void run() {
885 
886             // set high thread priority
887             android.os.Process.setThreadPriority(
888                             android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
889 
890             // play all at once
891             // int wrBytes = play.write(playBuffer, 0, 320000);
892 
893             // fill the buffer
894             // play.write(playBuffer, 0, 3200);
895 
896             // play.flush();
897 
898             // start playout
899             try {
900                 _at.play();
901             } catch (IllegalStateException e) {
902                 e.printStackTrace();
903             }
904 
905             // play with multiple writes
906             int i = 0;
907             for (; i < 3000 && _isRunningPlay; i++) {
908 
909                 if (_playFromFile) {
910                     try {
911                         _in.read(_playBuffer);
912                     } catch (IOException e) {
913                         e.printStackTrace();
914                     }
915 
916                     int wrBytes = _at.write(_playBuffer, 0 /* i * 320 */, 320);
917                 } else {
918                     int wrSamples =
919                                     _at.write(_circBuffer, _playIndex * 160,
920                                                     160);
921 
922                     // WebrtcLog("Played 10 ms from buffer, _playIndex = " +
923                     // _playIndex);
924                     // WebrtcLog("Diff = " + (_recIndex - _playIndex));
925 
926                     if (_playIndex == 49) {
927                         _playIndex = 0;
928                     } else {
929                         _playIndex += 1;
930                     }
931                 }
932 
933                 // WebrtcLog("Wrote 10 ms to buffer, head = "
934                 // + _at.getPlaybackHeadPosition());
935             }
936 
937             // stop playout
938             try {
939                 _at.stop();
940             } catch (IllegalStateException e) {
941                 e.printStackTrace();
942             }
943 
944             // returns the number of samples that has been written
945             WebrtcLog("Test stopped, i = " + i + ", head = "
946                             + _at.getPlaybackHeadPosition());
947             int headPos = _at.getPlaybackHeadPosition();
948 
949             // flush the buffers
950             _at.flush();
951 
952             // release the object
953             _at.release();
954             _at = null;
955 
956             // try {
957             // Thread.sleep() must be within a try - catch block
958             // Thread.sleep(3000);
959             // }catch (Exception e){
960             // System.out.println(e.getMessage());
961             // }
962 
963             _isRunningPlay = false;
964 
965         }
966     };
967 
recAudioInThread()968     int recAudioInThread() {
969 
970         if (_isRunningRec) {
971             return 0;
972         }
973 
974         // within
975         // onPeriodicNotification
976 
977         // reset index
978         _recIndex = 20;
979 
980         // Log some info (static)
981         WebrtcLog("Creating AudioRecord object");
982         final int minRecBufSize = AudioRecord.getMinBufferSize(16000,
983                         AudioFormat.CHANNEL_CONFIGURATION_MONO,
984                         AudioFormat.ENCODING_PCM_16BIT);
985         WebrtcLog("Min rec buf size = " + minRecBufSize);
986         // WebrtcLog("Min volume = " + AudioTrack.getMinVolume());
987         // WebrtcLog("Max volume = " + AudioTrack.getMaxVolume());
988         // WebrtcLog("Native sample rate = "
989         // + AudioRecord
990         // .getNativeInputSampleRate(AudioManager.STREAM_VOICE_CALL));
991 
992         final int recBufSize = minRecBufSize; // 3200; // 100 ms buffer
993         try {
994             _ar = new AudioRecord(
995                             MediaRecorder.AudioSource.MIC,
996                             16000,
997                             AudioFormat.CHANNEL_CONFIGURATION_MONO,
998                             AudioFormat.ENCODING_PCM_16BIT,
999                             recBufSize);
1000         } catch (Exception e) {
1001             WebrtcLog(e.getMessage());
1002         }
1003 
1004         // Log some info (non-static)
1005         WebrtcLog("Notification marker pos = "
1006                         + _ar.getNotificationMarkerPosition());
1007         // WebrtcLog("Play head pos = " + _ar.getRecordHeadPosition());
1008         WebrtcLog("Pos notification dt rec= "
1009                         + _ar.getPositionNotificationPeriod());
1010         // WebrtcLog("Playback rate = " + _ar.getRecordRate());
1011         // WebrtcLog("Playback rate = " + _ar.getPlaybackRate());
1012         WebrtcLog("Sample rate = " + _ar.getSampleRate());
1013         // WebrtcLog("Playback rate = " + _ar.getPlaybackRate());
1014         // WebrtcLog("Playback rate = " + _ar.getPlaybackRate());
1015 
1016         _isRunningRec = true;
1017 
1018         _recThread = new Thread(_recProc);
1019 
1020         _recThread.start();
1021 
1022         return 0;
1023     }
1024 
stopRecAudio()1025     int stopRecAudio() {
1026         if (!_isRunningRec) {
1027             return 0;
1028         }
1029 
1030         _isRunningRec = false;
1031 
1032         return 0;
1033     }
1034 
1035     private Runnable _recProc = new Runnable() {
1036         public void run() {
1037 
1038             // set high thread priority
1039             android.os.Process.setThreadPriority(
1040                             android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
1041 
1042             // start recording
1043             try {
1044                 _ar.startRecording();
1045             } catch (IllegalStateException e) {
1046                 e.printStackTrace();
1047             }
1048 
1049             // keep recording to circular buffer
1050             // for a while
1051             int i = 0;
1052             int rdSamples = 0;
1053             short[] tempBuffer = new short[160]; // Only used for native case
1054 
1055             for (; i < 3000 && _isRunningRec; i++) {
1056                 if (_runThroughNativeLayer) {
1057                     rdSamples = _ar.read(tempBuffer, 0, 160);
1058                     // audioLoop(tempBuffer, 160); // Insert into native layer
1059                 } else {
1060                     rdSamples = _ar.read(_circBuffer, _recIndex * 160, 160);
1061 
1062                     // WebrtcLog("Recorded 10 ms to buffer, _recIndex = " +
1063                     // _recIndex);
1064                     // WebrtcLog("rdSamples = " + rdSamples);
1065 
1066                     if (_recIndex == 49) {
1067                         _recIndex = 0;
1068                     } else {
1069                         _recIndex += 1;
1070                     }
1071                 }
1072             }
1073 
1074             // stop recording
1075             try {
1076                 _ar.stop();
1077             } catch (IllegalStateException e) {
1078                 e.printStackTrace();
1079             }
1080 
1081             // release the object
1082             _ar.release();
1083             _ar = null;
1084 
1085             // try {
1086             // Thread.sleep() must be within a try - catch block
1087             // Thread.sleep(3000);
1088             // }catch (Exception e){
1089             // System.out.println(e.getMessage());
1090             // }
1091 
1092             _isRunningRec = false;
1093 
1094             // returns the number of samples that has been written
1095             // WebrtcLog("Test stopped, i = " + i + ", head = "
1096             // + _at.getPlaybackHeadPosition());
1097             // int headPos = _at.getPlaybackHeadPosition();
1098         }
1099     };
1100 
WebrtcLog(String msg)1101     private void WebrtcLog(String msg) {
1102         Log.d("*Webrtc*", msg);
1103     }
1104 
1105     // //////////////// Native function prototypes ////////////////////
1106 
NativeInit()1107     private native static boolean NativeInit();
1108 
RunAutoTest(int testType, int extendedSel)1109     private native int RunAutoTest(int testType, int extendedSel);
1110 
Create()1111     private native boolean Create();
1112 
Delete()1113     private native boolean Delete();
1114 
Init(boolean enableTrace, boolean useExtTrans)1115     private native int Init(boolean enableTrace, boolean useExtTrans);
1116 
Terminate()1117     private native int Terminate();
1118 
CreateChannel()1119     private native int CreateChannel();
1120 
DeleteChannel(int channel)1121     private native int DeleteChannel(int channel);
1122 
SetLocalReceiver(int channel, int port)1123     private native int SetLocalReceiver(int channel, int port);
1124 
SetSendDestination(int channel, int port, String ipaddr)1125     private native int SetSendDestination(int channel, int port,
1126                     String ipaddr);
1127 
StartListen(int channel)1128     private native int StartListen(int channel);
1129 
StartPlayout(int channel)1130     private native int StartPlayout(int channel);
1131 
StartSend(int channel)1132     private native int StartSend(int channel);
1133 
StopListen(int channel)1134     private native int StopListen(int channel);
1135 
StopPlayout(int channel)1136     private native int StopPlayout(int channel);
1137 
StopSend(int channel)1138     private native int StopSend(int channel);
1139 
StartPlayingFileLocally(int channel, String fileName, boolean loop)1140     private native int StartPlayingFileLocally(int channel, String fileName,
1141                     boolean loop);
1142 
StopPlayingFileLocally(int channel)1143     private native int StopPlayingFileLocally(int channel);
1144 
StartRecordingPlayout(int channel, String fileName, boolean loop)1145     private native int StartRecordingPlayout(int channel, String fileName,
1146                     boolean loop);
1147 
StopRecordingPlayout(int channel)1148     private native int StopRecordingPlayout(int channel);
1149 
StartPlayingFileAsMicrophone(int channel, String fileName, boolean loop)1150     private native int StartPlayingFileAsMicrophone(int channel,
1151                     String fileName, boolean loop);
1152 
StopPlayingFileAsMicrophone(int channel)1153     private native int StopPlayingFileAsMicrophone(int channel);
1154 
NumOfCodecs()1155     private native int NumOfCodecs();
1156 
SetSendCodec(int channel, int index)1157     private native int SetSendCodec(int channel, int index);
1158 
SetVADStatus(int channel, boolean enable, int mode)1159     private native int SetVADStatus(int channel, boolean enable, int mode);
1160 
SetNSStatus(boolean enable, int mode)1161     private native int SetNSStatus(boolean enable, int mode);
1162 
SetAGCStatus(boolean enable, int mode)1163     private native int SetAGCStatus(boolean enable, int mode);
1164 
SetECStatus(boolean enable, int mode)1165     private native int SetECStatus(boolean enable, int mode);
1166 
SetSpeakerVolume(int volume)1167     private native int SetSpeakerVolume(int volume);
1168 
SetLoudspeakerStatus(boolean enable)1169     private native int SetLoudspeakerStatus(boolean enable);
1170 
1171     /*
1172      * this is used to load the 'webrtc-voice-demo-jni'
1173      * library on application startup.
1174      * The library has already been unpacked into
1175      * /data/data/webrtc.android.AndroidTest/lib/libwebrtc-voice-demo-jni.so
1176      * at installation time by the package manager.
1177      */
1178     static {
1179         Log.d("*Webrtc*", "Loading webrtc-voice-demo-jni...");
1180         System.loadLibrary("webrtc-voice-demo-jni");
1181 
1182         Log.d("*Webrtc*", "Calling native init...");
1183         if (!NativeInit()) {
1184             Log.e("*Webrtc*", "Native init failed");
1185             throw new RuntimeException("Native init failed");
1186         } else {
1187             Log.d("*Webrtc*", "Native init successful");
1188         }
1189     }
1190 }
1191