Resolved telecom framework conflicts
Cleaned thread handling More synchonizations
This commit is contained in:
@ -7,11 +7,6 @@
|
||||
#include <baresip.h>
|
||||
#include "logger.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ASYNC_WORKERS = 4
|
||||
};
|
||||
|
||||
typedef struct baresip_context
|
||||
{
|
||||
JavaVM *javaVM;
|
||||
@ -22,6 +17,36 @@ typedef struct baresip_context
|
||||
|
||||
BaresipContext g_ctx;
|
||||
|
||||
enum
|
||||
{
|
||||
ASYNC_WORKERS = 4
|
||||
};
|
||||
|
||||
static pthread_key_t g_thread_key;
|
||||
|
||||
static void detach_thread(void *env)
|
||||
{
|
||||
(void)env;
|
||||
LOGD("detaching thread from JVM\n");
|
||||
(*g_ctx.javaVM)->DetachCurrentThread(g_ctx.javaVM);
|
||||
}
|
||||
|
||||
static JNIEnv *get_jni_env(void)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jint res = (*g_ctx.javaVM)->GetEnv(g_ctx.javaVM, (void**)&env, JNI_VERSION_1_6);
|
||||
if (res != JNI_OK) {
|
||||
res = (*g_ctx.javaVM)->AttachCurrentThread(g_ctx.javaVM, &env, NULL);
|
||||
if (res == JNI_OK) {
|
||||
pthread_setspecific(g_thread_key, env);
|
||||
} else {
|
||||
LOGE("failed to AttachCurrentThread, ErrorCode = %d\n", res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static int vprintf_null(const char *p, size_t size, void *arg)
|
||||
{
|
||||
(void)p;
|
||||
@ -257,23 +282,23 @@ static void event_handler(enum bevent_ev ev, struct bevent *event, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
JavaVM *javaVM = g_ctx.javaVM;
|
||||
JNIEnv *env;
|
||||
jint res = (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6);
|
||||
if (res != JNI_OK) {
|
||||
LOGD("failed to get javaVM environment, ErrorCode = %d\n", res);
|
||||
res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
|
||||
if (JNI_OK != res) {
|
||||
LOGE("failed to AttachCurrentThread, ErrorCode = %d\n", res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
JNIEnv *env = get_jni_env();
|
||||
if (!env) return;
|
||||
|
||||
if (!g_ctx.mainActivityClz || !g_ctx.mainActivityObj) return;
|
||||
|
||||
jmethodID methodId =
|
||||
(*env)->GetMethodID(env, g_ctx.mainActivityClz, "uaEvent", "(Ljava/lang/String;JJ)V");
|
||||
jstring jEvent = (*env)->NewStringUTF(env, event_buf);
|
||||
LOGD("sending ua/call %ld/%ld event %s\n", (long)ua, (long)call, event_buf);
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, jEvent, (jlong)ua, (jlong)call);
|
||||
if (methodId) {
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, jEvent, (jlong)ua, (jlong)call);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE("uaEvent method call failed\n");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jEvent);
|
||||
|
||||
}
|
||||
@ -291,16 +316,10 @@ static void message_handler(
|
||||
return;
|
||||
}
|
||||
|
||||
JavaVM *javaVM = g_ctx.javaVM;
|
||||
JNIEnv *env;
|
||||
jint res = (*javaVM)->GetEnv(javaVM, (void **)&env, JNI_VERSION_1_6);
|
||||
if (res != JNI_OK) {
|
||||
res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
|
||||
if (JNI_OK != res) {
|
||||
LOGE("failed to AttachCurrentThread, ErrorCode = %d\n", res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
JNIEnv *env = get_jni_env();
|
||||
if (!env) return;
|
||||
|
||||
if (!g_ctx.mainActivityClz || !g_ctx.mainActivityObj) return;
|
||||
|
||||
jmethodID methodId = (*env)->GetMethodID(env, g_ctx.mainActivityClz, "messageEvent",
|
||||
"(JLjava/lang/String;Ljava/lang/String;[B)V");
|
||||
@ -319,7 +338,14 @@ static void message_handler(
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, jMsg, temp, 0);
|
||||
LOGD("sending message %ld/%s/%s/%.*s\n", (long)ua, peer_buf, ctype_buf, (int)size,
|
||||
mbuf_buf(body));
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, (jlong)ua, jPeer, jCtype, jMsg);
|
||||
if (methodId) {
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, (jlong)ua, jPeer, jCtype, jMsg);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE("messageEvent method call failed\n");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jCtype);
|
||||
(*env)->DeleteLocalRef(env, jPeer);
|
||||
(*env)->DeleteLocalRef(env, jMsg);
|
||||
@ -341,24 +367,30 @@ static void send_resp_handler(int err, const struct sip_msg *msg, void *arg)
|
||||
LOGD("send_response_handler received response '%u %s' at %s\n", msg->scode, reason_buf,
|
||||
native_time);
|
||||
|
||||
JavaVM *javaVM = g_ctx.javaVM;
|
||||
JNIEnv *env;
|
||||
jint res = (*javaVM)->GetEnv(javaVM, (void **)&env, JNI_VERSION_1_6);
|
||||
if (res != JNI_OK) {
|
||||
res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
|
||||
if (JNI_OK != res) {
|
||||
LOGE("failed to AttachCurrentThread, ErrorCode = %d\n", res);
|
||||
mem_deref(native_time);
|
||||
return;
|
||||
}
|
||||
JNIEnv *env = get_jni_env();
|
||||
if (!env) {
|
||||
mem_deref(native_time);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_ctx.mainActivityClz || !g_ctx.mainActivityObj) {
|
||||
mem_deref(native_time);
|
||||
return;
|
||||
}
|
||||
|
||||
jmethodID methodId = (*env)->GetMethodID(env, g_ctx.mainActivityClz, "messageResponse",
|
||||
"(ILjava/lang/String;Ljava/lang/String;)V");
|
||||
jstring javaReason = (*env)->NewStringUTF(env, reason_buf);
|
||||
jstring javaTime = (*env)->NewStringUTF(env, native_time);
|
||||
if (methodId)
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, msg->scode, javaReason, javaTime);
|
||||
if (methodId) {
|
||||
(*env)->CallVoidMethod(env, g_ctx.mainActivityObj, methodId, msg->scode, javaReason,
|
||||
javaTime);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE("uaEvent messageResponse method call failed\n");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, javaReason);
|
||||
(*env)->DeleteLocalRef(env, javaTime);
|
||||
|
||||
@ -435,6 +467,10 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
g_ctx.mainActivityClz = NULL;
|
||||
g_ctx.mainActivityObj = NULL;
|
||||
|
||||
if (pthread_key_create(&g_thread_key, detach_thread) != 0) {
|
||||
LOGE("failed to create pthread key\n");
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ import android.os.VibratorManager
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.Settings
|
||||
import android.system.OsConstants
|
||||
import android.telecom.Connection
|
||||
import android.telecom.DisconnectCause
|
||||
import android.telecom.PhoneAccountHandle
|
||||
import android.telecom.TelecomManager
|
||||
@ -1003,10 +1004,14 @@ class BaresipService: Service() {
|
||||
stopMediaPlayer()
|
||||
ConnectionService.connections[callp]?.setActive()
|
||||
ensureCommunicationMode()
|
||||
if (call!!.status.value == "incoming")
|
||||
call.status.value = "answered"
|
||||
else
|
||||
return
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (call != null) {
|
||||
if (call.status.value == "incoming")
|
||||
call.status.value = "answered"
|
||||
else
|
||||
return@post
|
||||
}
|
||||
}
|
||||
}
|
||||
"call redirect" -> {
|
||||
stopMediaPlayer()
|
||||
@ -1016,64 +1021,85 @@ class BaresipService: Service() {
|
||||
stopMediaPlayer()
|
||||
nm.cancel(CALL_NOTIFICATION_ID)
|
||||
Log.d(TAG, "AoR $aor call $callp established")
|
||||
call!!.status.value = "connected"
|
||||
call.onhold = false
|
||||
call.startTime = GregorianCalendar()
|
||||
updateStatusNotification()
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (call != null) {
|
||||
call.status.value = "connected"
|
||||
call.onhold = false
|
||||
call.startTime = GregorianCalendar()
|
||||
if (call.conferenceCall)
|
||||
Api.cmd_exec("conference")
|
||||
}
|
||||
updateStatusNotification()
|
||||
proximitySensing(proximitySensing)
|
||||
}
|
||||
if (!isMainVisible)
|
||||
return
|
||||
}
|
||||
"call update" -> {
|
||||
val newHeldState = when (ev[1].toInt()) {Api.SDP_INACTIVE, Api.SDP_RECVONLY -> true
|
||||
val newHeldState = when (ev[1].toInt()) {
|
||||
Api.SDP_INACTIVE, Api.SDP_RECVONLY -> true
|
||||
else -> false
|
||||
}
|
||||
val connection = ConnectionService.connections[callp]
|
||||
if (call!!.held && !newHeldState) {
|
||||
Log.d(TAG, "Call ${call.callp} un-held by peer.")
|
||||
call.onhold = false
|
||||
// Use a Coroutine with a small delay to let the SIP
|
||||
// transaction (the re-INVITE from the peer) finish
|
||||
// before trying to hold the other call and resume this one.
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
delay(100)
|
||||
call.resume()
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (call != null) {
|
||||
if (call.held && !newHeldState) {
|
||||
Log.d(TAG, "Call ${call.callp} un-held by peer.")
|
||||
call.onhold = false
|
||||
// Use a Coroutine with a small delay to let the SIP
|
||||
// transaction (the re-INVITE from the peer) finish
|
||||
// before trying to hold the other call and resume this one.
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
delay(100)
|
||||
call.resume()
|
||||
}
|
||||
}
|
||||
call.held = newHeldState
|
||||
if (newHeldState) {
|
||||
// Peer put us on hold
|
||||
call.showOnHoldNotice.value = true
|
||||
call.callOnHold.value = true
|
||||
if (connection?.state != Connection.STATE_HOLDING)
|
||||
connection?.setOnHold()
|
||||
} else {
|
||||
// Peer un-held us
|
||||
call.showOnHoldNotice.value = false
|
||||
if (!call.onhold) {
|
||||
call.callOnHold.value = false
|
||||
if (connection?.state != Connection.STATE_ACTIVE)
|
||||
connection?.setActive()
|
||||
}
|
||||
}
|
||||
if (call.state() == Api.CALL_STATE_EARLY) {
|
||||
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
||||
stopMediaPlayer()
|
||||
}
|
||||
if (call.status.value == "connected" && !call.held && !call.onhold) {
|
||||
if (call.callOnHold.value || call.showOnHoldNotice.value) {
|
||||
Log.d(
|
||||
TAG,
|
||||
"Safety guard: Clearing stuck hold flags for ${call.callp}"
|
||||
)
|
||||
call.callOnHold.value = false
|
||||
call.showOnHoldNotice.value = false
|
||||
connection?.setActive()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
call.held = newHeldState
|
||||
if (newHeldState) {
|
||||
// Peer put us on hold
|
||||
call.showOnHoldNotice.value = true
|
||||
call.callOnHold.value = true
|
||||
connection?.setOnHold()
|
||||
} else {
|
||||
// Peer un-held us
|
||||
call.showOnHoldNotice.value = false
|
||||
if (!call.onhold) {
|
||||
call.callOnHold.value = false
|
||||
connection?.setActive()
|
||||
}
|
||||
}
|
||||
if (call.state() == Api.CALL_STATE_EARLY) {
|
||||
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
||||
stopMediaPlayer()
|
||||
}
|
||||
if (call.status.value == "connected" && !call.held && !call.onhold) {
|
||||
if (call.callOnHold.value || call.showOnHoldNotice.value) {
|
||||
Log.d(TAG, "Safety guard: Clearing stuck hold flags for ${call.callp}")
|
||||
call.callOnHold.value = false
|
||||
call.showOnHoldNotice.value = false
|
||||
connection?.setActive()
|
||||
}
|
||||
}
|
||||
if (!isMainVisible || call.status.value != "connected")
|
||||
if (!isMainVisible || call?.status?.value != "connected")
|
||||
return
|
||||
}
|
||||
"call verified", "call secure" -> {
|
||||
if (ev[0] == "call secure") {
|
||||
call!!.security = R.color.colorTrafficYellow
|
||||
} else {
|
||||
call!!.security = R.color.colorTrafficGreen
|
||||
call.zid = ev[1]
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (call != null) {
|
||||
if (ev[0] == "call secure") {
|
||||
call.security = R.color.colorTrafficYellow
|
||||
} else {
|
||||
call.security = R.color.colorTrafficGreen
|
||||
call.zid = ev[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isMainVisible)
|
||||
return
|
||||
@ -1147,7 +1173,6 @@ class BaresipService: Service() {
|
||||
else -> DisconnectCause.REMOTE
|
||||
}
|
||||
connection.setDisconnected(DisconnectCause(cause))
|
||||
connection.destroy()
|
||||
ConnectionService.connections.remove(callp)
|
||||
}
|
||||
if (call != null) {
|
||||
@ -2661,13 +2686,15 @@ class BaresipService: Service() {
|
||||
if (!servers.contains(server)) servers.add(server)
|
||||
}
|
||||
// Update if change
|
||||
if (servers != dnsServers) {
|
||||
if (isServiceRunning && Config.updateDnsServers(servers) != 0) {
|
||||
Log.w(TAG, "Failed to update DNS servers '${servers}'")
|
||||
} else {
|
||||
// Log.d(TAG, "Updated DNS servers: '${servers}'")
|
||||
dnsServers = servers
|
||||
return true
|
||||
synchronized(dnsServers) {
|
||||
if (servers != dnsServers) {
|
||||
if (isServiceRunning && Config.updateDnsServers(servers) != 0) {
|
||||
Log.w(TAG, "Failed to update DNS servers '${servers}'")
|
||||
} else {
|
||||
// Log.d(TAG, "Updated DNS servers: '${servers}'")
|
||||
dnsServers = servers
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@ -33,7 +33,6 @@ class ConnectionService : ConnectionService() {
|
||||
fun onCallClosed(callp: Long) {
|
||||
connections[callp]?.let {
|
||||
it.setDisconnected(DisconnectCause(DisconnectCause.REMOTE))
|
||||
it.destroy()
|
||||
connections.remove(callp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2427,10 +2427,14 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
|
||||
when (ev[0]) {
|
||||
"call rejected" -> {
|
||||
if (aor == viewModel.selectedAor.value)
|
||||
viewModel.triggerAccountUpdate()
|
||||
}
|
||||
"call incoming", "call outgoing" -> {
|
||||
"call outgoing" -> {
|
||||
val callp = params[1] as Long
|
||||
if (!BaresipService.isMainVisible)
|
||||
viewModel.navigateToHome()
|
||||
spinToAor(viewModel, aor, Call.ofCallp(callp))
|
||||
}
|
||||
"call incoming" -> {
|
||||
val callp = params[1] as Long
|
||||
if (!BaresipService.isMainVisible)
|
||||
viewModel.navigateToHome()
|
||||
@ -2464,7 +2468,6 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
}
|
||||
showDialog.value = true
|
||||
}
|
||||
viewModel.triggerAccountUpdate()
|
||||
}
|
||||
"call established" -> {
|
||||
(ctx as? Activity)?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
@ -2472,16 +2475,11 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
viewModel.dialerState.callButtonsEnabled.value = true // Re-enable dialer
|
||||
val callp = params[1] as Long
|
||||
val call = Call.ofCallp(callp)
|
||||
if (call != null) {
|
||||
if (call != null)
|
||||
call.dtmfText.value = ""
|
||||
if (call.conferenceCall)
|
||||
Api.cmd_exec("conference")
|
||||
}
|
||||
viewModel.triggerAccountUpdate(call)
|
||||
}
|
||||
}
|
||||
"call update" -> {
|
||||
viewModel.triggerAccountUpdate()
|
||||
}
|
||||
"call verify" -> {
|
||||
val callp = params[1] as Long
|
||||
@ -2524,7 +2522,6 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
}
|
||||
if (aor == viewModel.selectedAor.value) {
|
||||
call.securityIconTint.value = call.security
|
||||
viewModel.triggerAccountUpdate(call)
|
||||
}
|
||||
}
|
||||
"call transfer", "transfer show" -> {
|
||||
@ -2568,9 +2565,10 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
showCall(ctx, viewModel, ua)
|
||||
}
|
||||
"call closed" -> {
|
||||
if (Call.calls().isEmpty())
|
||||
val calls = Call.calls()
|
||||
if (calls.isEmpty())
|
||||
(ctx as? Activity)?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
viewModel.updateCalls(Call.calls().toList())
|
||||
viewModel.updateCalls(calls.toList())
|
||||
val activity = ctx as? Activity
|
||||
if (activity != null) {
|
||||
val kgm = activity.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||
@ -2583,8 +2581,6 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
viewModel.dialerState.callButtonsEnabled.value = true
|
||||
ua.account.resumeUri = ""
|
||||
viewModel.triggerAccountUpdate()
|
||||
if (acc.missedCalls)
|
||||
viewModel.triggerAccountUpdate()
|
||||
}
|
||||
}
|
||||
"message", "message show", "message reply" -> {
|
||||
@ -2602,13 +2598,12 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
||||
break
|
||||
}
|
||||
}
|
||||
if (aor == viewModel.selectedAor.value)
|
||||
viewModel.triggerAccountUpdate()
|
||||
}
|
||||
else -> Log.e(TAG, "Unknown event '${ev[0]}'")
|
||||
}
|
||||
|
||||
viewModel.updateCalls(Call.calls().toList())
|
||||
viewModel.triggerAccountUpdate()
|
||||
handleNextEvent()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user