Мой офис пытается создать приложение VoIP для Android и исследует использование собственной реализации клиента SIP в Android. Мы загрузили образец приложения SipDemo в Android studio.
Мы наблюдаем периодическую ошибку, которая возникает примерно в половине случаев, когда мы делаем телефонный звонок с приложением:
- Ошибка возникает после установления вызова
- После того, как мы разместили вызов, мы получаем обратный вызов для метода SipAudioCall.Listener.onCallEstablished
- Но мы также получаем обратный вызов методу обратного вызова "onError" с параметрами errorCode = SipErrorCode.TRANSACTION_TERMINATED и errorMessage = "транзакция завершена".
- Когда это произойдет, мы сможем услышать двунаправленный аудиовызов между двумя устройствами. тестирование, но мы не можем повесить трубку. (Теперь объект SipAudioCall находится в неправильном состоянии)
Вот дополнительная информация о нашей настройке:
- Нашими клиентами являются планшеты Samsung Tab S6
- Мы подключаемся к серверу Asterisk, который мы развернули в соответствии с Asterisk Руководство Hello World .
- Мы настроили 2 добавочных номера.
- Наш тест показывает, что мы размещаем вызов между приложением SipDemo и программным телефоном Zoiper, который также подключен к серверу Asterisk.
Мы просмотрели запись SIP-сообщений Wireshark, но не обнаружили ничего неисправного. Мы также написали версию приложения SipDemo, которое может принимать телефонный звонок, и видели ту же ошибку, используя его для вызова самого себя на двух разных планшетах.
Я включаю сюда свой Android манифест:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.sip">
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CONFIGURE_SIP" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-feature
android:name="android.hardware.sip.voip"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="true" />
<uses-feature
android:name="android.hardware.microphone"
android:required="true" />
<application
android:icon="@drawable/icon"
android:label="SipDemo">
<activity
android:name=".WalkieTalkieActivity"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SipSettings"
android:label="set_preferences" />
<receiver
android:name=".IncomingCallReceiver"
android:label="Call Receiver" />
</application>
</manifest>
Код, который мы используем для настройки звонка, находится здесь:
public void initiateCall() {
updateStatus(sipAddress);
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
// Much of the client's interaction with the SIP Stack will
// happen via listeners. Even making an outgoing call, don't
// forget to set up a listener to set things up once the call is established.
@Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
updateStatus(call);
}
@Override
public void onCallEnded(SipAudioCall call) {
updateStatus("Ready.");
}
@Override
public void onError(SipAudioCall call, int errorCode,
String errorMessage) {
toastHelper("onError: called: errorCode: " + errorCode + " errorMessage: " + errorMessage, Toast.LENGTH_LONG);
}
};
call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
}
catch (Exception e) {
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (me != null) {
try {
manager.close(me.getUriString());
} catch (Exception ee) {
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}