diff --git a/app/src/main/cpp/baresip.c b/app/src/main/cpp/baresip.c
index ec545634..31702c9d 100644
--- a/app/src/main/cpp/baresip.c
+++ b/app/src/main/cpp/baresip.c
@@ -184,6 +184,9 @@ static void ua_event_handler(
case UA_EVENT_CALL_ANSWERED:
len = re_snprintf(event_buf, sizeof event_buf, "call answered");
break;
+ case UA_EVENT_CALL_REDIRECT:
+ len = re_snprintf(event_buf, sizeof event_buf, "call redirect,%s", prm + 4);
+ break;
case UA_EVENT_CALL_LOCAL_SDP:
if (strcmp(prm, "offer") == 0)
return;
@@ -958,6 +961,18 @@ JNIEXPORT jint JNICALL Java_com_tutpro_baresip_Api_account_1set_1answermode(
return account_set_answermode((struct account *)acc, mode);
}
+JNIEXPORT jboolean JNICALL Java_com_tutpro_baresip_Api_account_1sip_1autoredirect(
+ JNIEnv *env, jobject thiz, jlong acc)
+{
+ return account_sip_autoredirect((struct account *)acc);
+}
+
+JNIEXPORT void JNICALL Java_com_tutpro_baresip_Api_account_1set_1sip_1autoredirect(
+ JNIEnv *env, jobject thiz, jlong acc, jboolean allow)
+{
+ return account_set_sip_autoredirect((struct account *)acc, allow);
+}
+
JNIEXPORT jboolean JNICALL Java_com_tutpro_baresip_Api_account_1rtcp_1mux(
JNIEnv *env, jobject thiz, jlong acc)
{
diff --git a/app/src/main/kotlin/com/tutpro/baresip/Account.kt b/app/src/main/kotlin/com/tutpro/baresip/Account.kt
index ee8c08b0..ba1fee5c 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/Account.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/Account.kt
@@ -27,6 +27,7 @@ class Account(val accp: Long) {
var rtcpMux = Api.account_rtcp_mux(accp)
var dtmfMode = Api.account_dtmfmode(accp)
var answerMode = Api.account_answermode(accp)
+ var autoRedirect = Api.account_sip_autoredirect(accp)
var vmUri = Api.account_vm_uri(accp)
var vmNew = 0
var vmOld = 0
@@ -132,6 +133,9 @@ class Account(val accp: Long) {
if (answerMode == Api.ANSWERMODE_AUTO)
res += ";answermode=auto"
+ if (autoRedirect)
+ res += ";sip_autoredirect=yes"
+
res += ";ptime=20;regint=${regint};regq=0.5;pubint=0;call_transfer=yes;100rel=no"
var extra = ""
diff --git a/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt
index c3db50e2..df00af78 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt
@@ -49,6 +49,8 @@ class AccountActivity : AppCompatActivity() {
private lateinit var dtmfModeSpinner: Spinner
private var answerMode = Api.ANSWERMODE_MANUAL
private lateinit var answerModeSpinner: Spinner
+ private var autoRedirect = false
+ private lateinit var redirectModeSpinner: Spinner
private lateinit var vmUri: EditText
private lateinit var countryCode: EditText
private lateinit var telProvider: EditText
@@ -95,6 +97,7 @@ class AccountActivity : AppCompatActivity() {
rtcpCheck = binding.RtcpMux
dtmfModeSpinner = binding.dtmfModeSpinner
answerModeSpinner = binding.answerModeSpinner
+ redirectModeSpinner = binding.redirectModeSpinner
vmUri = binding.voicemailUri
countryCode = binding.countryCode
telProvider = binding.telephonyProvider
@@ -203,6 +206,8 @@ class AccountActivity : AppCompatActivity() {
else
Api.ANSWERMODE_AUTO
}
+ "redirect-mode" ->
+ acc.autoRedirect = text == "yes"
"voicemail-uri" ->
if (text.isNotEmpty())
acc.vmUri = text
@@ -344,6 +349,27 @@ class AccountActivity : AppCompatActivity() {
}
}
+ autoRedirect = acc.autoRedirect
+ val redirectModeKeys = arrayListOf(false, true)
+ val redirectModeVals = arrayListOf(getString(R.string.manual), getString(R.string.auto))
+ keyIx = redirectModeKeys.indexOf(acc.autoRedirect)
+ keyVal = redirectModeVals.elementAt(keyIx)
+ redirectModeKeys.removeAt(keyIx)
+ redirectModeVals.removeAt(keyIx)
+ redirectModeKeys.add(0, acc.autoRedirect)
+ redirectModeVals.add(0, keyVal)
+ val redirectModeAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
+ redirectModeVals)
+ redirectModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ redirectModeSpinner.adapter = redirectModeAdapter
+ redirectModeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
+ autoRedirect = redirectModeKeys[redirectModeVals.indexOf(parent.selectedItem.toString())]
+ }
+ override fun onNothingSelected(parent: AdapterView<*>) {
+ }
+ }
+
if (acc.countryCode != "")
countryCode.setText(acc.countryCode)
@@ -612,6 +638,12 @@ class AccountActivity : AppCompatActivity() {
}
}
+ if (autoRedirect != acc.autoRedirect) {
+ Api.account_set_sip_autoredirect(acc.accp, autoRedirect)
+ acc.autoRedirect = autoRedirect
+ Log.d(TAG, "New autoRedirect is ${acc.autoRedirect}")
+ }
+
var tVmUri = vmUri.text.toString().trim()
if (tVmUri != acc.vmUri) {
if (tVmUri != "") {
@@ -785,6 +817,12 @@ class AccountActivity : AppCompatActivity() {
getString(R.string.answer_mode_help)
)
}
+ binding.RedirectModeTitle.setOnClickListener {
+ Utils.alertView(
+ this, getString(R.string.redirect_mode),
+ getString(R.string.redirect_mode_help)
+ )
+ }
binding.VoicemailUriTitle.setOnClickListener {
Utils.alertView(
this, getString(R.string.voicemail_uri),
diff --git a/app/src/main/kotlin/com/tutpro/baresip/Api.kt b/app/src/main/kotlin/com/tutpro/baresip/Api.kt
index 837e92c8..fec2944f 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/Api.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/Api.kt
@@ -46,6 +46,8 @@ object Api {
external fun account_vm_uri(acc: Long): String
external fun account_answermode(acc: Long): Int
external fun account_set_answermode(acc: Long, mode: Int): Int
+ external fun account_sip_autoredirect(acc: Long): Boolean
+ external fun account_set_sip_autoredirect(acc: Long, allow: Boolean)
external fun account_rtcp_mux(acc: Long): Boolean
external fun account_set_rtcp_mux(acc: Long, value: Boolean): Int
external fun account_dtmfmode(acc: Long): Int
diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
index 85e9fd55..a87ae62c 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
@@ -777,6 +777,9 @@ class BaresipService: Service() {
else
return
}
+ "call redirect" -> {
+ stopMediaPlayer()
+ }
"call established" -> {
nm.cancel(CALL_NOTIFICATION_ID)
Log.d(TAG, "AoR $aor call $callp established in mode ${am.mode}")
@@ -951,10 +954,12 @@ class BaresipService: Service() {
}
val reason = ev[1].trim()
if ((reason != "") && (ua.calls().isEmpty())) {
- if (reason[0].isDigit())
- toast("${getString(R.string.call_failed)}: $reason")
- else
+ if (reason[0].isDigit()) {
+ if (reason[0] != '3')
+ toast("${getString(R.string.call_failed)}: $reason")
+ } else {
toast("${getString(R.string.call_closed)}: ${Api.call_peer_uri(callp)}: $reason")
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
index 1707bdd8..883f930c 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
@@ -1086,6 +1086,37 @@ class MainActivity : AppCompatActivity() {
"call answered" -> {
showCall(ua)
}
+ "call redirect" -> {
+ val redirectUri = ev[1]
+ val target = Utils.friendlyUri(this, redirectUri, acc)
+ if (acc.autoRedirect) {
+ if (ua.account.aor != aorSpinner.tag)
+ spinToAor(ua.account.aor)
+ callUri.setText(redirectUri)
+ callButton.performClick()
+ Toast.makeText(applicationContext,
+ String.format(getString(R.string.redirect_notice), target),
+ Toast.LENGTH_SHORT
+ ).show()
+ } else {
+ with(MaterialAlertDialogBuilder(this, R.style.AlertDialogTheme)) {
+ setTitle(R.string.redirect_request)
+ setMessage(String.format(getString(R.string.redirect_request_query), target))
+ setPositiveButton(getString(R.string.yes)) { dialog, _ ->
+ if (ua.account.aor != aorSpinner.tag)
+ spinToAor(ua.account.aor)
+ callUri.setText(redirectUri)
+ callButton.performClick()
+ dialog.dismiss()
+ }
+ setNeutralButton(getString(R.string.no)) { dialog, _ ->
+ dialog.dismiss()
+ }
+ show()
+ }
+ }
+ showCall(ua)
+ }
"call established" -> {
if (aor == aorSpinner.tag) {
dtmf.setText("")
diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml
index ca2bc3ff..73715109 100644
--- a/app/src/main/res/layout/activity_account.xml
+++ b/app/src/main/res/layout/activity_account.xml
@@ -368,6 +368,21 @@
android:paddingTop="8dp" >
+
+
+
+
+
Valitsee tulevien puheluiden vastaustavan.
Manuaalinen
Automaattinen
+ Uudelleenohjaustapa
+ Valitsee toteutetaanko puhelun uudelleenohjauspyyntö
+ automaattisesti vai kysytäänkö vahvistusta.
Puhepostin URI
SIP URI, jota käytetään
puhepostiviestien kuunteluun. Jos URI:a ei ole annettu, tietoa
@@ -521,6 +524,9 @@
Todennatko SAS:n <%1$s>\?
Siirtopyyntö
Hyväksytkö tämän puhelun siirron kohteeseen \'%1$s\'\?
+ Automaattinen uudelleenohjaus kohteeseen \'%1$s\'\
+ Uudelleenohjauspyyntö
+ Hyväksytkö puhelun uudelleenohjauksen kohteeseen \'%1$s\'\?
Puhelu epäonnistui
Puhelu on päättynyt
Tämä puhelu EI ole turvallinen!
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 46a7b47d..915970b5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -176,6 +176,9 @@
SIP INFO Requests
Answer Mode
Selects how incoming calls are answered.
+ Redirect Mode
+ Selects if call redirect request is followed automatically or
+ if confirmation is requested.
Manual
Automatic
Voicemail URI
@@ -494,6 +497,9 @@
Do you want to verify SAS <%1$s>\?
Transfer Request
Do you accept to transfer this call to \'%1$s\'\?
+ Automatic redirection to \'%1$s\'\
+ Redirect Request
+ Do you accept to call redirection to \'%1$s\'\?
Call failed
Call is closed
This call is NOT secure!