我需要在 2 个 android 设备之间开发 VOIP 应用程序。
据我所知,有一个用于此目的的 SIP 协议,但它需要注册到 SIP 服务器并访问互联网以进行 SIP 信令。
有什么方法可以在没有互联网访问的情况下在 android 中创建 VOIP 应用程序?
5 回答
当然有可能!为什么你需要互联网?只要你们都连接到同一个网络就可以了!下面是一个工作应用程序的 java 和 xml。
启动时,它会为您提供您自己的本地端口,例如“52022”.. 这是每次都是随机的,不幸的是,这无济于事。然后我们输入另一部手机的 IP 地址和他们随机生成的端口号,然后按连接。他们做的完全一样,万岁你已经连接了!这个测试应用程序显然需要您在附近交换端口号,但在我的适当应用程序中,我可以在连接之前轻松请求每个端口号。希望这可以帮助!
public class MainActivity extends Activity {
AudioGroup m_AudioGroup;
AudioStream m_AudioStream;
@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 {
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
m_AudioGroup = new AudioGroup();
m_AudioGroup.setMode(AudioGroup.MODE_NORMAL);
m_AudioStream = new AudioStream(InetAddress.getByAddress(getLocalIPAddress ()));
int localPort = m_AudioStream.getLocalPort();
m_AudioStream.setCodec(AudioCodec.PCMU);
m_AudioStream.setMode(RtpStream.MODE_NORMAL);
((TextView)findViewById(R.id.lblLocalPort)).setText(String.valueOf(localPort));
((Button) findViewById(R.id.button1)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String remoteAddress = ((EditText)findViewById(R.id.editText2)).getText().toString();
String remotePort = ((EditText)findViewById(R.id.editText1)).getText().toString();
try {
m_AudioStream.associate(InetAddress.getByName(remoteAddress), Integer.parseInt(remotePort));
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m_AudioStream.join(m_AudioGroup);
}
});
((Button) findViewById(R.id.button2)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
m_AudioStream.release();
}
});
} catch (Exception e) {
Log.e("----------------------", e.toString());
e.printStackTrace();
}
}
public static byte[] getLocalIPAddress () {
byte ip[]=null;
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()) {
ip= inetAddress.getAddress();
}
}
}
} catch (SocketException ex) {
Log.i("SocketException ", ex.toString());
}
return ip;
}
}
布局文件:
<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/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/connect" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Disconnect" />
</LinearLayout>
</LinearLayout>
编辑: IP 地址方法在 API 22 停止工作,使用以下代码:
private byte[] getLocalIPAddress() {
byte[] bytes = null;
try {
// get the string ip
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
String ip = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
// convert to bytes
InetAddress inetAddress = null;
try {
inetAddress = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
e.printStackTrace();
}
bytes = new byte[0];
if (inetAddress != null) {
bytes = inetAddress.getAddress();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, R.string.phone_voip_incompatible, Toast.LENGTH_SHORT).show();
}
return bytes;
}
实际上 SIP 客户端可以进行点对点通信,他们只需要知道自己的 IP 地址和侦听 SIP 消息的 UDP 端口即可。
您可以在两个通勤者上使用普通的 SIP 客户端(Windows 的 X-Lite、Linux 的 Twinkle 和其他一些也存在),并尝试在它们之间建立呼叫而无需服务器注册。这是很有可能的。
你也可以在本地局域网的某个地方运行一个简约的 SIP 服务器。例如,FreeSWITCH 可以最小化到一个非常小的占用空间。
好的,所以如果您正在寻找一些对等 2 对等通信,我认为 wifi 是要走的路(更好的距离和速度)。如果您只能为较新版本的 Android 进行开发,那么WI-FI Direct是不错的选择,但这仅适用于 Android 4.0 及更高版本
为了让某些东西在 4.0 以下运行,您将不得不使用 3rd 方库。我知道高通有一个名为alljoyn的库,但不确定它有多好。
我认为您可以在包括 Andriod 在内的多个平台上将 JITSI用于 p2p voip 服务。
这些是我对这个项目的发现:-
- 不需要任何服务器或互联网连接。
- 用户必须在同一网络下。
- 开源。
- Android apk 是可用的,很可能你可以在网站上找到它的代码,或者你可以反编译它。
这是不可能的,因为 VOIP 呼叫通过互联网和 sip 服务器传递。
例如 。如果您想通过 VOIP dailer 从您所在的国家/地区拨打电话,您必须需要互联网接入,因为无法通过蓝牙进行通信。
谢谢。