diff --git a/app/build.gradle b/app/build.gradle index a2a7460..a7c526e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,6 +47,11 @@ android { 'proguard-rules.pro' } } + android.applicationVariants.all { variant -> + variant.outputs.all { + outputFileName = "ritosip-${defaultConfig.versionName}.apk" + } + } buildFeatures { viewBinding true dataBinding true diff --git a/app/src/main/cpp/baresip.c b/app/src/main/cpp/baresip.c index 90a3e52..f1ee081 100644 --- a/app/src/main/cpp/baresip.c +++ b/app/src/main/cpp/baresip.c @@ -1705,6 +1705,16 @@ JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1video_1direct re_thread_leave(); } +JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1video_1mute( + JNIEnv *env, jobject obj, jlong call, jboolean mute) +{ + (void)env; + (void)obj; + re_thread_enter(); + video_set_source_mute(call_video((struct call *)call), (bool)mute); + re_thread_leave(); +} + JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1media_1direction( JNIEnv *env, jobject obj, jlong call, jint adir, jint vdir) { diff --git a/app/src/main/cpp/vidisp.c b/app/src/main/cpp/vidisp.c index a4444e1..61c8b2a 100644 --- a/app/src/main/cpp/vidisp.c +++ b/app/src/main/cpp/vidisp.c @@ -964,7 +964,9 @@ JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_VideoView_set_1surfaceSelf( } } else { LOGW("[SELF] Releasing windowSelf"); - ANativeWindow_release(window_self); + if(window_self) { + ANativeWindow_release(window_self); + } window_self = NULL; } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Api.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Api.kt index 2502eb1..0a64fe6 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Api.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Api.kt @@ -99,6 +99,7 @@ object Api { external fun call_has_video(callp: Long): Boolean external fun call_set_video_source(callp: Long, front: Boolean): Int external fun call_set_video_direction(callp: Long, dir: Int) + external fun call_set_video_mute(callp: Long, mute: Boolean) // added by ritoseo external fun call_set_media_direction(callp: Long, adir: Int, vdir: Int) external fun call_disable_video_stream(callp: Long, disable: Boolean) external fun call_video_enabled(callp: Long): Boolean diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/BaresipService.kt index 414b309..f578fea 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/BaresipService.kt @@ -395,6 +395,36 @@ class BaresipService: Service() { } else if(req == "audio_unmute") { Api.calls_mute(false) isMicMuted = false + } else if(req == "video_mute") { + if(uas.size > 0) { + val ua = uas[0] + val call = ua.currentCall() + call?.setVideoMute(true) + isVideoMuted = true + } + } else if(req == "video_unmute") { + if(uas.size > 0) { + val ua = uas[0] + val call = ua.currentCall() + call?.setVideoMute(false) + isVideoMuted = false + } + } else if(req == "audio_source") { + val param = intent?.getStringExtra("param") + if(param != null) { + try { + val json = JSONObject(param) + var device = "usb" + val source_target = json.getString("target") + if(source_target == "aux") { + device = "codec" + } + Utils.setAudioSourceDevice(device) + audioInputDevice = device + } catch(e : Exception) { + e.printStackTrace() + } + } } else if(req == "set_account") { UserAgent.deleteAllUas() val param = intent?.getStringExtra("param") @@ -422,9 +452,13 @@ class BaresipService: Service() { Api.account_set_auth_pass(acc.accp, password) acc.authPass = Api.account_auth_pass(acc.accp) - Api.account_set_answermode(acc.accp, Api.ANSWERMODE_AUTO) - acc.answerMode = Api.ANSWERMODE_AUTO - + if(BaresipService.callAnswerMode == "manual") { + Api.account_set_answermode(acc.accp, Api.ANSWERMODE_MANUAL) + acc.answerMode = Api.ANSWERMODE_MANUAL + } else { + Api.account_set_answermode(acc.accp, Api.ANSWERMODE_AUTO) + acc.answerMode = Api.ANSWERMODE_AUTO + } /* Api.log_level_set(0) @@ -773,9 +807,13 @@ class BaresipService: Service() { if (call != null) { callExist = true var audioMute = "unmute" + var videoMute = "unmute" if(isMicMuted) audioMute = "mute" + if(isVideoMuted) + videoMute = "mute" Utils.propertySet("sys.ritosip.call.mute.audio", audioMute) + Utils.propertySet("sys.ritosip.call.mute.video", videoMute) Utils.propertySet("sys.ritosip.call.status", "calling") Utils.propertySet("sys.ritosip.call.number", call.peerUri) @@ -899,6 +937,18 @@ class BaresipService: Service() { Utils.propertySet("sys.ritosip.media.input", "content") } + val usbMicExist = Utils.checkUsbMicrophone() + if(usbMicExist) { + Utils.propertySet("sys.ritosip.usb.microphone", "connected") + if(audioInputDevice == "usb") { + Utils.propertySet("sys.rito.audio.input.device", "usb") + } else { + Utils.propertySet("sys.rito.audio.input.device", "codec") + } + } else { + Utils.propertySet("sys.ritosip.usb.microphone", "disconnected") + } + delay(100) // 1초마다 실행 val now = LocalDateTime.now() @@ -2341,6 +2391,7 @@ class BaresipService: Service() { var callActionUri = "" var isMainVisible = false var isMicMuted = false + var isVideoMuted = false var isRecOn = false var toneCountry = "us" var videoSize = Size(0, 0) @@ -2392,6 +2443,8 @@ class BaresipService: Service() { var preferTransport = "udp" var videoFormatHeight = 480 var connectedDisplayCount = 0 + var callAnswerMode = "auto" + var audioInputDevice = "usb" var useDisplaySplitMode = false var displaySplitMode = DISPLAY_SPLIT_MODE_원거리_최대_근거리_우하단 var farViewDisplayId = 1 diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Call.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Call.kt index d64128c..260bf24 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Call.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Call.kt @@ -96,6 +96,10 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str Api.call_set_video_direction(callp, vdir) } + fun setVideoMute(mute: Boolean) { // added by ritoseo + Api.call_set_video_mute(callp, mute) + } + fun setMediaDirection(adir: Int, vdir: Int) { Api.call_set_media_direction(callp, adir, vdir) } diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt index 0112093..d249652 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Config.kt @@ -269,6 +269,12 @@ object Config { BaresipService.preferTransport = "udp" config = "${config}prefer_transport ${BaresipService.preferTransport}\n" + val answerMode = previousVariable("answer_mode") + if (answerMode != "") + BaresipService.callAnswerMode = answerMode + else + BaresipService.callAnswerMode = "auto" + config = "${config}answer_mode ${BaresipService.callAnswerMode}\n" save() BaresipService.isConfigInitialized = true diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt index 8f4000a..c4c18be 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/MainActivity.kt @@ -34,12 +34,14 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate +import androidx.appcompat.widget.AppCompatButton import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.net.toUri import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -127,6 +129,9 @@ class MainActivity : AppCompatActivity() { private lateinit var comDevChangedListener: AudioManager.OnCommunicationDeviceChangedListener private lateinit var permissions: Array + private lateinit var dialogImgBtn1: AppCompatButton + private lateinit var dialogImgBtn2: AppCompatButton + private var callHandler: Handler = Handler(Looper.getMainLooper()) private var callRunnable: Runnable? = null private var downloadsInputUri: Uri? = null @@ -238,6 +243,12 @@ class MainActivity : AppCompatActivity() { dialpadButton = binding.dialpadButton swipeRefresh = binding.swipeRefresh + dialogImgBtn1 = binding.dialogButtonImg1 + dialogImgBtn1.setOnClickListener { + + } + dialogImgBtn2 = binding.dialogButtonImg2 + BaresipService.supportedCameras = Utils.supportedCameras(applicationContext).isNotEmpty() imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager @@ -1876,7 +1887,10 @@ class MainActivity : AppCompatActivity() { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { val BTN_MISC = 188 + //val BTN_MENU = 58 + val SCANCODE_OPTION = 357 //MENU키 -> OPTION키로 매핑 //println("onKeyDown : ${keyCode}") + //println("onKeyDown2 : ${event?.scanCode}") val stream = if (am.mode == AudioManager.MODE_RINGTONE) AudioManager.STREAM_RING else @@ -1892,13 +1906,40 @@ class MainActivity : AppCompatActivity() { return true } KeyEvent.KEYCODE_BACK -> { - callVideoButton.requestFocus() + //callVideoButton.requestFocus() return true } + KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3, KeyEvent.KEYCODE_4, KeyEvent.KEYCODE_5, KeyEvent.KEYCODE_6, + KeyEvent.KEYCODE_7, KeyEvent.KEYCODE_8, KeyEvent.KEYCODE_9 + -> { + callUri.setText(callUri.text.toString() + (keyCode - KeyEvent.KEYCODE_0).toString()) + } + KeyEvent.KEYCODE_DEL -> { + val editable = callUri.text + val length = editable.length + if (length > 0) { + editable.delete(length - 1, length) + } + } BTN_MISC -> { return true } } + when (event?.scanCode) { + SCANCODE_OPTION -> { + val dialog = findViewById(R.id.dialogLayout) + if(dialog.isVisible) { + dialog.visibility = View.INVISIBLE + } else { + dialog.visibility = View.VISIBLE + findViewById(R.id.dialogButtonImg1).requestFocus() + } +// val dialog = findViewById(R.id.dialogBase) +// val customButton = LayoutInflater.from(this).inflate(R.layout.image_button, null) +// dialog.addView(customButton) + return true + } + } return super.onKeyDown(keyCode, event) @@ -2184,7 +2225,10 @@ class MainActivity : AppCompatActivity() { this.setShowWhenLocked(false) switchVideoLayout(false) - callVideoButton.requestFocus() + //callVideoButton.requestFocus() + + BaresipService.isMicMuted = false + BaresipService.isVideoMuted = false } "message", "message show", "message reply" -> { val i = Intent(applicationContext, ChatActivity::class.java) @@ -2959,7 +3003,8 @@ class MainActivity : AppCompatActivity() { callButton.visibility = View.VISIBLE callButton.isEnabled = true } - callVideoButton.visibility = View.VISIBLE + //callVideoButton.visibility = View.VISIBLE + callVideoButton.visibility = View.INVISIBLE // modified by ritoseo callVideoButton.isEnabled = true hangupButton.visibility = View.INVISIBLE hangupButton.isEnabled = false @@ -2993,7 +3038,8 @@ class MainActivity : AppCompatActivity() { callButton.isEnabled = true } - callVideoButton.visibility = View.VISIBLE + //callVideoButton.visibility = View.VISIBLE + callVideoButton.visibility = View.INVISIBLE // modified by ritoseo callVideoButton.isEnabled = true hangupButton.visibility = View.INVISIBLE answerButton.visibility = View.INVISIBLE diff --git a/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt index 64f6716..25f0eb0 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/plus/Utils.kt @@ -30,6 +30,7 @@ import android.net.wifi.WifiManager import android.os.Build import android.os.Bundle import android.os.Environment +import android.os.Process import android.provider.DocumentsContract import android.provider.MediaStore import android.provider.OpenableColumns @@ -1259,6 +1260,15 @@ object Utils { } } + fun setAudioSourceDevice(dev : String) { + propertySet("sys.rito.audio.input.device", dev) + //val process = Runtime.getRuntime().exec("ritosysc shell-order=killall audioserver") + val process = Runtime.getRuntime().exec("ritosysc shell-order=killall android.hardware.audio.service") + //val process = Runtime.getRuntime().exec("ritosysc shell-order=service call audio 11 i32 1 i32 3") + process.waitFor() + process.destroy() + } + fun checkDisplayConnection(idx : Int): String { val connId = idx + 1 val file = File("/sys/class/drm/card0-HDMI-A-${connId}/status") // 파일 경로 설정 @@ -1268,6 +1278,20 @@ object Utils { } } + fun checkUsbMicrophone(): Boolean { + var found = false + val file = File("/proc/asound/cards") // 파일 경로 설정 + file.bufferedReader().use { reader -> + reader.lineSequence().forEach { line -> + if(line.contains("USB")) { + found = true + } + } + } + + return found + } + fun checkCameraConnection(idx : Int): String { if(idx == 0) { val file = File("/d/hdmirx/status") // 파일 경로 설정 diff --git a/app/src/main/res/drawable/bg_button_selector.xml b/app/src/main/res/drawable/bg_button_selector.xml new file mode 100644 index 0000000..d7aaa13 --- /dev/null +++ b/app/src/main/res/drawable/bg_button_selector.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/custom_borer.xml b/app/src/main/res/drawable/custom_border.xml similarity index 100% rename from app/src/main/res/drawable/custom_borer.xml rename to app/src/main/res/drawable/custom_border.xml diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3116d4e..16f9e71 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -98,6 +98,7 @@ android:layout_width="match_parent" android:layout_height="48dp" android:background="@color/cardview_shadow_start_color" + android:clickable="false" android:gravity="center_vertical" android:popupBackground="@color/colorSpinnerDropdown" android:spinnerMode="dropdown" /> @@ -145,10 +146,12 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:background="@drawable/custom_borer" + android:background="@drawable/custom_border" + android:enabled="false" android:hint="@string/callee" android:inputType="textEmailAddress" android:textColorHint="@color/colorSecondaryDark" + android:textColor="#FF000000" android:textSize="34sp"> @@ -229,7 +232,8 @@ android:background="@null" android:contentDescription="@string/video_call" android:padding="0dp" - android:src="@drawable/call_video"> + android:src="@drawable/call_video" + android:visibility="invisible"> + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/image_button.xml b/app/src/main/res/layout/image_button.xml new file mode 100644 index 0000000..42382c3 --- /dev/null +++ b/app/src/main/res/layout/image_button.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/distribution.video/baresip/include/baresip.h b/distribution.video/baresip/include/baresip.h index d3a6d86..43a7cf8 100644 --- a/distribution.video/baresip/include/baresip.h +++ b/distribution.video/baresip/include/baresip.h @@ -1468,6 +1468,7 @@ struct stream *video_strm(const struct video *v); const struct vidcodec *video_codec(const struct video *vid, bool tx); void video_sdp_attr_decode(struct video *v); void video_req_keyframe(struct video *vid); +void video_set_source_mute(struct video *vid, bool mute); // added by ritoseo double video_calc_seconds(uint64_t rtp_ts); double video_timestamp_to_seconds(uint64_t timestamp); diff --git a/distribution.video/baresip/lib/arm64-v8a/libbaresip.a b/distribution.video/baresip/lib/arm64-v8a/libbaresip.a index d44bf75..9ac12d6 100644 Binary files a/distribution.video/baresip/lib/arm64-v8a/libbaresip.a and b/distribution.video/baresip/lib/arm64-v8a/libbaresip.a differ