From 9f94e72b1e42d8c671130e640c8f40166ac6325b Mon Sep 17 00:00:00 2001 From: jamie prince Date: Wed, 19 Aug 2026 03:22:05 +0100 Subject: [PATCH] Add Wear OS SIP client module running baresip NDK stack - New :wear application module (Wear Compose, minSdk 30) - Second JNI lib 'wearbaresip' reusing distribution static libs - Watch-side service initializes baresip via full init path (libre_init -> conf_configure -> baresip_init -> ua_init) - FGS started from MainActivity foreground state with mic type only (phoneCall requires default-dialer, rejected on watch) - Runtime-verified: builds, installs, native lib loads and SIP stack starts on armeabi-v7a Wear OS device --- .agentbridge/conversation.db | Bin 4096 -> 253952 bytes .agentbridge/conversation.db-shm | Bin 32768 -> 0 bytes .agentbridge/conversation.db-wal | Bin 696312 -> 0 bytes .gitignore | 2 + gradle/libs.versions.toml | 8 + settings.gradle.kts | 7 +- wear/build.gradle.kts | 52 ++ wear/src/main/AndroidManifest.xml | 41 ++ wear/src/main/cpp/CMakeLists.txt | 98 ++++ wear/src/main/cpp/baresip.c | 466 ++++++++++++++++++ wear/src/main/cpp/logger.h | 13 + .../com/tutpro/baresip/wear/MainActivity.kt | 49 ++ .../com/tutpro/baresip/wear/WearBaresipApp.kt | 10 + .../tutpro/baresip/wear/WearBaresipService.kt | 65 +++ 14 files changed, 806 insertions(+), 5 deletions(-) delete mode 100644 .agentbridge/conversation.db-shm delete mode 100644 .agentbridge/conversation.db-wal create mode 100644 wear/build.gradle.kts create mode 100644 wear/src/main/AndroidManifest.xml create mode 100644 wear/src/main/cpp/CMakeLists.txt create mode 100644 wear/src/main/cpp/baresip.c create mode 100644 wear/src/main/cpp/logger.h create mode 100644 wear/src/main/java/com/tutpro/baresip/wear/MainActivity.kt create mode 100644 wear/src/main/java/com/tutpro/baresip/wear/WearBaresipApp.kt create mode 100644 wear/src/main/java/com/tutpro/baresip/wear/WearBaresipService.kt diff --git a/.agentbridge/conversation.db b/.agentbridge/conversation.db index 4d0f4d75c0c482c3485d3529b474a8f56497a2ca..f5c01f757bde0494417984b0a3106532c200f389 100644 GIT binary patch literal 253952 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 delta 26 gcmZoTz~7)SL7J73fq{W>;zD~ML$CMuCWSft09~vHOaK4? diff --git a/.agentbridge/conversation.db-shm b/.agentbridge/conversation.db-shm deleted file mode 100644 index 63921544e0e29120cea716a3059b9dc058a2a966..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI5M^9Bz6onTkh++W?qF4YG3yOdU7VN$E-h0K~3-;c7?|o+c1O5gF#*q^fM-H4i z)4j>La$+L64%D;BTFGVa^Ui(me(%d;x=-e(9?+D^l>nr@k~&bXq>8UyUw`;KE${97 z{GpX!l0H_xne**kX;J1M-Y*|jm6!7OyBGKJ&mzx8qFh?*$W_<%Nv^j_SL?gl zz|~Z#4PD>J)y7hrxIWF*bXS|Y+DvM5*SC>Q3mF3o2+jxCjuWu)P zdvBdBeU7)zmA-?w?&$TMygtwM`fPn(XK$~I*Q+<(?3+UXe3i2(q#%nhD<5QlBo#o zk&8|;O`!)0W$r+k%nKNVp%{VD7>`Mqf*F{P#aNEjSc~=8gss?t-Pn(VID+FigG;!I z8@P@8c!Z~T9tWnzd$!lO%gt&7d6)k}82HIN9M_F^HsEIm18i5VI;<40w!ZB=3pU~VkOpK9V)OH+prURQHeu1ijz1O0QVGh1$p|8<+u57GoY3VHs9oV*oTEBj|iw8#!$QGXP4Rfy=}(pwpmj zI0p1o7aO^512X_hJ(Y!tV?fXPv5{LgFaw|*5&(k@1U=cx zM(*0c41jWY01P$|^c*)Exn~120LoDTFxWuQ6AEqQp$*IcD8~iBU;{zVAhnSvHZTLA uoEQLu4TNkPm_n&%BQtRfOp9|9?-2tzv{35|Os{p{=x==?Jz1TJW8eoHxNx5U diff --git a/.agentbridge/conversation.db-wal b/.agentbridge/conversation.db-wal deleted file mode 100644 index b205380ce316ee028120c058404c7491ead83af5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696312 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 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wear/src/main/cpp/CMakeLists.txt b/wear/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000..4c04408e --- /dev/null +++ b/wear/src/main/cpp/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 3.18...4.0) + +project(baresip-wear) + +add_link_options("LINKER:--build-id=none") + +set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution) + +add_library(lib_crypto STATIC IMPORTED) +set_target_properties(lib_crypto PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a) + +add_library(lib_ssl STATIC IMPORTED) +set_target_properties(lib_ssl PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a) + +add_library(lib_re STATIC IMPORTED) +set_target_properties(lib_re PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/re/lib/${ANDROID_ABI}/libre.a) + +add_library(lib_opus STATIC IMPORTED) +set_target_properties(lib_opus PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/opus/lib/${ANDROID_ABI}/libopus.a) + +add_library(lib_g722 STATIC IMPORTED) +set_target_properties(lib_g722 PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/g722/lib/${ANDROID_ABI}/libg722.a) + +add_library(lib_g722_1 STATIC IMPORTED) +set_target_properties(lib_g722_1 PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/g7221/lib/${ANDROID_ABI}/libg722_1.a) + +add_library(lib_g729 STATIC IMPORTED) +set_target_properties(lib_g729 PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/g729/lib/${ANDROID_ABI}/libbcg729.a) + +add_library(lib_ilbc STATIC IMPORTED) +set_target_properties(lib_ilbc PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/ilbc/lib/${ANDROID_ABI}/libilbc.a) + +add_library(lib_codec2 STATIC IMPORTED) +set_target_properties(lib_codec2 PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/codec2/lib/${ANDROID_ABI}/libcodec2.a) + +add_library(lib_amrnb STATIC IMPORTED) +set_target_properties(lib_amrnb PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/amr/lib/${ANDROID_ABI}/libamrnb.a) + +add_library(lib_amrwb STATIC IMPORTED) +set_target_properties(lib_amrwb PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/amr/lib/${ANDROID_ABI}/libamrwb.a) + +add_library(lib_amrwbenc STATIC IMPORTED) +set_target_properties(lib_amrwbenc PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/amr/lib/${ANDROID_ABI}/libamrwbenc.a) + +add_library(lib_zrtpcppcore STATIC IMPORTED) +set_target_properties(lib_zrtpcppcore PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/gzrtp/lib/${ANDROID_ABI}/libzrtpcppcore.a) + +add_library(lib_sndfile STATIC IMPORTED) +set_target_properties(lib_sndfile PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/sndfile/lib/${ANDROID_ABI}/libsndfile.a) + +add_library(lib_baresip STATIC IMPORTED) +set_target_properties(lib_baresip PROPERTIES IMPORTED_LOCATION + ${distribution_DIR}/baresip/lib/${ANDROID_ABI}/libbaresip.a) + +add_library(wearbaresip SHARED ${CMAKE_SOURCE_DIR}/baresip.c) + +target_include_directories(wearbaresip PRIVATE + ${distribution_DIR}/openssl/include + ${distribution_DIR}/re/include + ${distribution_DIR}/baresip/include) + +add_definitions(-DHAVE_PTHREAD) + +target_link_libraries( + wearbaresip + android + aaudio + lib_baresip + lib_re + lib_ssl + lib_crypto + lib_opus + lib_g722 + lib_g722_1 + lib_g729 + lib_ilbc + lib_codec2 + lib_amrnb + lib_amrwb + lib_amrwbenc + lib_zrtpcppcore + lib_sndfile + z + log) diff --git a/wear/src/main/cpp/baresip.c b/wear/src/main/cpp/baresip.c new file mode 100644 index 00000000..659e36e9 --- /dev/null +++ b/wear/src/main/cpp/baresip.c @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#include +#include +#include +#include "logger.h" + +typedef struct baresip_context +{ + JavaVM *javaVM; + jclass serviceClz; + jobject serviceObj; + +} BaresipContext; + +static BaresipContext g_ctx; + +enum +{ + ASYNC_WORKERS = 4 +}; + +static pthread_key_t g_thread_key; + +static void detach_thread(void *env) +{ + (void)env; + (*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 { + return NULL; + } + } + return env; +} + +static void ua_exit_handler(void *arg) +{ + (void)arg; + re_cancel(); +} + +static const char *translate_errorcode(uint16_t scode) +{ + switch (scode) { + case 404: + return ""; + case 486: + case 603: + return "busy"; + case 487: + return ""; + default: + return "error"; + } +} + +static void event_handler(enum bevent_ev ev, struct bevent *event, void *arg) +{ + (void)arg; + const char *prm = bevent_get_text(event); + struct call *call = bevent_get_call(event); + struct ua *ua = bevent_get_ua(event); + const struct sip_msg *msg = bevent_get_msg(event); + struct account *acc = ua_account(bevent_get_ua(event)); + const char *tone; + char event_buf[256]; + enum sdp_dir ardir; + int len, err; + struct pl module, module_event, data; + + switch (ev) { + case BEVENT_CREATE: + len = re_snprintf(event_buf, sizeof event_buf, "create", ""); + break; + case BEVENT_REGISTERING: + case BEVENT_UNREGISTERING: + case BEVENT_REGISTER_OK: + case BEVENT_FALLBACK_OK: + len = re_snprintf(event_buf, sizeof event_buf, "%s", prm); + break; + case BEVENT_REGISTER_FAIL: + case BEVENT_FALLBACK_FAIL: + len = re_snprintf(event_buf, sizeof event_buf, "registering failed,%s", prm); + break; + case BEVENT_SIPSESS_CONN: + ua = uag_find_msg(msg); + call = (struct call *)msg; + len = re_snprintf(event_buf, sizeof event_buf, "%s,%r,%ld", prm, &msg->from.auri, (long)event); + break; + case BEVENT_CALL_INCOMING: + len = re_snprintf(event_buf, sizeof event_buf, "call incoming,%s", prm); + break; + case BEVENT_CALL_OUTGOING: + len = re_snprintf(event_buf, sizeof event_buf, "call outgoing", ""); + break; + case BEVENT_CALL_ANSWERED: + len = re_snprintf(event_buf, sizeof event_buf, "call answered", ""); + break; + case BEVENT_CALL_REDIRECT: + len = re_snprintf(event_buf, sizeof event_buf, "call redirect,%s", prm + 4); + break; + case BEVENT_CALL_LOCAL_SDP: + if (strcmp(prm, "offer") == 0) + return; + len = re_snprintf(event_buf, sizeof event_buf, "call %sed", prm); + break; + case BEVENT_CALL_RINGING: + len = re_snprintf(event_buf, sizeof event_buf, "call ringing", ""); + break; + case BEVENT_CALL_PROGRESS: + ardir = sdp_media_rdir(stream_sdpmedia(audio_strm(call_audio(call)))); + len = re_snprintf(event_buf, sizeof event_buf, "call progress,%d", ardir); + break; + case BEVENT_CALL_ESTABLISHED: + len = re_snprintf(event_buf, sizeof event_buf, "call established", ""); + break; + case BEVENT_CALL_REMOTE_SDP: + ardir = sdp_media_rdir(stream_sdpmedia(audio_strm(call_audio(call)))); + len = re_snprintf(event_buf, sizeof event_buf, "call update,%d,%ld", ardir, (long)event); + break; + case BEVENT_CALL_MENC: + if (prm[0] == '0') + len = re_snprintf(event_buf, sizeof event_buf, "call secure", ""); + else if (prm[0] == '1') + len = re_snprintf(event_buf, sizeof event_buf, "call verify,%s", prm + 2); + else if (prm[0] == '2') + len = re_snprintf(event_buf, sizeof event_buf, "call verified,%s", prm + 2); + else + len = re_snprintf(event_buf, sizeof event_buf, "unknown menc event", ""); + break; + case BEVENT_CALL_TRANSFER: + len = re_snprintf(event_buf, sizeof event_buf, "call transfer,%s", prm); + break; + case BEVENT_CALL_TRANSFER_FAILED: + call_hold(call, false); + len = re_snprintf(event_buf, sizeof event_buf, "transfer failed,%s", prm); + break; + case BEVENT_CALL_CLOSED: + tone = call_scode(call) ? translate_errorcode(call_scode(call)) : ""; + len = re_snprintf(event_buf, sizeof event_buf, "call closed,%s,%s", prm, tone); + break; + case BEVENT_MWI_NOTIFY: + len = re_snprintf(event_buf, sizeof event_buf, "mwi notify,%s", prm); + break; + case BEVENT_MODULE: + err = re_regex(prm, strlen(prm), "[^,]*,[^,]*,[~]*", &module, &module_event, &data); + if (err) + return; + if (!pl_strcmp(&module_event, "dump")) { + len = re_snprintf(event_buf, sizeof event_buf, "sndfile dump,%r", &data); + break; + } + if (!pl_strcmp(&module_event, "recorder sessionid")) { + len = re_snprintf(event_buf, sizeof event_buf, "recorder sessionid,%r", &data); + break; + } + default: + return; + } + + if (len == -1) { + return; + } + + JNIEnv *env = get_jni_env(); + if (!env) return; + + if (!g_ctx.serviceClz || !g_ctx.serviceObj) return; + + jmethodID methodId = + (*env)->GetMethodID(env, g_ctx.serviceClz, "uaEvent", "(Ljava/lang/String;)V"); + jstring jEvent = (*env)->NewStringUTF(env, event_buf); + if (methodId) { + (*env)->CallVoidMethod(env, g_ctx.serviceObj, methodId, jEvent); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + } + } + (*env)->DeleteLocalRef(env, jEvent); +} + +static void message_handler( + struct ua *ua, const struct pl *peer, const struct pl *ctype, struct mbuf *body, void *arg) +{ + (void)arg; + char peer_buf[256]; + size_t size; + + if (snprintf(peer_buf, 256, "%.*s", (int)peer->l, peer->p) >= 256) { + return; + } + + JNIEnv *env = get_jni_env(); + if (!env) return; + + if (!g_ctx.serviceClz || !g_ctx.serviceObj) return; + + jmethodID methodId = (*env)->GetMethodID(env, g_ctx.serviceClz, "messageEvent", + "(JLjava/lang/String;Ljava/lang/String;[B)V"); + jstring jPeer = (*env)->NewStringUTF(env, peer_buf); + jbyteArray jMsg; + size = mbuf_get_left(body); + jMsg = (*env)->NewByteArray(env, (jsize)size); + if ((*env)->GetArrayLength(env, jMsg) != size) { + (*env)->DeleteLocalRef(env, jMsg); + jMsg = (*env)->NewByteArray(env, (jsize)size); + } + void *temp = (*env)->GetPrimitiveArrayCritical(env, (jarray)jMsg, 0); + memcpy(temp, mbuf_buf(body), size); + (*env)->ReleasePrimitiveArrayCritical(env, jMsg, temp, 0); + if (methodId) { + (*env)->CallVoidMethod(env, g_ctx.serviceObj, methodId, (jlong)ua, jPeer, NULL, jMsg); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + } + } + (*env)->DeleteLocalRef(env, jPeer); + (*env)->DeleteLocalRef(env, jMsg); +} + +static void send_resp_handler(int err, const struct sip_msg *msg, void *arg) +{ + char *native_time = (char *)arg; + char reason_buf[64]; + + if (err) { + mem_deref(native_time); + return; + } + + pl_strcpy(&(msg->reason), reason_buf, 64); + + JNIEnv *env = get_jni_env(); + if (!env) { + mem_deref(native_time); + return; + } + + if (!g_ctx.serviceClz || !g_ctx.serviceObj) { + mem_deref(native_time); + return; + } + + jmethodID methodId = (*env)->GetMethodID(env, g_ctx.serviceClz, "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.serviceObj, methodId, msg->scode, javaReason, + javaTime); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + } + } + (*env)->DeleteLocalRef(env, javaReason); + (*env)->DeleteLocalRef(env, javaTime); + + mem_deref(native_time); +} + +enum +{ + ID_UA_STOP_ALL +}; + +static struct mqueue *mq; + +static void mqueue_handler(int id, void *data, void *arg) +{ + (void)arg; + if (id == ID_UA_STOP_ALL) { + ua_stop_all((bool)(uintptr_t)data); + } +} + +#include + +static int pfd[2]; +static pthread_t loggingThread; + +static void *loggingFunction(void *arg) +{ + (void)arg; + ssize_t readSize; + char buf[128]; + + while ((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) { + if (buf[readSize - 1] == '\n') { + --readSize; + } + buf[readSize] = 0; + LOGD("%s", buf); + } + + return 0; +} + +static int runLoggingThread() +{ + setvbuf(stdout, 0, _IOLBF, 0); + setvbuf(stderr, 0, _IONBF, 0); + + pipe(pfd); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + + int ret = pthread_create(&loggingThread, NULL, loggingFunction, NULL); + if (ret != 0) { + return ret; + } + + pthread_detach(loggingThread); + + return 0; +} + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) +{ + (void)reserved; + + memset(&g_ctx, 0, sizeof(g_ctx)); + g_ctx.javaVM = vm; + + if (pthread_key_create(&g_thread_key, detach_thread) != 0) { + } + + return JNI_VERSION_1_6; +} + +JNIEXPORT void JNICALL +Java_com_tutpro_baresip_wear_WearBaresipService_baresipStart( + JNIEnv *env, jobject instance, jstring jPath, jstring jAddrs, jint jLogLevel, jstring jSoftware) +{ + int err; + + jclass clz = (*env)->GetObjectClass(env, instance); + g_ctx.serviceClz = (*env)->NewGlobalRef(env, clz); + g_ctx.serviceObj = (*env)->NewGlobalRef(env, instance); + + const char *path = (*env)->GetStringUTFChars(env, jPath, 0); + const char *addrs = (*env)->GetStringUTFChars(env, jAddrs, 0); + const char *software = (*env)->GetStringUTFChars(env, jSoftware, 0); + + runLoggingThread(); + + err = libre_init(); + if (err) { + goto out; + } + + if (re_thread_check(true) == 0) { + jint res = (*g_ctx.javaVM)->AttachCurrentThread(g_ctx.javaVM, &env, NULL); + if (JNI_OK != res) { + goto out; + } + } else { + goto out; + } + + conf_path_set(path); + + log_level_set((enum log_level)jLogLevel); + + err = conf_configure(); + if (err) { + goto out; + } + + re_thread_async_init(ASYNC_WORKERS); + + err = baresip_init(conf_config()); + if (err) { + goto out; + } + + dnsc_cache_max(net_dnsc(baresip_network()), 0); + + if (strlen(addrs) > 0) { + char *addr_list = (char *)malloc(strlen(addrs) + 1); + struct sa temp_sa; + char buf[256]; + net_flush_addresses(baresip_network()); + strcpy(addr_list, addrs); + char *ptr = strtok(addr_list, ";"); + while (ptr != NULL) { + if (0 == sa_set_str(&temp_sa, ptr, 0)) { + sa_ntop(&temp_sa, buf, 256); + ptr = strtok(NULL, ";"); + net_add_address_ifname(baresip_network(), &temp_sa, ptr); + } else { + ptr = strtok(NULL, ";"); + } + if (ptr) + *(ptr - 1) = ';'; + ptr = strtok(NULL, ";"); + } + free(addr_list); + } + + err = ua_init(software, true, true, true); + if (err) { + goto out; + } + + uag_set_exit_handler(ua_exit_handler, NULL); + + err = bevent_register(event_handler, NULL); + if (err) { + goto out; + } + + err = message_listen(baresip_message(), message_handler, NULL); + if (err) { + goto out; + } + + err = conf_modules(); + if (err) { + goto out; + } + + err = mqueue_alloc(&mq, mqueue_handler, NULL); + if (err) { + goto out; + } + +out: + (*env)->ReleaseStringUTFChars(env, jPath, path); + (*env)->ReleaseStringUTFChars(env, jAddrs, addrs); + (*env)->ReleaseStringUTFChars(env, jSoftware, software); +} + +JNIEXPORT void JNICALL +Java_com_tutpro_baresip_wear_WearBaresipService_baresipStop(JNIEnv *env, jobject instance) +{ + (void)env; + (void)instance; + + ua_stop_all(true); + baresip_close(); + libre_close(); + + if (g_ctx.serviceClz) { + (*env)->DeleteGlobalRef(env, g_ctx.serviceClz); + g_ctx.serviceClz = NULL; + } + if (g_ctx.serviceObj) { + (*env)->DeleteGlobalRef(env, g_ctx.serviceObj); + g_ctx.serviceObj = NULL; + } +} diff --git a/wear/src/main/cpp/logger.h b/wear/src/main/cpp/logger.h new file mode 100644 index 00000000..7c9c1483 --- /dev/null +++ b/wear/src/main/cpp/logger.h @@ -0,0 +1,13 @@ +#include +#include + +#ifndef BARESIP_LOGGER_H +#define BARESIP_LOGGER_H + +#define LOG_TAG "Baresip Wear" +#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) + +#endif diff --git a/wear/src/main/java/com/tutpro/baresip/wear/MainActivity.kt b/wear/src/main/java/com/tutpro/baresip/wear/MainActivity.kt new file mode 100644 index 00000000..0fc9ffff --- /dev/null +++ b/wear/src/main/java/com/tutpro/baresip/wear/MainActivity.kt @@ -0,0 +1,49 @@ +package com.tutpro.baresip.wear + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat +import androidx.wear.compose.material.Text +import androidx.wear.compose.material.TimeText + +class MainActivity : ComponentActivity() { + + private val recordAudioPermission = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { granted -> + if (granted) { + startBaresipService() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + TimeText() + Text(text = "Baresip Wear") + } + + if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) + == PackageManager.PERMISSION_GRANTED + ) { + startBaresipService() + } else { + recordAudioPermission.launch(Manifest.permission.RECORD_AUDIO) + } + } + + private fun startBaresipService() { + val intent = Intent(this, WearBaresipService::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(intent) + } else { + startService(intent) + } + } +} diff --git a/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipApp.kt b/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipApp.kt new file mode 100644 index 00000000..29bdaef4 --- /dev/null +++ b/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipApp.kt @@ -0,0 +1,10 @@ +package com.tutpro.baresip.wear + +import android.app.Application + +class WearBaresipApp : Application() { + // The foreground service is launched from MainActivity (foreground state), + // not from Application.onCreate(), because starting a microphone-type + // foreground service from a non-foreground context is rejected on + // targetSdk 34+. +} diff --git a/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipService.kt b/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipService.kt new file mode 100644 index 00000000..cf208f43 --- /dev/null +++ b/wear/src/main/java/com/tutpro/baresip/wear/WearBaresipService.kt @@ -0,0 +1,65 @@ +package com.tutpro.baresip.wear + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat + +class WearBaresipService : Service() { + + override fun onCreate() { + super.onCreate() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Baresip Wear", + NotificationManager.IMPORTANCE_LOW + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Baresip Wear") + .setContentText("SIP stack running") + .setSmallIcon(android.R.drawable.sym_call_incoming) + .build() + startForeground(NOTIFICATION_ID, notification) + + // Start the native baresip stack. Path points at the app's private + // config directory where accounts.cfg etc. are expected. + val path = applicationContext.filesDir.absolutePath + baresipStart(path, "", 2, "baresip-studio-wear") + + return START_STICKY + } + + override fun onDestroy() { + baresipStop() + super.onDestroy() + } + + override fun onBind(intent: Intent?): IBinder? = null + + external fun baresipStart(path: String, addrs: String, logLevel: Int, software: String) + external fun baresipStop() + + fun uaEvent(event: String) { + // TODO route to watch UI / Data Layer + } + + companion object { + const val CHANNEL_ID = "baresip-wear" + const val NOTIFICATION_ID = 1 + } + + init { + System.loadLibrary("wearbaresip") + } +}