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