I want to create a VoIP system which works using AudioStream/AudioGroup and can function using only a local WiFi Hotspot. I create a WiFi-Hotspot on android device1 and connect device2 to it. When I fill in the local IP Address of device1, which I get via getLocalIPAddress(), and the IP Address of device2, which I get via the fetchIPs() method on device1, and click on 'Connect' on both devices, the code doesn't throw any exceptions, but I do not hear the microphone audio of either device.
Note1: This code is taken from this answer by @murphybro2 and is slightly changed. Note2: When using the getLocalIPAddress() on device1 (the host), the ip Address comes back as 115.163.242.10 while the fetched IP from device2 has the form 192.168.xxx.yyy
I put android.permission.INTERNET, android.permission.ACCESS_WIFI_STATE and android.permission.RECORD_AUDIO into the Manifest file
MainActivity.java:
package com.applications.fihdi.testapp487623;
import android.content.Context;
import android.media.AudioManager;
import android.net.rtp.*;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.widget.*;
import java.io.*;
import java.net.*;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
String ip = getLocalIPAddress();
Log.d("VOIP","String ip: " + ip);
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
final AudioGroup m_AudioGroup = new AudioGroup();
m_AudioGroup.setMode(AudioGroup.MODE_NORMAL);
final AudioStream m_AudioStream = new AudioStream(InetAddress.getByName(ip));
Log.d("VOIP","localhost (same as ip??): = " + InetAddress.getLocalHost());
int localPort = m_AudioStream.getLocalPort();
Log.d("VOIP","Local Port: "+ Integer.toString(localPort));
m_AudioStream.setCodec(AudioCodec.PCMU);
m_AudioStream.setMode(RtpStream.MODE_NORMAL);
((TextView) findViewById(R.id.lblLocalPort)).setText(String.valueOf(localPort));
((TextView) findViewById(R.id.statusLabel)).setText("Status: local port number generated");
findViewById(R.id.connectButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("VOIP","ConnectButton pressed");
String remoteAddress;
String remotePort;
remoteAddress = ((EditText) findViewById(R.id.editText2)).getText().toString();
//String remoteAddress = fetchIPs().get(0);
remotePort = ((EditText) findViewById(R.id.editText1)).getText().toString();
//Log.d("VOIP", fetchIPs().get(0));
try {
m_AudioStream.associate(InetAddress.getByName(remoteAddress), Integer.parseInt(remotePort));
Log.d("VOIP","AudioStream associated");
((TextView) findViewById(R.id.statusLabel)).setText("Status: connected to: " + fetchIPs().get(0));
m_AudioStream.join(m_AudioGroup);
Log.d("VOIP","AudioStream joined");
} catch (Exception e) {
((TextView) findViewById(R.id.statusLabel)).setText("Couldn't connect");
Log.d("VOIP","Exception with associating");
}
}
});
findViewById(R.id.DisconnectButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
m_AudioStream.release();
}
});
} catch (Exception e) {
Log.e("VOIP", "Exception when setting up the Audiostream!");
e.printStackTrace();
}
findViewById(R.id.fetchButtons).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("VOIP","FetchIp Button pressed");
ArrayList<String> connectedIPs = fetchIPs();
((EditText) findViewById(R.id.editText2)).setText(connectedIPs.get(0));
for(int i = 0; i<connectedIPs.size(); i++){
Log.d("VOIP", "connectedIps[" + i + "]: " + connectedIPs.get(i));
}
}
});
}
public String getLocalIPAddress() {
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()) {
String ip = Formatter.formatIpAddress(inetAddress.hashCode());
Log.d("VOIP", "***** IP="+ ip);
return ip;
}
}
}
} catch (SocketException ex) {
Log.e("VOIP", ex.toString());
}
return null;
}
public ArrayList<String> fetchIPs() {
BufferedReader bufRead = null;
ArrayList<String> result = null;
try {
result = new ArrayList<String>();
bufRead = new BufferedReader(new FileReader("/proc/net/arp"));
String fileLine;
while ((fileLine = bufRead.readLine()) != null) {
String[] splitted = fileLine.split(" +");
if ((splitted != null) && (splitted.length >= 4)) {
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")) {
try {
String ping = "ping -c 1 -W 1 " + splitted[0];
Runtime run = Runtime.getRuntime();
Process pro = run.exec(ping);
try {
pro.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
int exit = pro.exitValue();
if (exit == 0) {
result.add(splitted[0]);
} else {
throw new Exception();
}
} catch (Exception e) {
Log.d("MainActivity", "Something went wrong with pinging the adress: " + splitted[0]);
Log.d("MainActivity", e.getMessage());
}
}
}
}
} catch (Exception e) {
}
try {
bufRead.close();
} catch (Exception e) {
}
return result;
}
}
main_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/lblLocalPort"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/localPort" />
<EditText
android:id="@+id/editText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="@string/iPHint"
android:inputType="phone" />
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="@string/portHint"
android:inputType="number" >
<requestFocus />
</EditText>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<Button
android:id="@+id/connectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/connect" />
<Button
android:id="@+id/DisconnectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Disconnect" />
<Button
android:id="@+id/fetchButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Fetch IPs" />
</LinearLayout>
<TextView
android:id="@+id/statusLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
dimens.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="activity_vertical_margin">8dp</dimen>
<dimen name="activity_horizontal_margin">8dp</dimen>
</resources>
getLocalIPAddress()
should return you the IP address of the WiFi Network Interface.
In the current code, you are return the first IP address of the network interface in your list.
You should check the netInterface.getName()
and compare with the WiFi interface Name and return the IP address.
Once your IP address is proper you can proceed further.