Added limited support for multiple simultaneously active network interfaces

Show notification when baresip is started without network access
This commit is contained in:
Juha Heinanen
2021-10-05 13:52:49 +03:00
parent f042fb9a31
commit 1c3c07186e
9 changed files with 271 additions and 156 deletions
+1
View File
@@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+25 -53
View File
@@ -5,19 +5,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <re.h> #include <re.h>
#include <baresip.h> #include <baresip.h>
#include "logger.h"
#define LOGD(...) \ #define LOG_TAG "Baresip Lib"
if (log_level_get() < LEVEL_INFO) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__))
#define LOGI(...) \
if (log_level_get() < LEVEL_WARN) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__))
#define LOGW(...) \
if (log_level_get() < LEVEL_ERROR) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__))
#define LOGE(...) \
if (log_level_get() <= LEVEL_ERROR) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__))
typedef struct baresip_context { typedef struct baresip_context {
JavaVM *javaVM; JavaVM *javaVM;
@@ -202,6 +192,8 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
len = re_snprintf(event_buf, sizeof event_buf, "call answered", prm); len = re_snprintf(event_buf, sizeof event_buf, "call answered", prm);
break; break;
case UA_EVENT_CALL_LOCAL_SDP: case UA_EVENT_CALL_LOCAL_SDP:
if (strcmp(prm, "offer") == 0)
return;
len = re_snprintf(event_buf, sizeof event_buf, "call %sed", prm); len = re_snprintf(event_buf, sizeof event_buf, "call %sed", prm);
break; break;
case UA_EVENT_CALL_RINGING: case UA_EVENT_CALL_RINGING:
@@ -436,23 +428,12 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_VERSION_1_6; return JNI_VERSION_1_6;
} }
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1add_1address(JNIEnv *env, jobject thiz, jstring javaIp);
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1use_1nameserver(JNIEnv *env, jobject thiz, jstring javaServers);
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instance, Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instance, jstring jPath,
jstring jPath, jstring jIpAddrs, jstring jNetInterface, jint jNetAf, jint jLogLevel) { jstring jAddrs, jint jLogLevel) {
LOGI("starting baresip\n"); LOGI("starting baresip\n");
const char *net_interface = (*env)->GetStringUTFChars(env, jNetInterface, 0);
const int net_af = jNetAf;
const char *ip_addrs = (*env)->GetStringUTFChars(env, jIpAddrs, 0);
char start_error[64] = ""; char start_error[64] = "";
JavaVM *javaVM = g_ctx.javaVM; JavaVM *javaVM = g_ctx.javaVM;
@@ -468,6 +449,7 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
int err; int err;
const char *path = (*env)->GetStringUTFChars(env, jPath, 0); const char *path = (*env)->GetStringUTFChars(env, jPath, 0);
const char *addrs = (*env)->GetStringUTFChars(env, jAddrs, 0);
struct le *le; struct le *le;
runLoggingThread(); runLoggingThread();
@@ -487,15 +469,6 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
goto out; goto out;
} }
if (strlen(net_interface) > 0) {
struct config *theconf = conf_config();
str_ncpy(theconf->net.ifname, net_interface,
sizeof(theconf->net.ifname));
}
if (net_af != AF_UNSPEC)
conf_config()->net.af = net_af;
err = baresip_init(conf_config()); err = baresip_init(conf_config());
if (err) { if (err) {
LOGW("baresip_init() failed (%d)\n", err); LOGW("baresip_init() failed (%d)\n", err);
@@ -503,20 +476,21 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
goto out; goto out;
} }
if (strlen(ip_addrs) > 0) { if (strlen(addrs) > 0) {
char* addr_list = (char*)malloc(strlen(ip_addrs)); char* addr_list = (char*)malloc(strlen(addrs));
struct sa temp_sa; struct sa temp_sa;
char buf[256]; char buf[256];
net_flush_addresses(baresip_network()); net_flush_addresses(baresip_network());
strcpy(addr_list, ip_addrs); strcpy(addr_list, addrs);
char *ptr = strtok(addr_list, ";"); char *ptr = strtok(addr_list, ";");
while (ptr != NULL) { while (ptr != NULL) {
LOGI("adding address '%s'", ptr);
if (0 == sa_set_str(&temp_sa, ptr, 0)) { if (0 == sa_set_str(&temp_sa, ptr, 0)) {
sa_ntop(&temp_sa, buf, 256); sa_ntop(&temp_sa, buf, 256);
net_add_address(baresip_network(), &temp_sa); ptr = strtok(NULL, ";");
net_add_address_ifname(baresip_network(), &temp_sa, ptr);
} else { } else {
LOGE("invalid ip address %s\n", ptr); LOGE("invalid ip address %s\n", ptr);
ptr = strtok(NULL, ";");
res = EAFNOSUPPORT; res = EAFNOSUPPORT;
} }
ptr = strtok(NULL, ";"); ptr = strtok(NULL, ";");
@@ -524,7 +498,7 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
free(addr_list); free(addr_list);
} }
net_debug_log(); // net_debug_log();
play_set_path(baresip_player(), path); play_set_path(baresip_player(), path);
@@ -572,7 +546,6 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
(*env)->DeleteLocalRef(env, javaUA); (*env)->DeleteLocalRef(env, javaUA);
} }
LOGI("allocating mqeue\n");
err = mqueue_alloc(&mq, mqueue_handler, NULL); err = mqueue_alloc(&mq, mqueue_handler, NULL);
if (err) { if (err) {
LOGW("mqueue_alloc failed (%d)\n", err); LOGW("mqueue_alloc failed (%d)\n", err);
@@ -1674,26 +1647,25 @@ Java_com_tutpro_baresip_Api_net_1use_1nameserver(JNIEnv *env, jobject thiz, jstr
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1add_1address(JNIEnv *env, jobject thiz, jstring javaIp) { Java_com_tutpro_baresip_Api_net_1add_1address_1ifname(JNIEnv *env, jobject thiz, jstring jAddr,
const char *native_ip = (*env)->GetStringUTFChars(env, javaIp, 0); jstring jIfName) {
const char *addr = (*env)->GetStringUTFChars(env, jAddr, 0);
const char *name = (*env)->GetStringUTFChars(env, jIfName, 0);
int res = 0; int res = 0;
struct sa temp_sa; struct sa temp_sa;
char buf[256]; char buf[256];
LOGI("adding address '%s'\n", native_ip); LOGD("adding address/ifname '%s/%s'\n", addr, name);
if (str_len(native_ip) == 0) { if (0 == sa_set_str(&temp_sa, addr, 0)) {
(*env)->ReleaseStringUTFChars(env, javaIp, native_ip);
return 0;
}
if (0 == sa_set_str(&temp_sa, native_ip, 0)) {
sa_ntop(&temp_sa, buf, 256); sa_ntop(&temp_sa, buf, 256);
re_thread_enter(); re_thread_enter();
net_add_address(baresip_network(), &temp_sa); res = net_add_address_ifname(baresip_network(), &temp_sa, name);
re_thread_leave(); re_thread_leave();
} else { } else {
LOGE("invalid ip address %s\n", native_ip); LOGE("invalid ip address %s\n", addr);
res = EAFNOSUPPORT; res = EAFNOSUPPORT;
} }
(*env)->ReleaseStringUTFChars(env, javaIp, native_ip); (*env)->ReleaseStringUTFChars(env, jAddr, addr);
(*env)->ReleaseStringUTFChars(env, jIfName, name);
return res; return res;
} }
@@ -1711,7 +1683,7 @@ Java_com_tutpro_baresip_Api_net_1rm_1address(JNIEnv *env, jobject thiz, jstring
if (0 == sa_set_str(&temp_sa, native_ip, 0)) { if (0 == sa_set_str(&temp_sa, native_ip, 0)) {
sa_ntop(&temp_sa, buf, 256); sa_ntop(&temp_sa, buf, 256);
re_thread_enter(); re_thread_enter();
net_rm_address(baresip_network(), &temp_sa); res = net_rm_address(baresip_network(), &temp_sa);
re_thread_leave(); re_thread_leave();
} else { } else {
LOGE("invalid ip address %s\n", native_ip); LOGE("invalid ip address %s\n", native_ip);
@@ -75,7 +75,7 @@ object Api {
external fun log_level_set(level: Int) external fun log_level_set(level: Int)
external fun net_use_nameserver(servers: String): Int external fun net_use_nameserver(servers: String): Int
external fun net_add_address(ip_addr: String): Int external fun net_add_address_ifname(ip_addr: String, if_name: String): Int
external fun net_rm_address(ip_addr: String): Int external fun net_rm_address(ip_addr: String): Int
external fun net_debug() external fun net_debug()
external fun net_dns_debug() external fun net_dns_debug()
@@ -19,6 +19,8 @@ import android.text.SpannableString
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.view.View import android.view.View
import android.widget.RemoteViews import android.widget.RemoteViews
import android.content.Intent
import android.content.BroadcastReceiver
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.annotation.StringRes import androidx.annotation.StringRes
@@ -48,15 +50,18 @@ class BaresipService: Service() {
private lateinit var partialWakeLock: PowerManager.WakeLock private lateinit var partialWakeLock: PowerManager.WakeLock
private lateinit var proximityWakeLock: PowerManager.WakeLock private lateinit var proximityWakeLock: PowerManager.WakeLock
private lateinit var wifiLock: WifiManager.WifiLock private lateinit var wifiLock: WifiManager.WifiLock
private lateinit var br: BroadcastReceiver private lateinit var bluetoothReceiver: BroadcastReceiver
private lateinit var hotSpotReceiver: BroadcastReceiver
private var rtTimer: Timer? = null private var rtTimer: Timer? = null
private var audioFocusRequest: AudioFocusRequest? = null private var audioFocusRequest: AudioFocusRequest? = null
private var audioFocusUsage = -1 private var audioFocusUsage = -1
private var origVolume = -1 private var origVolume = -1
private val btAdapter = BluetoothAdapter.getDefaultAdapter() private val btAdapter = BluetoothAdapter.getDefaultAdapter()
private var linkAddresses = mutableMapOf<String, String>()
private var activeNetwork: Network? = null private var activeNetwork: Network? = null
private var linkAddresses = mutableListOf<LinkAddress>() private var hotSpotIsEnabled = false
private var hotSpotAddresses = mapOf<String, String>()
@SuppressLint("WakelockTimeout") @SuppressLint("WakelockTimeout")
override fun onCreate() { override fun onCreate() {
@@ -102,21 +107,35 @@ class BaresipService: Service() {
override fun onAvailable(network: Network) { override fun onAvailable(network: Network) {
super.onAvailable(network) super.onAvailable(network)
Log.i(TAG, "Network $network is available") Log.d(TAG, "Network $network is available")
updateNetwork() // If API >= 26, this will be followed by onCapabilitiesChanged
if (isServiceRunning && VERSION.SDK_INT < 26)
updateNetwork()
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
Log.d(TAG, "Network $network is losing after $maxMsToLive ms")
} }
override fun onLost(network: Network) { override fun onLost(network: Network) {
super.onLost(network) super.onLost(network)
Log.i(TAG, "Network $network is lost") Log.d(TAG, "Network $network is lost")
if (activeNetwork == network) if (isServiceRunning)
updateNetwork()
}
override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) {
super.onCapabilitiesChanged(network, caps)
Log.d(TAG, "Network $network capabilities changed: $caps")
if (isServiceRunning)
updateNetwork() updateNetwork()
} }
override fun onLinkPropertiesChanged(network: Network, props: LinkProperties) { override fun onLinkPropertiesChanged(network: Network, props: LinkProperties) {
super.onLinkPropertiesChanged(network, props) super.onLinkPropertiesChanged(network, props)
Log.i(TAG, "Network $network link properties changed") Log.d(TAG, "Network $network link properties changed: $props")
if (activeNetwork == network) if (isServiceRunning)
updateNetwork() updateNetwork()
} }
@@ -124,6 +143,55 @@ class BaresipService: Service() {
) )
wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
hotSpotIsEnabled = Utils.isHotSpotOn(wm)
hotSpotReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context, intent: Intent) {
val action = intent.action
if ("android.net.wifi.WIFI_AP_STATE_CHANGED" == action) {
val state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0)
if (WifiManager.WIFI_STATE_ENABLED == state % 10) {
if (hotSpotIsEnabled) {
Log.d(TAG, "HotSpot is still enabled")
} else {
Log.d(TAG, "HotSpot is enabled")
hotSpotIsEnabled = true
Timer().schedule(1000) {
hotSpotAddresses = Utils.hotSpotAddresses()
Log.d(TAG, "HotSpot addresses $hotSpotAddresses")
if (hotSpotAddresses.isNotEmpty()) {
for ((k, v) in hotSpotAddresses)
if (Api.net_add_address_ifname(k, v) != 0)
Log.e(TAG, "Failed to add $v address $k")
Timer().schedule(2000) {
Api.uag_reset_transp(register = true, reinvite = false)
}
} else {
Log.w(TAG, "Could not get hotspot addresses")
}
}
}
} else {
if (!hotSpotIsEnabled) {
Log.d(TAG, "HotSpot is still disabled")
} else {
Log.d(TAG, "HotSpot is disabled")
hotSpotIsEnabled = false
if (hotSpotAddresses.isNotEmpty()) {
for ((k, _) in hotSpotAddresses)
if (Api.net_rm_address(k) != 0)
Log.e(TAG, "Failed to remove address $k")
hotSpotAddresses = mapOf()
Api.uag_reset_transp(register = true, reinvite = false)
}
}
}
}
}
}
this.registerReceiver(hotSpotReceiver,
IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED"))
tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
@@ -133,7 +201,7 @@ class BaresipService: Service() {
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Baresip") wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Baresip")
wifiLock.setReferenceCounted(false) wifiLock.setReferenceCounted(false)
br = object : BroadcastReceiver() { bluetoothReceiver = object : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) { override fun onReceive(ctx: Context, intent: Intent) {
when (intent.action) { when (intent.action) {
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED -> { BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED -> {
@@ -206,7 +274,7 @@ class BaresipService: Service() {
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED) filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)
filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED) filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)
this.registerReceiver(br, filter) this.registerReceiver(bluetoothReceiver, filter)
} }
super.onCreate() super.onCreate()
@@ -230,26 +298,12 @@ class BaresipService: Service() {
"Start" -> { "Start" -> {
var ipAddrs = ""
for (n in cm.allNetworks) {
val props = cm.getLinkProperties(n)
if (props != null) {
for (a in props.linkAddresses)
linkAddresses.add(a)
val addrs = Utils.hostAddresses(props.linkAddresses)
if (addrs != "") {
if (ipAddrs == "")
ipAddrs = addrs
else
ipAddrs += ";$addrs"
}
}
}
updateDnsServers() updateDnsServers()
val assets = arrayOf("accounts", "config", "contacts", "busy.wav", "callwaiting.wav", val assets = arrayOf(
"error.wav", "ringback.wav") "accounts", "config", "contacts", "busy.wav", "callwaiting.wav",
"error.wav", "ringback.wav"
)
var file = File(filesPath) var file = File(filesPath)
if (!file.exists()) { if (!file.exists()) {
Log.d(TAG, "Creating baresip directory") Log.d(TAG, "Creating baresip directory")
@@ -278,13 +332,15 @@ class BaresipService: Service() {
CallHistory.restore() CallHistory.restore()
Message.restore() Message.restore()
if (ipAddrs == "") linkAddresses = linkAddresses()
Log.w(TAG, "Starting baresip without IP addresses") var addrs = ""
for (la in linkAddresses)
addrs = "$addrs;${la.key};${la.value}"
Log.d(TAG, "Link addresses: $addrs")
Thread { Thread {
baresipStart( baresipStart(filesPath, addrs.removePrefix(";"), logLevel)
filesPath, ipAddrs, "", Api.AF_UNSPEC, logLevel
)
}.start() }.start()
isServiceRunning = true isServiceRunning = true
@@ -293,11 +349,22 @@ class BaresipService: Service() {
if (AccountsActivity.noAccounts()) { if (AccountsActivity.noAccounts()) {
val newIntent = Intent(this, MainActivity::class.java) val newIntent = Intent(this, MainActivity::class.java)
newIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP or newIntent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_NEW_TASK
newIntent.putExtra("action", "accounts") newIntent.putExtra("action", "accounts")
startActivity(newIntent) startActivity(newIntent)
} }
if (linkAddresses.isEmpty()) {
val newIntent = Intent(this, MainActivity::class.java)
newIntent.flags =
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_NEW_TASK
newIntent.putExtra("action", "no network")
startActivity(newIntent)
}
} }
"Call Reject" -> { "Call Reject" -> {
@@ -333,8 +400,10 @@ class BaresipService: Service() {
if (ua == null) if (ua == null)
Log.w(TAG, "onStartCommand did not find UA $uap") Log.w(TAG, "onStartCommand did not find UA $uap")
else else
ChatsActivity.saveUaMessage(ua.account.aor, ChatsActivity.saveUaMessage(
intent.getStringExtra("time")!!.toLong()) ua.account.aor,
intent.getStringExtra("time")!!.toLong()
)
nm.cancel(MESSAGE_NOTIFICATION_ID) nm.cancel(MESSAGE_NOTIFICATION_ID)
} }
@@ -344,8 +413,10 @@ class BaresipService: Service() {
if (ua == null) if (ua == null)
Log.w(TAG, "onStartCommand did not find UA $uap") Log.w(TAG, "onStartCommand did not find UA $uap")
else else
ChatsActivity.deleteUaMessage(ua.account.aor, ChatsActivity.deleteUaMessage(
intent.getStringExtra("time")!!.toLong()) ua.account.aor,
intent.getStringExtra("time")!!.toLong()
)
nm.cancel(MESSAGE_NOTIFICATION_ID) nm.cancel(MESSAGE_NOTIFICATION_ID)
} }
@@ -376,7 +447,8 @@ class BaresipService: Service() {
override fun onDestroy() { override fun onDestroy() {
Log.d(TAG, "At Baresip Service onDestroy") Log.d(TAG, "At Baresip Service onDestroy")
super.onDestroy() super.onDestroy()
this.unregisterReceiver(br) this.unregisterReceiver(bluetoothReceiver)
this.unregisterReceiver(hotSpotReceiver)
if (am.isBluetoothScoOn) am.stopBluetoothSco() if (am.isBluetoothScoOn) am.stopBluetoothSco()
cleanService() cleanService()
if (isServiceRunning) { if (isServiceRunning) {
@@ -847,6 +919,7 @@ class BaresipService: Service() {
@Keep @Keep
fun started() { fun started() {
Log.d(TAG, "Received 'started' from baresip") Log.d(TAG, "Received 'started' from baresip")
Api.net_debug()
val intent = Intent("service event") val intent = Intent("service event")
intent.putExtra("event", "started") intent.putExtra("event", "started")
intent.putExtra("params", arrayListOf(callActionUri)) intent.putExtra("params", arrayListOf(callActionUri))
@@ -1084,56 +1157,87 @@ class BaresipService: Service() {
} }
private fun updateNetwork() { private fun updateNetwork() {
if (!isServiceRunning)
return
/* for (n in cm.allNetworks) /* for (n in cm.allNetworks)
Log.i(TAG, "NETWORK $n with caps ${cm.getNetworkCapabilities(n)} and props " + Log.d(TAG, "NETWORK $n with caps ${cm.getNetworkCapabilities(n)} and props " +
"${cm.getLinkProperties(n)} is active ${isNetworkActive(n)}") */ "${cm.getLinkProperties(n)} is active ${isNetworkActive(n)}") */
activeNetwork = activeNetwork()
updateDnsServers()
val lnAddrs = linkAddresses()
Log.d(TAG, "Old/new link addresses $linkAddresses/$lnAddrs")
var added = 0
for (a in lnAddrs)
if (!linkAddresses.containsKey(a.key)) {
if (Api.net_add_address_ifname(a.key, a.value) != 0)
Log.e(TAG, "Failed to add address: $a")
else
added++
}
var removed = 0
for (a in linkAddresses)
if (!lnAddrs.containsKey(a.key)) {
if (Api.net_rm_address(a.key) != 0)
Log.e(TAG, "Failed to remove address: $a")
else
removed++
}
val active = activeNetwork()
Log.d(TAG, "Added/Removed/Active = $added/$removed/$active")
if (added > 0 || removed > 0 || active != activeNetwork) {
linkAddresses = lnAddrs
activeNetwork = active
Api.uag_reset_transp(register = true, reinvite = true)
}
Api.net_debug()
if (activeNetwork != null) { if (activeNetwork != null) {
val linkCaps = cm.getNetworkCapabilities(activeNetwork) val caps = cm.getNetworkCapabilities(activeNetwork)
val linkProps = cm.getLinkProperties(activeNetwork) if (caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "Using active network $activeNetwork with caps: $linkCaps, props: $linkProps")
val lnAddrs = mutableListOf<LinkAddress>()
for (n in cm.allNetworks) {
val props = cm.getLinkProperties(n)
if (props != null)
for (a in props.linkAddresses)
lnAddrs.add(a)
}
var addrUpdate = false
for (a in lnAddrs)
if (!linkAddresses.contains(a)) {
Api.net_add_address(a.address.hostAddress)
addrUpdate = true
}
for (a in linkAddresses)
if (!lnAddrs.contains(a)) {
Api.net_rm_address(a.address.hostAddress)
addrUpdate = true
}
val dnsUpdate = updateDnsServers()
if (addrUpdate) {
linkAddresses = lnAddrs
Api.uag_reset_transp(register = true, reinvite = true)
} else {
if (dnsUpdate)
UserAgent.register()
}
if (linkCaps != null && linkCaps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "Acquiring WiFi Lock") Log.d(TAG, "Acquiring WiFi Lock")
wifiLock.acquire() wifiLock.acquire()
} else { return
Log.d(TAG, "Releasing WiFi Lock")
wifiLock.release()
} }
} else }
Log.w(TAG, "No active network") Log.d(TAG, "Releasing WiFi Lock")
wifiLock.release()
} }
private fun updateDnsServers(): Boolean { private fun linkAddresses(): MutableMap<String, String> {
val lnAddrs = mutableMapOf<String, String>()
for (n in cm.allNetworks) {
val caps = cm.getNetworkCapabilities(n) ?: continue
if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND) ||
VERSION.SDK_INT < 28) {
val props = cm.getLinkProperties(n) ?: continue
for (la in props.linkAddresses)
if (la.scope == android.system.OsConstants.RT_SCOPE_UNIVERSE &&
props.interfaceName != null)
lnAddrs[la.address.hostAddress] = props.interfaceName!!
}
}
if (hotSpotIsEnabled) {
hotSpotAddresses = Utils.hotSpotAddresses()
Log.d(TAG, "HotSpot addresses $hotSpotAddresses")
for ((k, v) in hotSpotAddresses)
lnAddrs[k] = v
}
return lnAddrs
}
private fun updateDnsServers() {
if (isServiceRunning && !dynDns) if (isServiceRunning && !dynDns)
return false return
val servers = mutableListOf<InetAddress>() val servers = mutableListOf<InetAddress>()
// Use DNS servers first from active network (if given) // Use DNS servers first from active network (if available)
for (n in cm.allNetworks) for (n in cm.allNetworks)
if (isNetworkActive(n)) { if (isNetworkActive(n)) {
val linkProps = cm.getLinkProperties(n) val linkProps = cm.getLinkProperties(n)
@@ -1157,10 +1261,8 @@ class BaresipService: Service() {
} else { } else {
// Log.d(TAG, "Updated DNS servers: '${servers}'") // Log.d(TAG, "Updated DNS servers: '${servers}'")
dnsServers = servers dnsServers = servers
return true
} }
} }
return false
} }
private fun activeNetwork(): Network? { private fun activeNetwork(): Network? {
@@ -1200,8 +1302,7 @@ class BaresipService: Service() {
isServiceClean = true isServiceClean = true
} }
private external fun baresipStart(path: String, ipAddrs: String, netInterface: String, private external fun baresipStart(path: String, addrs: String, logLevel: Int)
netAf: Int, logLevel: Int)
private external fun baresipStop(force: Boolean) private external fun baresipStop(force: Boolean)
companion object { companion object {
@@ -1,7 +1,6 @@
package com.tutpro.baresip package com.tutpro.baresip
import android.content.Context import android.content.Context
import java.net.InetAddress import java.net.InetAddress
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -21,6 +21,8 @@ import android.text.TextWatcher
import android.view.* import android.view.*
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.* import android.widget.*
import android.content.Intent
import android.content.BroadcastReceiver
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
@@ -330,8 +332,12 @@ class MainActivity : AppCompatActivity() {
} else { } else {
val latest = CallHistory.aorLatestHistory(aor) val latest = CallHistory.aorLatestHistory(aor)
if (latest != null) if (latest != null)
callUri.setText(Utils.friendlyUri(ContactsActivity.contactName(latest.peerUri), callUri.setText(
Utils.aorDomain(ua.account.aor))) Utils.friendlyUri(
ContactsActivity.contactName(latest.peerUri),
Utils.aorDomain(ua.account.aor)
)
)
} }
} }
} }
@@ -707,8 +713,14 @@ class MainActivity : AppCompatActivity() {
"accounts" -> { "accounts" -> {
resumeAction = "accounts" resumeAction = "accounts"
} }
"no network" -> {
Utils.alertView(this, getString(R.string.notice),
getString(R.string.no_network))
return
}
"call" -> { "call" -> {
if (Call.calls().isNotEmpty()) { if (Call.calls().isNotEmpty()) {
Toast.makeText(applicationContext, getString(R.string.call_already_active), Toast.makeText(applicationContext, getString(R.string.call_already_active),
Toast.LENGTH_SHORT).show() Toast.LENGTH_SHORT).show()
return return
+43 -15
View File
@@ -10,6 +10,7 @@ import android.graphics.Bitmap
import android.graphics.Bitmap.createScaledBitmap import android.graphics.Bitmap.createScaledBitmap
import android.graphics.Color import android.graphics.Color
import android.net.* import android.net.*
import android.net.wifi.WifiManager
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.DocumentsContract import android.provider.DocumentsContract
@@ -24,20 +25,21 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import java.io.* import java.io.*
import java.lang.reflect.Method
import java.security.SecureRandom import java.security.SecureRandom
import java.util.* import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
object Utils { object Utils {
@@ -106,10 +108,14 @@ object Utils {
var u = uri var u = uri
if (uri.startsWith("<") && (uri.endsWith(">"))) if (uri.startsWith("<") && (uri.endsWith(">")))
u = uri.substring(1).substringBeforeLast(">") u = uri.substring(1).substringBeforeLast(">")
u = u.replace(":5060", "")
u = u.replace(";transport=udp", "", true)
if (u.split(":").size == 3 || uriParams(u).isNotEmpty())
return u
return if (u.contains("@")) { return if (u.contains("@")) {
val user = uriUserPart(u) val user = uriUserPart(u)
val host = uriHostPart(u) val host = uriHostPart(u)
if (isE164Number(user) || (host == domain)) if (isE164Number(user) || host == domain)
user user
else else
"$user@$host" "$user@$host"
@@ -277,17 +283,6 @@ object Utils {
return true return true
} }
fun hostAddresses(list: List<LinkAddress>?): String {
var result = ""
if (list != null) for (la in list)
if (la.scope == android.system.OsConstants.RT_SCOPE_UNIVERSE)
if (result == "")
result = la.address.hostAddress
else
result += ";" + la.address.hostAddress
return result
}
fun implode(list: List<String>, sep: String): String { fun implode(list: List<String>, sep: String): String {
var res = "" var res = ""
for (s in list) { for (s in list) {
@@ -305,6 +300,39 @@ object Utils {
return appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND return appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
} }
fun isHotSpotOn(wm: WifiManager): Boolean {
try {
val method: Method = wm.javaClass.getDeclaredMethod("isWifiApEnabled")
method.isAccessible = true
return method.invoke(wm) as Boolean
} catch (ignored: Throwable) {
}
return false
}
fun hotSpotAddresses(): Map<String, String> {
val result = mutableMapOf<String, String>()
try {
val interfaces: Enumeration<NetworkInterface> = NetworkInterface.getNetworkInterfaces()
while (interfaces.hasMoreElements()) {
val iface: NetworkInterface = interfaces.nextElement()
val ifName = iface.name
if (ifName.startsWith("ap") || ifName.startsWith("wlan")) {
val addresses: Enumeration<InetAddress> = iface.inetAddresses
while (addresses.hasMoreElements()) {
val inetAddress: InetAddress = addresses.nextElement()
if (!inetAddress.isLoopbackAddress && !inetAddress.isLinkLocalAddress)
result[inetAddress.hostAddress] = ifName
}
if (result.isNotEmpty()) return result
}
}
} catch (ex: SocketException) {
Log.e(TAG, ex.toString())
}
return result
}
fun dtmfWatcher(callp: String): TextWatcher { fun dtmfWatcher(callp: String): TextWatcher {
return object : TextWatcher { return object : TextWatcher {
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
+1
View File
@@ -495,4 +495,5 @@
</string> </string>
<string name="no_cameras">Sinulla ei ole yhtään tuettua video-kameraa.</string> <string name="no_cameras">Sinulla ei ole yhtään tuettua video-kameraa.</string>
<string name="show_password">Näytä salasana</string> <string name="show_password">Näytä salasana</string>
<string name="no_network">Ei verkkoyhteyttä!</string>
</resources> </resources>
+1
View File
@@ -448,4 +448,5 @@
<string name="no_video_calls">Grant \"Camera\" permission to place or answer video calls.</string> <string name="no_video_calls">Grant \"Camera\" permission to place or answer video calls.</string>
<string name="no_cameras">You don\'t have any supported video cameras.</string> <string name="no_cameras">You don\'t have any supported video cameras.</string>
<string name="show_password">Show Password</string> <string name="show_password">Show Password</string>
<string name="no_network">No network connection!</string>
</resources> </resources>