Work on call recording
This commit is contained in:
@@ -59,7 +59,7 @@ class AccountListAdapter(private val cxt: Context, private val rows: ArrayList<A
|
|||||||
viewHolder.aorView.text))
|
viewHolder.aorView.text))
|
||||||
setPositiveButton(cxt.getText(R.string.delete)) { dialog, _ ->
|
setPositiveButton(cxt.getText(R.string.delete)) { dialog, _ ->
|
||||||
Api.ua_destroy(ua.uap)
|
Api.ua_destroy(ua.uap)
|
||||||
NewCallHistory.clear(ua.account.aor)
|
CallHistory.clear(ua.account.aor)
|
||||||
Message.clear(ua.account.aor)
|
Message.clear(ua.account.aor)
|
||||||
ua.remove()
|
ua.remove()
|
||||||
AccountsActivity.generateAccounts()
|
AccountsActivity.generateAccounts()
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ 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
|
||||||
@@ -411,18 +410,17 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
Contact.contactsUpdate()
|
Contact.contactsUpdate()
|
||||||
|
|
||||||
val history = CallHistory.get()
|
val history = NewCallHistory.get()
|
||||||
if (history.isEmpty()) {
|
if (history.isEmpty()) {
|
||||||
NewCallHistory.restore()
|
CallHistory.restore()
|
||||||
} else {
|
} else {
|
||||||
for (old in history) {
|
for (old in history) {
|
||||||
val new = NewCallHistory(old.aor, old.peerUri, old.direction)
|
val new = CallHistory(old.aor, old.peerUri, old.direction)
|
||||||
new.stopTime = old.time
|
new.stopTime = old.stopTime
|
||||||
if (old.connected)
|
new.startTime = old.startTime
|
||||||
new.startTime = GregorianCalendar(0, 0, 0)
|
|
||||||
callHistory.add(new)
|
callHistory.add(new)
|
||||||
}
|
}
|
||||||
NewCallHistory.save()
|
CallHistory.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message.restore()
|
Message.restore()
|
||||||
@@ -593,6 +591,8 @@ class BaresipService: Service() {
|
|||||||
|
|
||||||
if (ev[0] == "sndfile dump") {
|
if (ev[0] == "sndfile dump") {
|
||||||
Log.d(TAG, "Got sndfile dump ${ev[1]}")
|
Log.d(TAG, "Got sndfile dump ${ev[1]}")
|
||||||
|
if (Call.calls().size > 0)
|
||||||
|
Call.calls()[0].dumpfile = ev[1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,8 +679,8 @@ class BaresipService: Service() {
|
|||||||
if (!Utils.checkPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO))) {
|
if (!Utils.checkPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO))) {
|
||||||
toast(getString(R.string.no_calls))
|
toast(getString(R.string.no_calls))
|
||||||
if (ua.account.callHistory) {
|
if (ua.account.callHistory) {
|
||||||
NewCallHistory.add(NewCallHistory(aor, peerUri, "in"))
|
CallHistory.add(CallHistory(aor, peerUri, "in"))
|
||||||
NewCallHistory.save()
|
CallHistory.save()
|
||||||
ua.account.missedCalls = true
|
ua.account.missedCalls = true
|
||||||
}
|
}
|
||||||
if (!isMainVisible)
|
if (!isMainVisible)
|
||||||
@@ -761,8 +761,8 @@ class BaresipService: Service() {
|
|||||||
"call rejected" -> {
|
"call rejected" -> {
|
||||||
playUnInterrupted(R.raw.callwaiting, 1)
|
playUnInterrupted(R.raw.callwaiting, 1)
|
||||||
if (ua.account.callHistory) {
|
if (ua.account.callHistory) {
|
||||||
NewCallHistory.add(NewCallHistory(aor, ev[1], "in"))
|
CallHistory.add(CallHistory(aor, ev[1], "in"))
|
||||||
NewCallHistory.save()
|
CallHistory.save()
|
||||||
ua.account.missedCalls = true
|
ua.account.missedCalls = true
|
||||||
if (!isMainVisible)
|
if (!isMainVisible)
|
||||||
return
|
return
|
||||||
@@ -894,29 +894,17 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
val missed = call.startTime == null && call.dir == "in" && !call.rejected
|
val missed = call.startTime == null && call.dir == "in" && !call.rejected
|
||||||
if (ua.account.callHistory) {
|
if (ua.account.callHistory) {
|
||||||
val history = NewCallHistory(aor, call.peerUri, call.dir)
|
val history = CallHistory(aor, call.peerUri, call.dir)
|
||||||
history.startTime = call.startTime
|
history.startTime = call.startTime
|
||||||
history.stopTime = GregorianCalendar()
|
history.stopTime = GregorianCalendar()
|
||||||
NewCallHistory.add(history)
|
if (call.startTime != null && call.dumpfile != "") {
|
||||||
NewCallHistory.save()
|
val recording = filesDir.absolutePath + "/recordings/" +
|
||||||
|
call.dumpfile.substringBeforeLast("-")
|
||||||
|
history.recording = recording
|
||||||
|
}
|
||||||
|
CallHistory.add(history)
|
||||||
|
CallHistory.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) {
|
||||||
@@ -1540,7 +1528,7 @@ class BaresipService: Service() {
|
|||||||
|
|
||||||
val uas = ArrayList<UserAgent>()
|
val uas = ArrayList<UserAgent>()
|
||||||
val calls = ArrayList<Call>()
|
val calls = ArrayList<Call>()
|
||||||
var callHistory = ArrayList<NewCallHistory>()
|
var callHistory = ArrayList<CallHistory>()
|
||||||
var messages = ArrayList<Message>()
|
var messages = ArrayList<Message>()
|
||||||
val messageUpdate = MutableLiveData<Long>()
|
val messageUpdate = MutableLiveData<Long>()
|
||||||
val contactUpdate = MutableLiveData<Long>()
|
val contactUpdate = MutableLiveData<Long>()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
|
|||||||
var zid = ""
|
var zid = ""
|
||||||
var startTime: GregorianCalendar? = null // Set when call is established
|
var startTime: GregorianCalendar? = null // Set when call is established
|
||||||
var referTo = ""
|
var referTo = ""
|
||||||
|
var dumpfile = ""
|
||||||
|
|
||||||
fun add() {
|
fun add() {
|
||||||
BaresipService.calls.add(0, this)
|
BaresipService.calls.add(0, this)
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import java.util.*
|
|||||||
class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<CallRow.Details>) :
|
class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<CallRow.Details>) :
|
||||||
ArrayAdapter<CallRow.Details>(ctx, R.layout.call_detail_row, rows) {
|
ArrayAdapter<CallRow.Details>(ctx, R.layout.call_detail_row, rows) {
|
||||||
|
|
||||||
private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
private val layoutInflater =
|
||||||
|
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
|
||||||
private class ViewHolder(view: View?) {
|
private class ViewHolder(view: View?) {
|
||||||
val directionView = view?.findViewById(R.id.direction) as ImageView
|
val directionView = view?.findViewById(R.id.direction) as ImageView
|
||||||
@@ -72,12 +73,11 @@ 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 recording = rows[position].recording
|
||||||
val time = format.format(startTime.time).toString()
|
if (recording != "") {
|
||||||
if (BaresipService.recordings.containsKey(time)) {
|
|
||||||
viewHolder.durationView.typeface = Typeface.DEFAULT_BOLD
|
viewHolder.durationView.typeface = Typeface.DEFAULT_BOLD
|
||||||
viewHolder.durationView.setOnClickListener {
|
viewHolder.durationView.setOnClickListener {
|
||||||
Utils.playRecording(ctx, BaresipService.recordings[time]!!)
|
Utils.playRecording(ctx, recording)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,5 +85,4 @@ class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<C
|
|||||||
|
|
||||||
return rowView
|
return rowView
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,18 @@ import java.io.*
|
|||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.GregorianCalendar
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
class NewCallHistory(val aor: String, val peerUri: String, val direction: String) : Serializable {
|
class CallHistory(val aor: String, val peerUri: String, val direction: String) : Serializable {
|
||||||
|
|
||||||
var startTime: GregorianCalendar? = null // Set to time when call is established (if ever)
|
var startTime: GregorianCalendar? = null // Set to time when call is established (if ever)
|
||||||
var stopTime = GregorianCalendar() // Set to time when call is closed
|
var stopTime = GregorianCalendar() // Set to time when call is closed
|
||||||
|
var recording = ""
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val serialVersionUID: Long = 1
|
private const val serialVersionUID: Long = 2
|
||||||
private const val CALL_HISTORY_SIZE = 128
|
private const val CALL_HISTORY_SIZE = 128
|
||||||
|
|
||||||
fun add(history: NewCallHistory) {
|
fun add(history: CallHistory) {
|
||||||
BaresipService.callHistory.add(history)
|
BaresipService.callHistory.add(history)
|
||||||
if (aorHistorySize(history.aor) > CALL_HISTORY_SIZE) {
|
if (aorHistorySize(history.aor) > CALL_HISTORY_SIZE) {
|
||||||
var i = 0
|
var i = 0
|
||||||
@@ -44,7 +45,7 @@ class NewCallHistory(val aor: String, val peerUri: String, val direction: String
|
|||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
Log.d(TAG, "Saving history of ${BaresipService.callHistory.size} calls")
|
Log.d(TAG, "Saving history of ${BaresipService.callHistory.size} calls")
|
||||||
val file = File(BaresipService.filesPath, "call_history")
|
val file = File(BaresipService.filesPath, "history")
|
||||||
try {
|
try {
|
||||||
val fos = FileOutputStream(file)
|
val fos = FileOutputStream(file)
|
||||||
val oos = ObjectOutputStream(fos)
|
val oos = ObjectOutputStream(fos)
|
||||||
@@ -58,13 +59,13 @@ class NewCallHistory(val aor: String, val peerUri: String, val direction: String
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun restore() {
|
fun restore() {
|
||||||
val file = File(BaresipService.filesPath, "call_history")
|
val file = File(BaresipService.filesPath, "history")
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
val fis = FileInputStream(file)
|
val fis = FileInputStream(file)
|
||||||
val ois = ObjectInputStream(fis)
|
val ois = ObjectInputStream(fis)
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
BaresipService.callHistory = ois.readObject() as ArrayList<NewCallHistory>
|
BaresipService.callHistory = ois.readObject() as ArrayList<CallHistory>
|
||||||
ois.close()
|
ois.close()
|
||||||
fis.close()
|
fis.close()
|
||||||
Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls")
|
Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls")
|
||||||
@@ -77,28 +78,31 @@ class NewCallHistory(val aor: String, val peerUri: String, val direction: String
|
|||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
fun print() {
|
fun print() {
|
||||||
for (h in BaresipService.callHistory)
|
for (h in BaresipService.callHistory)
|
||||||
Log.d(TAG, "[${h.aor}, ${h.peerUri}, ${h.direction}, ${h.startTime}, ${h.stopTime}]")
|
Log.d(TAG, "[${h.aor}, ${h.peerUri}, ${h.direction}, ${h.startTime}," +
|
||||||
|
"${h.stopTime}, ${h.recording}]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallHistory(val aor: String, val peerUri: String, val direction: String,
|
class NewCallHistory(val aor: String, val peerUri: String, val direction: String) : Serializable {
|
||||||
val connected: Boolean) : Serializable {
|
|
||||||
|
|
||||||
val time: GregorianCalendar = GregorianCalendar()
|
var startTime: GregorianCalendar? = null
|
||||||
|
var stopTime = GregorianCalendar()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun get(): ArrayList<CallHistory> {
|
private const val serialVersionUID: Long = 1
|
||||||
val file = File(BaresipService.filesPath, "calls")
|
|
||||||
var result = ArrayList<CallHistory>()
|
fun get(): ArrayList<NewCallHistory> {
|
||||||
|
val file = File(BaresipService.filesPath, "call_history")
|
||||||
|
var result = ArrayList<NewCallHistory>()
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
val fis = FileInputStream(file)
|
val fis = FileInputStream(file)
|
||||||
val ois = ObjectInputStream(fis)
|
val ois = ObjectInputStream(fis)
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
result = ois.readObject() as ArrayList<CallHistory>
|
result = ois.readObject() as ArrayList<NewCallHistory>
|
||||||
ois.close()
|
ois.close()
|
||||||
fis.close()
|
fis.close()
|
||||||
Log.d(TAG, "Got history of ${result.size} calls")
|
Log.d(TAG, "Got history of ${result.size} calls")
|
||||||
|
|||||||
@@ -4,14 +4,19 @@ import java.util.*
|
|||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class CallRow(val aor: String, val peerUri: String, val direction: Int,
|
class CallRow(val aor: String, val peerUri: String, val direction: Int,
|
||||||
startTime: GregorianCalendar?, val stopTime: GregorianCalendar) {
|
startTime: GregorianCalendar?,
|
||||||
|
val stopTime: GregorianCalendar,
|
||||||
|
private val recording: String)
|
||||||
|
|
||||||
class Details(val direction: Int, val startTime: GregorianCalendar?, val stopTime: GregorianCalendar)
|
{
|
||||||
|
|
||||||
|
class Details(val direction: Int, val startTime: GregorianCalendar?,
|
||||||
|
val stopTime: GregorianCalendar, val recording: String)
|
||||||
|
|
||||||
val details = ArrayList<Details>()
|
val details = ArrayList<Details>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
details.add(Details(direction, startTime, stopTime))
|
details.add(Details(direction, startTime, stopTime, recording))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class CallsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
DialogInterface.BUTTON_POSITIVE -> {
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
removeUaHistoryAt(pos)
|
removeUaHistoryAt(pos)
|
||||||
NewCallHistory.save()
|
CallHistory.save()
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEUTRAL -> {
|
DialogInterface.BUTTON_NEUTRAL -> {
|
||||||
@@ -168,8 +168,8 @@ class CallsActivity : AppCompatActivity() {
|
|||||||
setMessage(String.format(getString(R.string.delete_history_alert),
|
setMessage(String.format(getString(R.string.delete_history_alert),
|
||||||
aor.substringAfter(":")))
|
aor.substringAfter(":")))
|
||||||
setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
||||||
NewCallHistory.clear(aor)
|
CallHistory.clear(aor)
|
||||||
NewCallHistory.save()
|
CallHistory.save()
|
||||||
aorGenerateHistory(aor)
|
aorGenerateHistory(aor)
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
@@ -244,9 +244,11 @@ class CallsActivity : AppCompatActivity() {
|
|||||||
else
|
else
|
||||||
R.drawable.arrow_up_red
|
R.drawable.arrow_up_red
|
||||||
if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri))
|
if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri))
|
||||||
uaHistory.last().details.add(CallRow.Details(direction, h.startTime, h.stopTime))
|
uaHistory.last().details.add(CallRow.Details(direction, h.startTime,
|
||||||
|
h.stopTime, h.recording))
|
||||||
else
|
else
|
||||||
uaHistory.add(CallRow(h.aor, h.peerUri, direction, h.startTime, h.stopTime))
|
uaHistory.add(CallRow(h.aor, h.peerUri, direction, h.startTime,
|
||||||
|
h.stopTime, h.recording))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1200,6 +1200,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
callTimer.stop()
|
callTimer.stop()
|
||||||
}
|
}
|
||||||
|
if (BaresipService.isRecOn) {
|
||||||
|
Api.module_unload("sndfile")
|
||||||
|
BaresipService.isRecOn = false
|
||||||
|
recIcon!!.setIcon(R.drawable.rec_off)
|
||||||
|
}
|
||||||
if (aor == aorSpinner.tag) {
|
if (aor == aorSpinner.tag) {
|
||||||
callUri.inputType = InputType.TYPE_CLASS_TEXT +
|
callUri.inputType = InputType.TYPE_CLASS_TEXT +
|
||||||
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||||
@@ -1892,7 +1897,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val latestPeerUri = NewCallHistory.aorLatestPeerUri(aor)
|
val latestPeerUri = CallHistory.aorLatestPeerUri(aor)
|
||||||
if (latestPeerUri != null)
|
if (latestPeerUri != null)
|
||||||
callUri.setText(Utils.friendlyUri(this, latestPeerUri, ua.account))
|
callUri.setText(Utils.friendlyUri(this, latestPeerUri, ua.account))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user