From bdca32be49fe500342c911e21f638db827fdb5be Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 29 Sep 2023 11:18:08 +0200 Subject: [PATCH] Added call recording --- .../java/org/linphone/core/CoreContext.kt | 12 ++++------ .../java/org/linphone/ui/call/CallActivity.kt | 2 +- .../ui/call/fragment/ActiveCallFragment.kt | 9 +++++++ .../ui/call/viewmodel/CurrentCallViewModel.kt | 24 +++++++++++++++++++ .../java/org/linphone/utils/LinphoneUtils.kt | 17 +++++++++++++ .../drawable/in_call_button_background.xml | 2 ++ ...und_in_call_selected_button_background.xml | 5 ++++ .../res/layout-land/call_extra_actions.xml | 3 +++ .../main/res/layout/call_extra_actions.xml | 3 +++ app/src/main/res/values/strings.xml | 2 ++ 10 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/drawable/shape_round_in_call_selected_button_background.xml diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt index 8b271e4ce..a3db8c039 100644 --- a/app/src/main/java/org/linphone/core/CoreContext.kt +++ b/app/src/main/java/org/linphone/core/CoreContext.kt @@ -42,6 +42,7 @@ import org.linphone.ui.call.CallActivity import org.linphone.utils.ActivityMonitor import org.linphone.utils.AppUtils import org.linphone.utils.Event +import org.linphone.utils.LinphoneUtils class CoreContext @UiThread constructor(val context: Context) : HandlerThread("Core Thread") { companion object { @@ -280,8 +281,9 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C /*if (LinphoneUtils.checkIfNetworkHasLowBandwidth(context)) { Log.w("[Context] Enabling low bandwidth mode!") params.isLowBandwidthEnabled = true - } - params.recordFile = LinphoneUtils.getRecordingFilePathForAddress(address)*/ + }*/ + + params.recordFile = LinphoneUtils.getRecordingFilePathForAddress(address) if (localAddress != null) { val account = core.accountList.find { account -> @@ -299,10 +301,6 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C } } - /*if (corePreferences.sendEarlyMedia) { - params.isEarlyMediaSendingEnabled = true - }*/ - val call = core.inviteAddressWithParams(address, params) Log.i("$TAG Starting call $call") } @@ -343,7 +341,7 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C return } - // params.recordFile = LinphoneUtils.getRecordingFilePathForAddress(call.remoteAddress) + params.recordFile = LinphoneUtils.getRecordingFilePathForAddress(call.remoteAddress) /*if (LinphoneUtils.checkIfNetworkHasLowBandwidth(context)) { Log.w("$TAG Enabling low bandwidth mode!") diff --git a/app/src/main/java/org/linphone/ui/call/CallActivity.kt b/app/src/main/java/org/linphone/ui/call/CallActivity.kt index daf3ac75c..f8ea7436d 100644 --- a/app/src/main/java/org/linphone/ui/call/CallActivity.kt +++ b/app/src/main/java/org/linphone/ui/call/CallActivity.kt @@ -298,7 +298,7 @@ class CallActivity : AppCompatActivity() { } } - private fun showGreenToast(message: String, @DrawableRes icon: Int, duration: Long = 4000) { + fun showGreenToast(message: String, @DrawableRes icon: Int, duration: Long = 4000) { val greenToast = AppUtils.getGreenToast(this, binding.toastsArea, message, icon) binding.toastsArea.addView(greenToast.root) diff --git a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt index 1840ff8a5..4aab752f0 100644 --- a/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/fragment/ActiveCallFragment.kt @@ -228,6 +228,15 @@ class ActiveCallFragment : GenericCallFragment() { } } + callViewModel.isRecording.observe(viewLifecycleOwner) { recording -> + val text = if (recording) { + getString(R.string.toast_call_recording_started) + } else { + getString(R.string.toast_call_recording_stopped) + } + (requireActivity() as CallActivity).showGreenToast(text, R.drawable.record) + } + actionsBottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { when (newState) { diff --git a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt index d3e95faab..2a36ef3c3 100644 --- a/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt +++ b/app/src/main/java/org/linphone/ui/call/viewmodel/CurrentCallViewModel.kt @@ -72,6 +72,8 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() { val isOutgoing = MutableLiveData() + val isRecording = MutableLiveData() + val isMicrophoneMuted = MutableLiveData() val isSpeakerEnabled = MutableLiveData() @@ -503,6 +505,23 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() { } } + @UiThread + fun toggleRecording() { + coreContext.postOnCoreThread { + if (::currentCall.isInitialized) { + if (currentCall.params.isRecording) { + Log.i("$TAG Stopping call recording") + currentCall.stopRecording() + } else { + Log.i("$TAG Starting call recording") + currentCall.startRecording() + } + val recording = currentCall.params.isRecording + isRecording.postValue(recording) + } + } + } + @UiThread fun toggleFullScreen() { if (fullScreenMode.value == false && isVideoEnabled.value == false) return @@ -611,6 +630,11 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() { isOutgoing.postValue(call.dir == Call.Dir.Outgoing) + if (call.params.isRecording) { + // Do not set it to false to prevent the "no longer recording" toast to be displayed + isRecording.postValue(true) + } + val address = call.remoteAddress.clone() address.clean() displayedAddress.postValue(address.asStringUriOnly()) diff --git a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt index 60696c60a..99e23204c 100644 --- a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt +++ b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt @@ -22,6 +22,10 @@ package org.linphone.utils import androidx.annotation.AnyThread import androidx.annotation.IntegerRes import androidx.annotation.WorkerThread +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.core.Account @@ -37,6 +41,8 @@ class LinphoneUtils { companion object { private const val TAG = "[Linphone Utils]" + private const val RECORDING_DATE_PATTERN = "dd-MM-yyyy-HH-mm-ss" + @WorkerThread fun getDefaultAccount(): Account? { return coreContext.core.defaultAccount ?: coreContext.core.accountList.firstOrNull() @@ -192,6 +198,17 @@ class LinphoneUtils { return "${localSipUri.asStringUriOnly()}~${remoteSipUri.asStringUriOnly()}" } + @WorkerThread + fun getRecordingFilePathForAddress(address: Address): String { + val displayName = getDisplayName(address) + val dateFormat: DateFormat = SimpleDateFormat( + RECORDING_DATE_PATTERN, + Locale.getDefault() + ) + val fileName = "${displayName}_${dateFormat.format(Date())}.mkv" + return FileUtils.getFileStoragePath(fileName).absolutePath + } + @WorkerThread fun callStateToString(state: Call.State): String { return when (state) { diff --git a/app/src/main/res/drawable/in_call_button_background.xml b/app/src/main/res/drawable/in_call_button_background.xml index 22033920b..f9d61c0d2 100644 --- a/app/src/main/res/drawable/in_call_button_background.xml +++ b/app/src/main/res/drawable/in_call_button_background.xml @@ -2,6 +2,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/call_extra_actions.xml b/app/src/main/res/layout-land/call_extra_actions.xml index bc59ee999..c3f26ca15 100644 --- a/app/src/main/res/layout-land/call_extra_actions.xml +++ b/app/src/main/res/layout-land/call_extra_actions.xml @@ -147,12 +147,14 @@ Call is being transferred to %s Call has been transferred to %s Call transfer to %s failed! + Call is being recorded + Call is no longer being recorded Skip