Work on call recording
This commit is contained in:
@ -60,6 +60,10 @@ add_library(lib_zrtpcppcore STATIC IMPORTED)
|
|||||||
set_target_properties(lib_zrtpcppcore PROPERTIES IMPORTED_LOCATION
|
set_target_properties(lib_zrtpcppcore PROPERTIES IMPORTED_LOCATION
|
||||||
${distribution_DIR}/gzrtp/lib/${ANDROID_ABI}/libzrtpcppcore.a)
|
${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)
|
add_library(lib_baresip STATIC IMPORTED)
|
||||||
set_target_properties(lib_baresip PROPERTIES IMPORTED_LOCATION
|
set_target_properties(lib_baresip PROPERTIES IMPORTED_LOCATION
|
||||||
${distribution_DIR}/baresip/lib/${ANDROID_ABI}/libbaresip.a)
|
${distribution_DIR}/baresip/lib/${ANDROID_ABI}/libbaresip.a)
|
||||||
@ -90,5 +94,6 @@ target_link_libraries(baresip
|
|||||||
lib_amrwbenc
|
lib_amrwbenc
|
||||||
lib_webrtc
|
lib_webrtc
|
||||||
lib_zrtpcppcore
|
lib_zrtpcppcore
|
||||||
|
lib_sndfile
|
||||||
z
|
z
|
||||||
log)
|
log)
|
||||||
|
|||||||
@ -147,7 +147,8 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
|
|||||||
const char *tone;
|
const char *tone;
|
||||||
char event_buf[256];
|
char event_buf[256];
|
||||||
enum sdp_dir ardir;
|
enum sdp_dir ardir;
|
||||||
int len;
|
int len, err;
|
||||||
|
struct pl module, module_event, data;
|
||||||
|
|
||||||
LOGD("ua event (%s) %s\n", uag_event_str(ev), prm);
|
LOGD("ua event (%s) %s\n", uag_event_str(ev), prm);
|
||||||
|
|
||||||
@ -225,6 +226,15 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
|
|||||||
case UA_EVENT_MWI_NOTIFY:
|
case UA_EVENT_MWI_NOTIFY:
|
||||||
len = re_snprintf(event_buf, sizeof event_buf, "mwi notify,%s", prm);
|
len = re_snprintf(event_buf, sizeof event_buf, "mwi notify,%s", prm);
|
||||||
break;
|
break;
|
||||||
|
case UA_EVENT_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;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1088,7 +1098,7 @@ Java_com_tutpro_baresip_Api_ua_1answer(JNIEnv *env, jobject thiz, jlong ua, jlon
|
|||||||
re_thread_leave();
|
re_thread_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_tutpro_baresip_Api_ua_1add_1custom_1header(JNIEnv *env, jobject thiz, jlong ua,
|
Java_com_tutpro_baresip_Api_ua_1add_1custom_1header(JNIEnv *env, jobject thiz, jlong ua,
|
||||||
jstring jname, jstring jbody) {
|
jstring jname, jstring jbody) {
|
||||||
const char *name = (*env)->GetStringUTFChars(env, jname, 0);
|
const char *name = (*env)->GetStringUTFChars(env, jname, 0);
|
||||||
@ -1104,7 +1114,6 @@ Java_com_tutpro_baresip_Api_ua_1add_1custom_1header(JNIEnv *env, jobject thiz, j
|
|||||||
LOGW("adding custom header to ua %ld failed with error %d\n", (long)ua, err);
|
LOGW("adding custom header to ua %ld failed with error %d\n", (long)ua, err);
|
||||||
(*env)->ReleaseStringUTFChars(env, jname, name);
|
(*env)->ReleaseStringUTFChars(env, jname, name);
|
||||||
(*env)->ReleaseStringUTFChars(env, jbody, body);
|
(*env)->ReleaseStringUTFChars(env, jbody, body);
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import androidx.media.AudioManagerCompat
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@ -384,6 +385,23 @@ class BaresipService: Service() {
|
|||||||
if (File(filesDir, "history").exists())
|
if (File(filesDir, "history").exists())
|
||||||
File(filesDir, "history").renameTo(File(filesDir, "calls"))
|
File(filesDir, "history").renameTo(File(filesDir, "calls"))
|
||||||
|
|
||||||
|
if (!File(filesDir, "tmp").exists())
|
||||||
|
File(filesDir, "tmp").mkdir()
|
||||||
|
|
||||||
|
if (!File(filesDir, "recordings").exists())
|
||||||
|
File(filesDir, "recordings").mkdir()
|
||||||
|
else {
|
||||||
|
File(filesDir, "recordings").walk().forEach { f ->
|
||||||
|
Log.d(TAG, "***** file ${f.name}")
|
||||||
|
val recording = f.name.substringBeforeLast("-")
|
||||||
|
if (recording.startsWith("dump")) {
|
||||||
|
val time = recording.takeLast(19)
|
||||||
|
if (!recordings.containsKey(time))
|
||||||
|
recordings[time] = filesDir.absolutePath + "/recordings/" + recording
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Recordings $recordings")
|
||||||
|
}
|
||||||
|
|
||||||
if (contactsMode != "android")
|
if (contactsMode != "android")
|
||||||
Contact.restoreBaresipContacts()
|
Contact.restoreBaresipContacts()
|
||||||
@ -573,6 +591,11 @@ class BaresipService: Service() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ev[0] == "sndfile dump") {
|
||||||
|
Log.d(TAG, "Got sndfile dump ${ev[1]}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val ua = UserAgent.ofUap(uap)
|
val ua = UserAgent.ofUap(uap)
|
||||||
if (ua == null) {
|
if (ua == null) {
|
||||||
Log.w(TAG, "uaEvent $event did not find ua $uap")
|
Log.w(TAG, "uaEvent $event did not find ua $uap")
|
||||||
@ -877,6 +900,23 @@ class BaresipService: Service() {
|
|||||||
NewCallHistory.add(history)
|
NewCallHistory.add(history)
|
||||||
NewCallHistory.save()
|
NewCallHistory.save()
|
||||||
ua.account.missedCalls = ua.account.missedCalls || missed
|
ua.account.missedCalls = ua.account.missedCalls || missed
|
||||||
|
if (isRecOn && call.startTime != null) {
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
|
||||||
|
val startTime = call.startTime!!
|
||||||
|
var time = format.format(startTime.time).toString()
|
||||||
|
var recording = filesDir.absolutePath + "/recordings/" +
|
||||||
|
"dump-$aor=>${call.peerUri}-$time"
|
||||||
|
if (File("$recording-dec.wav").exists()) {
|
||||||
|
recordings[time] = recording
|
||||||
|
} else {
|
||||||
|
startTime.add(Calendar.SECOND, 1)
|
||||||
|
time = format.format(startTime.time).toString()
|
||||||
|
recording = filesDir.absolutePath + "/recordings/" +
|
||||||
|
"dump-$aor=>${call.peerUri}-$time"
|
||||||
|
recordings[time] = recording
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!Utils.isVisible()) {
|
if (!Utils.isVisible()) {
|
||||||
if (missed) {
|
if (missed) {
|
||||||
@ -1496,6 +1536,7 @@ class BaresipService: Service() {
|
|||||||
var callActionUri = ""
|
var callActionUri = ""
|
||||||
var isMainVisible = false
|
var isMainVisible = false
|
||||||
var isMicMuted = false
|
var isMicMuted = false
|
||||||
|
var isRecOn = false
|
||||||
|
|
||||||
val uas = ArrayList<UserAgent>()
|
val uas = ArrayList<UserAgent>()
|
||||||
val calls = ArrayList<Call>()
|
val calls = ArrayList<Call>()
|
||||||
@ -1514,6 +1555,7 @@ class BaresipService: Service() {
|
|||||||
var dnsServers = listOf<InetAddress>()
|
var dnsServers = listOf<InetAddress>()
|
||||||
val serviceEvent = MutableLiveData<Event<Long>>()
|
val serviceEvent = MutableLiveData<Event<Long>>()
|
||||||
val serviceEvents = mutableListOf<ServiceEvent>()
|
val serviceEvents = mutableListOf<ServiceEvent>()
|
||||||
|
val recordings: MutableMap<String, String> = mutableMapOf()
|
||||||
|
|
||||||
private var audioFocusRequest: AudioFocusRequestCompat? = null
|
private var audioFocusRequest: AudioFocusRequestCompat? = null
|
||||||
private var btAdapter: BluetoothAdapter? = null
|
private var btAdapter: BluetoothAdapter? = null
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Typeface
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -9,6 +11,7 @@ import android.widget.ArrayAdapter
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -23,6 +26,7 @@ class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<C
|
|||||||
val durationView = view?.findViewById(R.id.duration) as TextView
|
val durationView = view?.findViewById(R.id.duration) as TextView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SimpleDateFormat")
|
||||||
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
|
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
|
||||||
|
|
||||||
val viewHolder: ViewHolder
|
val viewHolder: ViewHolder
|
||||||
@ -59,7 +63,7 @@ class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<C
|
|||||||
viewHolder.durationView.text = ""
|
viewHolder.durationView.text = ""
|
||||||
} else {
|
} else {
|
||||||
val startText = if (DateUtils.isToday(startTime.timeInMillis)) {
|
val startText = if (DateUtils.isToday(startTime.timeInMillis)) {
|
||||||
val fmt = DateFormat.getTimeInstance(DateFormat.LONG)
|
val fmt = DateFormat.getTimeInstance(DateFormat.MEDIUM)
|
||||||
ctx.getString(R.string.today) + " " + fmt.format(startTime.time)
|
ctx.getString(R.string.today) + " " + fmt.format(startTime.time)
|
||||||
} else {
|
} else {
|
||||||
val fmt = DateFormat.getDateTimeInstance()
|
val fmt = DateFormat.getDateTimeInstance()
|
||||||
@ -68,6 +72,14 @@ class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<C
|
|||||||
viewHolder.timeView.text = startText
|
viewHolder.timeView.text = startText
|
||||||
val duration = (stopTime.time.time - startTime.time.time) / 1000
|
val duration = (stopTime.time.time - startTime.time.time) / 1000
|
||||||
viewHolder.durationView.text = DateUtils.formatElapsedTime(duration)
|
viewHolder.durationView.text = DateUtils.formatElapsedTime(duration)
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
|
||||||
|
val time = format.format(startTime.time).toString()
|
||||||
|
if (BaresipService.recordings.containsKey(time)) {
|
||||||
|
viewHolder.durationView.typeface = Typeface.DEFAULT_BOLD
|
||||||
|
viewHolder.durationView.setOnClickListener {
|
||||||
|
Utils.playRecording(ctx, BaresipService.recordings[time]!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,6 +115,8 @@ object Config {
|
|||||||
if (!config.contains("dtls_srtp_use_ec"))
|
if (!config.contains("dtls_srtp_use_ec"))
|
||||||
config = "${config}dtls_srtp_use_ec prime256v1\n"
|
config = "${config}dtls_srtp_use_ec prime256v1\n"
|
||||||
|
|
||||||
|
replaceVariable("snd_path", "${BaresipService.filesPath}/recordings")
|
||||||
|
|
||||||
Utils.putFileContents(configPath, config.toByteArray())
|
Utils.putFileContents(configPath, config.toByteArray())
|
||||||
BaresipService.isConfigInitialized = true
|
BaresipService.isConfigInitialized = true
|
||||||
Log.i(TAG, "Initialized config to '$config'")
|
Log.i(TAG, "Initialized config to '$config'")
|
||||||
|
|||||||
@ -76,6 +76,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private lateinit var kgm: KeyguardManager
|
private lateinit var kgm: KeyguardManager
|
||||||
private lateinit var screenEventReceiver: BroadcastReceiver
|
private lateinit var screenEventReceiver: BroadcastReceiver
|
||||||
private lateinit var serviceEventObserver: Observer<Event<Long>>
|
private lateinit var serviceEventObserver: Observer<Event<Long>>
|
||||||
|
private var recIcon: MenuItem? = null
|
||||||
private var micIcon: MenuItem? = null
|
private var micIcon: MenuItem? = null
|
||||||
private var speakerIcon: MenuItem? = null
|
private var speakerIcon: MenuItem? = null
|
||||||
private lateinit var swipeRefresh: SwipeRefreshLayout
|
private lateinit var swipeRefresh: SwipeRefreshLayout
|
||||||
@ -1258,6 +1259,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
menuInflater.inflate(R.menu.main_menu, menu)
|
menuInflater.inflate(R.menu.main_menu, menu)
|
||||||
|
|
||||||
|
menuInflater.inflate(R.menu.rec_icon, menu)
|
||||||
|
recIcon = menu.findItem(R.id.recIcon)
|
||||||
|
if (BaresipService.isRecOn)
|
||||||
|
recIcon!!.setIcon(R.drawable.rec_on)
|
||||||
|
else
|
||||||
|
recIcon!!.setIcon(R.drawable.rec_off)
|
||||||
|
|
||||||
menuInflater.inflate(R.menu.mic_icon, menu)
|
menuInflater.inflate(R.menu.mic_icon, menu)
|
||||||
micIcon = menu.findItem(R.id.micIcon)
|
micIcon = menu.findItem(R.id.micIcon)
|
||||||
if (BaresipService.isMicMuted)
|
if (BaresipService.isMicMuted)
|
||||||
@ -1279,6 +1287,19 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
|
||||||
|
R.id.recIcon -> {
|
||||||
|
if (Call.call("connected") == null) {
|
||||||
|
BaresipService.isRecOn = !BaresipService.isRecOn
|
||||||
|
if (BaresipService.isRecOn) {
|
||||||
|
item.setIcon(R.drawable.rec_on)
|
||||||
|
Api.module_load("sndfile")
|
||||||
|
} else {
|
||||||
|
item.setIcon(R.drawable.rec_off)
|
||||||
|
Api.module_unload("sndfile")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
R.id.micIcon -> {
|
R.id.micIcon -> {
|
||||||
if (Call.call("connected") != null) {
|
if (Call.call("connected") != null) {
|
||||||
BaresipService.isMicMuted = !BaresipService.isMicMuted
|
BaresipService.isMicMuted = !BaresipService.isMicMuted
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import android.graphics.Bitmap.createScaledBitmap
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.media.AudioAttributes
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
@ -24,10 +25,12 @@ import android.widget.ImageView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.media.AudioDeviceInfo
|
import android.media.AudioDeviceInfo
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
import android.media.MediaPlayer
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.core.text.isDigitsOnly
|
import androidx.core.text.isDigitsOnly
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
@ -992,4 +995,105 @@ object Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun playRecording(ctx: Context, recording: String) {
|
||||||
|
Log.d(TAG, "Playing recording $recording")
|
||||||
|
val decPlayer = MediaPlayer()
|
||||||
|
decPlayer.apply {
|
||||||
|
setAudioAttributes(
|
||||||
|
AudioAttributes.Builder()
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
setOnPreparedListener {
|
||||||
|
val encPlayer = MediaPlayer()
|
||||||
|
encPlayer.apply {
|
||||||
|
setAudioAttributes(
|
||||||
|
AudioAttributes.Builder()
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
setOnPreparedListener {
|
||||||
|
it.start()
|
||||||
|
decPlayer.start()
|
||||||
|
Log.d(TAG, "Started players")
|
||||||
|
}
|
||||||
|
setOnCompletionListener {
|
||||||
|
Log.d(TAG, "Stopping encPlayer")
|
||||||
|
it.stop()
|
||||||
|
it.release()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val file = "$recording-enc.wav"
|
||||||
|
val encFile = File(file).copyTo(File(BaresipService.filesPath + "/tmp/encode.wav"), true)
|
||||||
|
val encUri = encFile.toUri()
|
||||||
|
Log.d(TAG, "Setting data source $encUri")
|
||||||
|
setDataSource(ctx, encUri)
|
||||||
|
prepareAsync()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.e(TAG, "encPlayer IllegalArgumentException: $e")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "encPlayer IOException: $e")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "encPlayer Exception: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setOnCompletionListener {
|
||||||
|
Log.d(TAG, "Stopping decPlayer")
|
||||||
|
it.stop()
|
||||||
|
it.release()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val file = "$recording-dec.wav"
|
||||||
|
val decFile = File(file).copyTo(File(BaresipService.filesPath + "/tmp/decode.wav"), true)
|
||||||
|
val decUri = decFile.toUri()
|
||||||
|
Log.d(TAG, "Setting data source $decUri")
|
||||||
|
setDataSource(ctx, decUri)
|
||||||
|
prepareAsync()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.e(TAG, "decPlayer IllegalArgumentException: $e")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "decPlayer IOException: $e")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "decPlayer Exception: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun playFile(ctx: Context, path: String) {
|
||||||
|
Log.d(TAG, "Playing file $path")
|
||||||
|
MediaPlayer().apply {
|
||||||
|
setAudioAttributes(
|
||||||
|
AudioAttributes.Builder()
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
setOnPreparedListener {
|
||||||
|
Log.d(TAG, "Starting MediaPlayer")
|
||||||
|
it.start()
|
||||||
|
Log.d(TAG, "MediaPlayer started")
|
||||||
|
}
|
||||||
|
setOnCompletionListener {
|
||||||
|
Log.d(TAG, "Stopping MediaPlayer")
|
||||||
|
it.stop()
|
||||||
|
it.release()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "Preparing $path")
|
||||||
|
setDataSource(ctx, path.toUri())
|
||||||
|
prepareAsync()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.e(TAG, "MediaPlayer IllegalArgumentException: ${e.printStackTrace()}")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "MediaPlayer IOException: ${e.printStackTrace()}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "MediaPlayer Exception: ${e.printStackTrace()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user