blob: 9d94726a709b7c51d8573ffa18126db70efa6909 [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc.videoengineapp;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import org.webrtc.videoengine.ViERenderer;
import android.app.TabActivity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Display;
import android.view.OrientationEventListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.TabHost.TabSpec;
public class WebRTCDemo extends TabActivity implements IViEAndroidCallback,
View.OnClickListener,
OnItemSelectedListener {
private ViEAndroidJavaAPI ViEAndroidAPI = null;
// remote renderer
private SurfaceView remoteSurfaceView = null;
// local renderer and camera
private SurfaceView svLocal = null;
// channel number
private int channel;
private int cameraId;
private int voiceChannel = -1;
// flags
private boolean viERunning = false;
private boolean voERunning = false;
// debug
private boolean enableTrace = false;
// Constant
private static final String TAG = "WEBRTC";
private static final int RECEIVE_CODEC_FRAMERATE = 15;
private static final int SEND_CODEC_FRAMERATE = 15;
private static final int INIT_BITRATE = 500;
private static final String LOOPBACK_IP = "127.0.0.1";
private static final String RINGTONE_URL = "content://settings/system/ringtone";
private int volumeLevel = 204;
private TabHost mTabHost = null;
private TabSpec mTabSpecConfig;
private TabSpec mTabSpecVideo;
private LinearLayout mLlRemoteSurface = null;
private LinearLayout mLlLocalSurface = null;
private Button btStartStopCall;
private Button btSwitchCamera;
// Global Settings
private CheckBox cbVideoSend;
private boolean enableVideoSend = true;
private CheckBox cbVideoReceive;
private boolean enableVideoReceive = true;
private boolean enableVideo = true;
private CheckBox cbVoice;
private boolean enableVoice = true;
private EditText etRemoteIp;
private String remoteIp = "";
private CheckBox cbLoopback;
private boolean loopbackMode = true;
private CheckBox cbStats;
private boolean isStatsOn = true;
private CheckBox cbCPULoad;
private boolean isCPULoadOn = true;
private boolean useOpenGLRender = true;
// Video settings
private Spinner spCodecType;
private int codecType = 0;
private Spinner spCodecSize;
private int codecSizeWidth = 0;
private int codecSizeHeight = 0;
private TextView etVRxPort;
private int receivePortVideo = 11111;
private TextView etVTxPort;
private int destinationPortVideo = 11111;
private CheckBox cbEnableNack;
private boolean enableNack = false;
private CheckBox cbEnableVideoRTPDump;
// Audio settings
private Spinner spVoiceCodecType;
private int voiceCodecType = 0;
private TextView etARxPort;
private int receivePortVoice = 11113;
private TextView etATxPort;
private int destinationPortVoice = 11113;
private CheckBox cbEnableSpeaker;
private boolean enableSpeaker = false;
private CheckBox cbEnableAGC;
private boolean enableAGC = false;
private CheckBox cbEnableAECM;
private boolean enableAECM = false;
private CheckBox cbEnableNS;
private boolean enableNS = false;
private CheckBox cbEnableDebugAPM;
private CheckBox cbEnableVoiceRTPDump;
// Stats variables
private int frameRateI;
private int bitRateI;
private int packetLoss;
private int frameRateO;
private int bitRateO;
// Variable for storing variables
private String webrtcName = "/webrtc";
private String webrtcDebugDir = null;
private WakeLock wakeLock;
private boolean usingFrontCamera = true;
private String[] mVideoCodecsStrings = null;
private String[] mVideoCodecsSizeStrings = { "176x144", "320x240",
"352x288", "640x480" };
private String[] mVoiceCodecsStrings = null;
private Thread mBackgroundLoad = null;
private boolean mIsBackgroudLoadRunning = false;
private OrientationEventListener orientationListener;
int currentOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
int currentCameraOrientation = 0;
private StatsView statsView = null;
private BroadcastReceiver receiver;
public int GetCameraOrientation(int cameraOrientation) {
Display display = this.getWindowManager().getDefaultDisplay();
int displatyRotation = display.getRotation();
int degrees = 0;
switch (displatyRotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result=0;
if(cameraOrientation>180) {
result=(cameraOrientation + degrees) % 360;
}
else {
result=(cameraOrientation - degrees+360) % 360;
}
return result;
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int newRotation = GetCameraOrientation(currentCameraOrientation);
if (viERunning){
ViEAndroidAPI.SetRotation(cameraId,newRotation);
}
}
// Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Set screen orientation
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
PowerManager pm = (PowerManager)this.getSystemService(
Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(
PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
setContentView(R.layout.tabhost);
IntentFilter receiverFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().compareTo(Intent.ACTION_HEADSET_PLUG)
== 0) {
int state = intent.getIntExtra("state", 0);
Log.v(TAG, "Intent.ACTION_HEADSET_PLUG state: " + state +
" microphone: " + intent.getIntExtra("microphone", 0));
if (voERunning) {
if (state == 1) {
enableSpeaker = true;
}
else {
enableSpeaker = false;
}
RouteAudio(enableSpeaker);
}
}
}
};
registerReceiver(receiver, receiverFilter );
mTabHost = getTabHost();
// Main tab
mTabSpecVideo = mTabHost.newTabSpec("tab_video");
mTabSpecVideo.setIndicator("Main");
mTabSpecVideo.setContent(R.id.tab_video);
mTabHost.addTab(mTabSpecVideo);
// Shared config tab
mTabHost = getTabHost();
mTabSpecConfig = mTabHost.newTabSpec("tab_config");
mTabSpecConfig.setIndicator("Settings");
mTabSpecConfig.setContent(R.id.tab_config);
mTabHost.addTab(mTabSpecConfig);
TabSpec mTabv;
mTabv = mTabHost.newTabSpec("tab_vconfig");
mTabv.setIndicator("Video");
mTabv.setContent(R.id.tab_vconfig);
mTabHost.addTab(mTabv);
TabSpec mTaba;
mTaba = mTabHost.newTabSpec("tab_aconfig");
mTaba.setIndicator("Audio");
mTaba.setContent(R.id.tab_aconfig);
mTabHost.addTab(mTaba);
int childCount = mTabHost.getTabWidget().getChildCount();
for (int i=0; i<childCount; i++)
mTabHost.getTabWidget().getChildAt(i).getLayoutParams().height = 50;
orientationListener =
new OrientationEventListener(this,SensorManager.SENSOR_DELAY_UI) {
public void onOrientationChanged (int orientation) {
if (orientation != ORIENTATION_UNKNOWN) {
currentOrientation = orientation;
}
}
};
orientationListener.enable ();
// Create a folder named webrtc in /scard for debugging
webrtcDebugDir = Environment.getExternalStorageDirectory().toString() +
webrtcName;
File webrtcDir = new File(webrtcDebugDir);
if (!webrtcDir.exists() && webrtcDir.mkdir() == false) {
Log.v(TAG, "Failed to create " + webrtcDebugDir);
}
else if (!webrtcDir.isDirectory()) {
Log.v(TAG, webrtcDebugDir + " exists but not a folder");
webrtcDebugDir = null;
}
StartMain();
return;
}
// Called before the activity is destroyed.
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
unregisterReceiver(receiver);
}
private class StatsView extends View{
public StatsView(Context context){
super(context);
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
mLoadPaint.setTextSize(16);
mLoadPaint.setARGB(255, 255, 255, 255);
String mLoadText;
mLoadText = "> " + frameRateI + " fps/" + bitRateI + "k bps/ " + packetLoss;
canvas.drawText(mLoadText, 4, 172, mLoadPaint);
mLoadText = "< " + frameRateO + " fps/ " + bitRateO + "k bps";
canvas.drawText(mLoadText, 4, 192, mLoadPaint);
updateDisplay();
}
void updateDisplay() {
invalidate();
}
}
private String GetLocalIpAddress() {
String localIPs = "";
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr =
intf.getInetAddresses();
enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
localIPs +=
inetAddress.getHostAddress().toString() + " ";
// Set the remote ip address the same as
// the local ip address of the last netif
remoteIp = inetAddress.getHostAddress().toString();
}
}
}
} catch (SocketException ex) {
Log.e(TAG, ex.toString());
}
return localIPs;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (viERunning) {
StopAll();
StartMain();
}
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
private void StopAll() {
Log.d(TAG, "StopAll");
if (ViEAndroidAPI != null) {
StopCPULoad();
if (voERunning) {
voERunning = false;
StopVoiceEngine();
}
if (viERunning) {
viERunning = false;
ViEAndroidAPI.StopRender(channel);
ViEAndroidAPI.StopReceive(channel);
ViEAndroidAPI.StopSend(channel);
ViEAndroidAPI.RemoveRemoteRenderer(channel);
ViEAndroidAPI.StopCamera(cameraId);
ViEAndroidAPI.Terminate();
mLlRemoteSurface.removeView(remoteSurfaceView);
mLlLocalSurface.removeView(svLocal);
remoteSurfaceView = null;
svLocal = null;
}
}
}
public class SpinnerAdapter extends ArrayAdapter<String> {
private String[] mCodecString = null;
public SpinnerAdapter(Context context, int textViewResourceId, String[] objects) {
super(context, textViewResourceId, objects);
mCodecString = objects;
}
@Override public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent);
}
@Override public View getView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent);
}
public View getCustomView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View row = inflater.inflate(R.layout.row, parent, false);
TextView label = (TextView)row.findViewById(R.id.spinner_row);
label.setText(mCodecString[position]);
return row;
}
}
private void StartMain() {
mTabHost.setCurrentTab(0);
mLlRemoteSurface = (LinearLayout) findViewById(R.id.llRemoteView);
mLlLocalSurface = (LinearLayout) findViewById(R.id.llLocalView);
if (null == ViEAndroidAPI)
ViEAndroidAPI = new ViEAndroidJavaAPI(this);
if (0 > SetupVoE() || 0 > ViEAndroidAPI.GetVideoEngine() ||
0 > ViEAndroidAPI.Init(enableTrace) ) {
// Show dialog
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("WebRTC Error");
alertDialog.setMessage("Can not init video engine.");
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
return;
} });
alertDialog.show();
}
btSwitchCamera = (Button)findViewById(R.id.btSwitchCamera);
btSwitchCamera.setOnClickListener(this);
btStartStopCall = (Button)findViewById(R.id.btStartStopCall);
btStartStopCall.setOnClickListener(this);
findViewById(R.id.btExit).setOnClickListener(this);
// cleaning
remoteSurfaceView = null;
svLocal = null;
// Video codec
mVideoCodecsStrings = ViEAndroidAPI.GetCodecs();
spCodecType = (Spinner)findViewById(R.id.spCodecType);
spCodecType.setOnItemSelectedListener(this);
spCodecType.setAdapter(new SpinnerAdapter(this,
R.layout.row,
mVideoCodecsStrings));
spCodecType.setSelection(0);
// Video Codec size
spCodecSize = (Spinner) findViewById(R.id.spCodecSize);
spCodecSize.setOnItemSelectedListener(this);
spCodecSize.setAdapter(new SpinnerAdapter(this,
R.layout.row,
mVideoCodecsSizeStrings));
spCodecSize.setSelection(0);
// Voice codec
mVoiceCodecsStrings = ViEAndroidAPI.VoE_GetCodecs();
spVoiceCodecType = (Spinner)findViewById(R.id.spVoiceCodecType);
spVoiceCodecType.setOnItemSelectedListener(this);
spVoiceCodecType.setAdapter(new SpinnerAdapter(this,
R.layout.row,
mVoiceCodecsStrings));
spVoiceCodecType.setSelection(0);
// Find ISAC and use it
for (int i = 0; i < mVoiceCodecsStrings.length; ++i) {
if (mVoiceCodecsStrings[i].contains("ISAC")) {
spVoiceCodecType.setSelection(i);
break;
}
}
RadioGroup radioGroup = (RadioGroup)findViewById(R.id.radio_group1);
radioGroup.clearCheck();
if (useOpenGLRender == true) {
radioGroup.check(R.id.radio_opengl);
}
else {
radioGroup.check(R.id.radio_surface);
}
etRemoteIp = (EditText) findViewById(R.id.etRemoteIp);
etRemoteIp.setText(remoteIp);
cbLoopback = (CheckBox) findViewById(R.id.cbLoopback);
cbLoopback.setChecked(loopbackMode);
cbStats = (CheckBox) findViewById(R.id.cbStats);
cbStats.setChecked(isStatsOn);
cbCPULoad = (CheckBox) findViewById(R.id.cbCPULoad);
cbCPULoad.setChecked(isCPULoadOn);
cbVoice = (CheckBox) findViewById(R.id.cbVoice);
cbVoice.setChecked(enableVoice);
cbVideoSend = (CheckBox) findViewById(R.id.cbVideoSend);
cbVideoSend.setChecked(enableVideoSend);
cbVideoReceive = (CheckBox) findViewById(R.id.cbVideoReceive);
cbVideoReceive.setChecked(enableVideoReceive);
etVTxPort = (EditText) findViewById(R.id.etVTxPort);
etVTxPort.setText(Integer.toString(destinationPortVideo));
etVRxPort = (EditText) findViewById(R.id.etVRxPort);
etVRxPort.setText(Integer.toString(receivePortVideo));
etATxPort = (EditText) findViewById(R.id.etATxPort);
etATxPort.setText(Integer.toString(destinationPortVoice));
etARxPort = (EditText) findViewById(R.id.etARxPort);
etARxPort.setText(Integer.toString(receivePortVoice));
cbEnableNack = (CheckBox) findViewById(R.id.cbNack);
cbEnableNack.setChecked(enableNack);
cbEnableSpeaker = (CheckBox) findViewById(R.id.cbSpeaker);
cbEnableSpeaker.setChecked(enableSpeaker);
cbEnableAGC = (CheckBox) findViewById(R.id.cbAutoGainControl);
cbEnableAGC.setChecked(enableAGC);
cbEnableAECM = (CheckBox) findViewById(R.id.cbAECM);
cbEnableAECM.setChecked(enableAECM);
cbEnableNS = (CheckBox) findViewById(R.id.cbNoiseSuppression);
cbEnableNS.setChecked(enableNS);
cbEnableDebugAPM = (CheckBox) findViewById(R.id.cbDebugRecording);
cbEnableDebugAPM.setChecked(false); // Disable APM debugging by default
cbEnableVideoRTPDump = (CheckBox) findViewById(R.id.cbVideoRTPDump);
cbEnableVideoRTPDump.setChecked(false); // Disable Video RTP Dump
cbEnableVoiceRTPDump = (CheckBox) findViewById(R.id.cbVoiceRTPDump);
cbEnableVoiceRTPDump.setChecked(false); // Disable Voice RTP Dump
etRemoteIp.setOnClickListener(this);
cbLoopback.setOnClickListener(this);
cbStats.setOnClickListener(this);
cbCPULoad.setOnClickListener(this);
cbEnableNack.setOnClickListener(this);
cbEnableSpeaker.setOnClickListener(this);
cbEnableAECM.setOnClickListener(this);
cbEnableAGC.setOnClickListener(this);
cbEnableNS.setOnClickListener(this);
cbEnableDebugAPM.setOnClickListener(this);
cbEnableVideoRTPDump.setOnClickListener(this);
cbEnableVoiceRTPDump.setOnClickListener(this);
if (loopbackMode) {
remoteIp = LOOPBACK_IP;
etRemoteIp.setText(remoteIp);
}
else {
GetLocalIpAddress();
etRemoteIp.setText(remoteIp);
}
// Read settings to refresh each configuration
ReadSettings();
}
private String GetRemoteIPString() {
return etRemoteIp.getText().toString();
}
private void StartPlayingRingtone() {
MediaPlayer mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(this, Uri.parse(RINGTONE_URL));
mMediaPlayer.prepare();
mMediaPlayer.seekTo(0);
mMediaPlayer.start();
} catch (IOException e) {
Log.v(TAG, "MediaPlayer Failed: " + e);
}
}
private void StartCall() {
int ret = 0;
StartPlayingRingtone();
if (enableVoice) {
StartVoiceEngine();
}
if (enableVideo) {
if (enableVideoSend) {
// camera and preview surface
svLocal = ViERenderer.CreateLocalRenderer(this);
}
channel = ViEAndroidAPI.CreateChannel(voiceChannel);
ret = ViEAndroidAPI.SetLocalReceiver(channel,
receivePortVideo);
ret = ViEAndroidAPI.SetSendDestination(channel,
destinationPortVideo,
GetRemoteIPString());
if (enableVideoReceive) {
if(useOpenGLRender) {
Log.v(TAG, "Create OpenGL Render");
remoteSurfaceView = ViERenderer.CreateRenderer(this, true);
ret = ViEAndroidAPI.AddRemoteRenderer(channel, remoteSurfaceView);
}
else {
Log.v(TAG, "Create SurfaceView Render");
remoteSurfaceView = ViERenderer.CreateRenderer(this, false);
ret = ViEAndroidAPI.AddRemoteRenderer(channel, remoteSurfaceView);
}
ret = ViEAndroidAPI.SetReceiveCodec(channel,
codecType,
INIT_BITRATE,
codecSizeWidth,
codecSizeHeight,
RECEIVE_CODEC_FRAMERATE);
ret = ViEAndroidAPI.StartRender(channel);
ret = ViEAndroidAPI.StartReceive(channel);
}
if (enableVideoSend) {
currentCameraOrientation =
ViEAndroidAPI.GetCameraOrientation(usingFrontCamera ? 1 : 0);
ret = ViEAndroidAPI.SetSendCodec(channel, codecType, INIT_BITRATE,
codecSizeWidth, codecSizeHeight, SEND_CODEC_FRAMERATE);
int camId = ViEAndroidAPI.StartCamera(channel, usingFrontCamera ? 1 : 0);
if(camId > 0) {
cameraId = camId;
int neededRotation = GetCameraOrientation(currentCameraOrientation);
ViEAndroidAPI.SetRotation(cameraId, neededRotation);
}
else {
ret = camId;
}
ret = ViEAndroidAPI.StartSend(channel);
}
// TODO(leozwang): Add more options besides PLI, currently use pli
// as the default. Also check return value.
ret = ViEAndroidAPI.EnablePLI(channel, true);
ret = ViEAndroidAPI.SetCallback(channel, this);
if (enableVideoSend) {
if (mLlLocalSurface != null)
mLlLocalSurface.addView(svLocal);
}
if (enableVideoReceive) {
if (mLlRemoteSurface != null) {
mLlRemoteSurface.addView(remoteSurfaceView);
}
}
isStatsOn = cbStats.isChecked();
if (isStatsOn) {
AddStatsView();
}
else {
RemoveSatsView();
}
isCPULoadOn = cbCPULoad.isChecked();
if (isCPULoadOn) {
StartCPULoad();
}
else {
StopCPULoad();
}
viERunning = true;
}
}
private void StopVoiceEngine() {
// Stop send
if (0 != ViEAndroidAPI.VoE_StopSend(voiceChannel)) {
Log.d(TAG, "VoE stop send failed");
}
// Stop listen
if (0 != ViEAndroidAPI.VoE_StopListen(voiceChannel)) {
Log.d(TAG, "VoE stop listen failed");
}
// Stop playout
if (0 != ViEAndroidAPI.VoE_StopPlayout(voiceChannel)) {
Log.d(TAG, "VoE stop playout failed");
}
if (0 != ViEAndroidAPI.VoE_DeleteChannel(voiceChannel)) {
Log.d(TAG, "VoE delete channel failed");
}
voiceChannel=-1;
// Terminate
if (0 != ViEAndroidAPI.VoE_Terminate()) {
Log.d(TAG, "VoE terminate failed");
}
}
private int SetupVoE() {
// Create VoiceEngine
// Error logging is done in native API wrapper
ViEAndroidAPI.VoE_Create(getApplicationContext());
// Initialize
if (0 != ViEAndroidAPI.VoE_Init(enableTrace)) {
Log.d(TAG, "VoE init failed");
return -1;
}
// Create channel
voiceChannel = ViEAndroidAPI.VoE_CreateChannel();
if (0 != voiceChannel) {
Log.d(TAG, "VoE create channel failed");
return -1;
}
// Suggest to use the voice call audio stream for hardware volume controls
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
return 0;
}
private int StartVoiceEngine() {
// Set local receiver
if (0 != ViEAndroidAPI.VoE_SetLocalReceiver(voiceChannel,
receivePortVoice)) {
Log.d(TAG, "VoE set local receiver failed");
}
if (0 != ViEAndroidAPI.VoE_StartListen(voiceChannel)) {
Log.d(TAG, "VoE start listen failed");
}
// Route audio
RouteAudio(enableSpeaker);
// set volume to default value
if (0 != ViEAndroidAPI.VoE_SetSpeakerVolume(volumeLevel)) {
Log.d(TAG, "VoE set speaker volume failed");
}
// Start playout
if (0 != ViEAndroidAPI.VoE_StartPlayout(voiceChannel)) {
Log.d(TAG, "VoE start playout failed");
}
if (0 != ViEAndroidAPI.VoE_SetSendDestination(voiceChannel,
destinationPortVoice,
GetRemoteIPString())) {
Log.d(TAG, "VoE set send destination failed");
}
if (0 != ViEAndroidAPI.VoE_SetSendCodec(voiceChannel, voiceCodecType)) {
Log.d(TAG, "VoE set send codec failed");
}
if (0 != ViEAndroidAPI.VoE_SetECStatus(enableAECM)) {
Log.d(TAG, "VoE set EC Status failed");
}
if (0 != ViEAndroidAPI.VoE_SetAGCStatus(enableAGC)) {
Log.d(TAG, "VoE set AGC Status failed");
}
if (0 != ViEAndroidAPI.VoE_SetNSStatus(enableNS)) {
Log.d(TAG, "VoE set NS Status failed");
}
if (0 != ViEAndroidAPI.VoE_StartSend(voiceChannel)) {
Log.d(TAG, "VoE start send failed");
}
voERunning = true;
return 0;
}
private void RouteAudio(boolean enableSpeaker) {
if (0 != ViEAndroidAPI.VoE_SetLoudspeakerStatus(enableSpeaker)) {
Log.d(TAG, "VoE set louspeaker status failed");
}
}
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.btSwitchCamera:
if (usingFrontCamera ){
btSwitchCamera.setText(R.string.frontCamera);
}
else {
btSwitchCamera.setText(R.string.backCamera);
}
usingFrontCamera = !usingFrontCamera;
if (viERunning) {
currentCameraOrientation =
ViEAndroidAPI.GetCameraOrientation(usingFrontCamera?1:0);
ViEAndroidAPI.StopCamera(cameraId);
mLlLocalSurface.removeView(svLocal);
ViEAndroidAPI.StartCamera(channel,usingFrontCamera?1:0);
mLlLocalSurface.addView(svLocal);
int neededRotation = GetCameraOrientation(currentCameraOrientation);
ViEAndroidAPI.SetRotation(cameraId, neededRotation);
}
break;
case R.id.btStartStopCall:
ReadSettings();
if (viERunning || voERunning) {
StopAll();
wakeLock.release(); // release the wake lock
btStartStopCall.setText(R.string.startCall);
}
else if (enableVoice || enableVideo){
StartCall();
wakeLock.acquire(); // screen stay on during the call
btStartStopCall.setText(R.string.stopCall);
}
break;
case R.id.btExit:
StopAll();
finish();
break;
case R.id.cbLoopback:
loopbackMode = cbLoopback.isChecked();
if (loopbackMode) {
remoteIp = LOOPBACK_IP;
etRemoteIp.setText(LOOPBACK_IP);
}
else {
GetLocalIpAddress();
etRemoteIp.setText(remoteIp);
}
break;
case R.id.etRemoteIp:
remoteIp = etRemoteIp.getText().toString();
break;
case R.id.cbStats:
isStatsOn = cbStats.isChecked();
if (isStatsOn) {
AddStatsView();
}
else {
RemoveSatsView();
}
break;
case R.id.cbCPULoad:
isCPULoadOn = cbCPULoad.isChecked();
if (isCPULoadOn) {
StartCPULoad();
}
else {
StopCPULoad();
}
break;
case R.id.radio_surface:
useOpenGLRender = false;
break;
case R.id.radio_opengl:
useOpenGLRender = true;
break;
case R.id.cbNack:
enableNack = cbEnableNack.isChecked();
if (viERunning) {
ViEAndroidAPI.EnableNACK(channel, enableNack);
}
break;
case R.id.cbSpeaker:
enableSpeaker = cbEnableSpeaker.isChecked();
if (voERunning){
RouteAudio(enableSpeaker);
}
break;
case R.id.cbDebugRecording:
if(voERunning && webrtcDebugDir != null) {
if (cbEnableDebugAPM.isChecked() ) {
ViEAndroidAPI.VoE_StartDebugRecording(
webrtcDebugDir + String.format("/apm_%d.dat",
System.currentTimeMillis()));
}
else {
ViEAndroidAPI.VoE_StopDebugRecording();
}
}
break;
case R.id.cbVoiceRTPDump:
if(voERunning && webrtcDebugDir != null) {
if (cbEnableVoiceRTPDump.isChecked() ) {
ViEAndroidAPI.VoE_StartIncomingRTPDump(channel,
webrtcDebugDir + String.format("/voe_%d.rtp",
System.currentTimeMillis()));
}
else {
ViEAndroidAPI.VoE_StopIncomingRTPDump(channel);
}
}
break;
case R.id.cbVideoRTPDump:
if(viERunning && webrtcDebugDir != null) {
if (cbEnableVideoRTPDump.isChecked() ) {
ViEAndroidAPI.StartIncomingRTPDump(channel,
webrtcDebugDir + String.format("/vie_%d.rtp",
System.currentTimeMillis()));
}
else {
ViEAndroidAPI.StopIncomingRTPDump(channel);
}
}
break;
case R.id.cbAutoGainControl:
enableAGC=cbEnableAGC.isChecked();
if(voERunning) {
ViEAndroidAPI.VoE_SetAGCStatus(enableAGC);
}
break;
case R.id.cbNoiseSuppression:
enableNS=cbEnableNS.isChecked();
if(voERunning) {
ViEAndroidAPI.VoE_SetNSStatus(enableNS);
}
break;
case R.id.cbAECM:
enableAECM = cbEnableAECM.isChecked();
if (voERunning) {
ViEAndroidAPI.VoE_SetECStatus(enableAECM);
}
break;
}
}
private void ReadSettings() {
codecType = spCodecType.getSelectedItemPosition();
voiceCodecType = spVoiceCodecType.getSelectedItemPosition();
String sCodecSize = spCodecSize.getSelectedItem().toString();
String[] aCodecSize = sCodecSize.split("x");
codecSizeWidth = Integer.parseInt(aCodecSize[0]);
codecSizeHeight = Integer.parseInt(aCodecSize[1]);
loopbackMode = cbLoopback.isChecked();
enableVoice = cbVoice.isChecked();
enableVideoSend = cbVideoSend.isChecked();
enableVideoReceive = cbVideoReceive.isChecked();
enableVideo = enableVideoSend || enableVideoReceive;
destinationPortVideo =
Integer.parseInt(etVTxPort.getText().toString());
receivePortVideo =
Integer.parseInt(etVRxPort.getText().toString());
destinationPortVoice =
Integer.parseInt(etATxPort.getText().toString());
receivePortVoice =
Integer.parseInt(etARxPort.getText().toString());
enableNack = cbEnableNack.isChecked();
enableSpeaker = cbEnableSpeaker.isChecked();
enableAGC = cbEnableAGC.isChecked();
enableAECM = cbEnableAECM.isChecked();
enableNS = cbEnableNS.isChecked();
}
public void onItemSelected(AdapterView<?> adapterView, View view,
int position, long id) {
if ((adapterView == spCodecType || adapterView == spCodecSize) &&
viERunning) {
ReadSettings();
// change the codectype
if (enableVideoReceive) {
if (0 != ViEAndroidAPI.SetReceiveCodec(channel, codecType,
INIT_BITRATE, codecSizeWidth,
codecSizeHeight,
RECEIVE_CODEC_FRAMERATE))
Log.d(TAG, "ViE set receive codec failed");
}
if (enableVideoSend) {
if (0 != ViEAndroidAPI.SetSendCodec(channel, codecType,
INIT_BITRATE, codecSizeWidth, codecSizeHeight,
SEND_CODEC_FRAMERATE))
Log.d(TAG, "ViE set send codec failed");
}
}
else if ((adapterView == spVoiceCodecType) && voERunning) {
// change voice engine codec
ReadSettings();
if (0 != ViEAndroidAPI.VoE_SetSendCodec(voiceChannel, voiceCodecType)) {
Log.d(TAG, "VoE set send codec failed");
}
}
}
public void onNothingSelected(AdapterView<?> arg0) {
Log.d(TAG, "No setting selected");
}
public int UpdateStats(int in_frameRateI, int in_bitRateI, int in_packetLoss,
int in_frameRateO, int in_bitRateO) {
frameRateI = in_frameRateI;
bitRateI = in_bitRateI;
packetLoss = in_packetLoss;
frameRateO = in_frameRateO;
bitRateO = in_bitRateO;
return 0;
}
private void AddStatsView() {
if (statsView != null) {
return;
}
statsView = new StatsView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
mTabHost.addView(statsView, params);
statsView.setBackgroundColor(0);
}
private void RemoveSatsView() {
mTabHost.removeView(statsView);
statsView = null;
}
private void StartCPULoad() {
if (null == mBackgroundLoad) {
mBackgroundLoad = new Thread(new Runnable() {
public void run() {
Log.v(TAG, "Background load started");
mIsBackgroudLoadRunning = true;
try{
while (mIsBackgroudLoadRunning) {
// This while simulates cpu load.
// Log.v(TAG, "Runnable!!!");
}
}
catch(Throwable t) {
Log.v(TAG, "StartCPULoad failed");
}
}
});
mBackgroundLoad.start();
}
else {
if (mBackgroundLoad.getState() == Thread.State.TERMINATED) {
mBackgroundLoad.start();
}
}
}
private void StopCPULoad() {
if (null != mBackgroundLoad) {
mIsBackgroudLoadRunning = false;
try{
mBackgroundLoad.join();
}
catch(Throwable t) {
Log.v(TAG, "StopCPULoad failed");
}
}
}
}