Home | History | Annotate | Download | only in test
      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. */
     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.
    372     protected void onDestroy() {
    373         super.onDestroy();
    374         // ShutdownVoE();
    375     }
    376 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   1101     private void WebrtcLog(String msg) {
   1102         Log.d("*Webrtc*", msg);
   1103     }
   1104 
   1105     // //////////////// Native function prototypes ////////////////////
   1106 
   1107     private native static boolean NativeInit();
   1108 
   1109     private native int RunAutoTest(int testType, int extendedSel);
   1110 
   1111     private native boolean Create();
   1112 
   1113     private native boolean Delete();
   1114 
   1115     private native int Init(boolean enableTrace, boolean useExtTrans);
   1116 
   1117     private native int Terminate();
   1118 
   1119     private native int CreateChannel();
   1120 
   1121     private native int DeleteChannel(int channel);
   1122 
   1123     private native int SetLocalReceiver(int channel, int port);
   1124 
   1125     private native int SetSendDestination(int channel, int port,
   1126                     String ipaddr);
   1127 
   1128     private native int StartListen(int channel);
   1129 
   1130     private native int StartPlayout(int channel);
   1131 
   1132     private native int StartSend(int channel);
   1133 
   1134     private native int StopListen(int channel);
   1135 
   1136     private native int StopPlayout(int channel);
   1137 
   1138     private native int StopSend(int channel);
   1139 
   1140     private native int StartPlayingFileLocally(int channel, String fileName,
   1141                     boolean loop);
   1142 
   1143     private native int StopPlayingFileLocally(int channel);
   1144 
   1145     private native int StartRecordingPlayout(int channel, String fileName,
   1146                     boolean loop);
   1147 
   1148     private native int StopRecordingPlayout(int channel);
   1149 
   1150     private native int StartPlayingFileAsMicrophone(int channel,
   1151                     String fileName, boolean loop);
   1152 
   1153     private native int StopPlayingFileAsMicrophone(int channel);
   1154 
   1155     private native int NumOfCodecs();
   1156 
   1157     private native int SetSendCodec(int channel, int index);
   1158 
   1159     private native int SetVADStatus(int channel, boolean enable, int mode);
   1160 
   1161     private native int SetNSStatus(boolean enable, int mode);
   1162 
   1163     private native int SetAGCStatus(boolean enable, int mode);
   1164 
   1165     private native int SetECStatus(boolean enable, int mode);
   1166 
   1167     private native int SetSpeakerVolume(int volume);
   1168 
   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