feat: hanging up and bottom sheet behaviors should work now
This commit is contained in:
parent
b3576336d9
commit
459dfa72c2
|
@ -1,6 +1,9 @@
|
|||
package org.thoughtcrime.securesms.calls
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.android.synthetic.main.activity_webrtc_tests.*
|
||||
|
@ -9,6 +12,7 @@ import kotlinx.coroutines.isActive
|
|||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.Debouncer
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
|
@ -28,7 +32,7 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
private const val LOCAL_STREAM_ID = "local_track"
|
||||
|
||||
const val ACTION_ANSWER = "answer"
|
||||
const val ACTION_UPDATE_ICE = "updateIce"
|
||||
const val ACTION_END = "end-call"
|
||||
|
||||
const val EXTRA_SDP = "WebRtcTestsActivity_EXTRA_SDP"
|
||||
const val EXTRA_ADDRESS = "WebRtcTestsActivity_EXTRA_ADDRESS"
|
||||
|
@ -42,6 +46,8 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
private val audioSource by lazy { connectionFactory.createAudioSource(MediaConstraints()) }
|
||||
private val videoCapturer by lazy { createCameraCapturer(Camera2Enumerator(this)) }
|
||||
|
||||
private val acceptedCallMessageHashes = mutableSetOf<Int>()
|
||||
|
||||
private val connectionFactory by lazy {
|
||||
|
||||
val decoderFactory = DefaultVideoDecoderFactory(eglBase.eglBaseContext)
|
||||
|
@ -127,13 +133,44 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
peerConnection.createOffer(this, MediaConstraints())
|
||||
}
|
||||
|
||||
lifecycleScope.launchWhenResumed {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
while (this.isActive) {
|
||||
delay(5_000L)
|
||||
peerConnection.getStats(this@WebRtcTestsActivity)
|
||||
val answer = synchronized(WebRtcUtils.callCache) {
|
||||
WebRtcUtils.callCache[callAddress]?.firstOrNull { it.type == SignalServiceProtos.CallMessage.Type.ANSWER }
|
||||
}
|
||||
if (answer != null) {
|
||||
peerConnection.setRemoteDescription(
|
||||
this@WebRtcTestsActivity,
|
||||
SessionDescription(SessionDescription.Type.ANSWER, answer.sdps[0])
|
||||
)
|
||||
break
|
||||
}
|
||||
delay(2_000L)
|
||||
}
|
||||
}
|
||||
|
||||
registerReceiver(object: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
endCall()
|
||||
}
|
||||
}, IntentFilter(ACTION_END))
|
||||
|
||||
lifecycleScope.launchWhenResumed {
|
||||
while (this.isActive) {
|
||||
delay(2_000L)
|
||||
peerConnection.getStats(this@WebRtcTestsActivity)
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
val set = WebRtcUtils.callCache[callAddress] ?: mutableSetOf()
|
||||
set.filter { it.hashCode() !in acceptedCallMessageHashes
|
||||
&& it.type == SignalServiceProtos.CallMessage.Type.ICE_CANDIDATES }.forEach { callMessage ->
|
||||
callMessage.iceCandidates().forEach { candidate ->
|
||||
peerConnection.addIceCandidate(candidate)
|
||||
}
|
||||
acceptedCallMessageHashes.add(callMessage.hashCode())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStatsDelivered(statsReport: RTCStatsReport?) {
|
||||
|
@ -143,11 +180,11 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
}
|
||||
|
||||
private fun endCall() {
|
||||
peerConnection.close()
|
||||
MessageSender.sendNonDurably(
|
||||
CallMessage(SignalServiceProtos.CallMessage.Type.END_CALL,emptyList(),emptyList(), emptyList()),
|
||||
CallMessage.endCall(),
|
||||
callAddress
|
||||
)
|
||||
peerConnection.close()
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@ -156,29 +193,6 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
endCall()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
if (intent == null) return
|
||||
callAddress = intent.getParcelableExtra(EXTRA_ADDRESS) ?: run { finish(); return }
|
||||
when (intent.action) {
|
||||
ACTION_ANSWER -> {
|
||||
peerConnection.setRemoteDescription(this,
|
||||
SessionDescription(SessionDescription.Type.ANSWER, intent.getStringArrayExtra(EXTRA_SDP)!![0])
|
||||
)
|
||||
}
|
||||
ACTION_UPDATE_ICE -> {
|
||||
val sdpIndexes = intent.getIntArrayExtra(EXTRA_SDP_MLINE_INDEXES)!!
|
||||
val sdpMids = intent.getStringArrayExtra(EXTRA_SDP_MIDS)!!
|
||||
val sdp = intent.getStringArrayExtra(EXTRA_SDP)!!
|
||||
val amount = minOf(sdpIndexes.size, sdpMids.size)
|
||||
(0 until amount).map { index ->
|
||||
val candidate = IceCandidate(sdpMids[index], sdpIndexes[index], sdp[index])
|
||||
peerConnection.addIceCandidate(candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCameraCapturer(enumerator: CameraEnumerator): CameraVideoCapturer? {
|
||||
val deviceNames = enumerator.deviceNames
|
||||
|
||||
|
@ -316,4 +330,11 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
|
|||
Log.d("Loki-RTC", "onSetFailure: $p0")
|
||||
}
|
||||
|
||||
private fun CallMessage.iceCandidates(): List<IceCandidate> {
|
||||
val candidateSize = sdpMids.size
|
||||
return (0 until candidateSize).map { i ->
|
||||
IceCandidate(sdpMids[i], sdpMLineIndexes[i], sdps[i])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import androidx.loader.app.LoaderManager
|
|||
import androidx.loader.content.Loader
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.seed_reminder_stub.*
|
||||
import kotlinx.android.synthetic.main.seed_reminder_stub.view.*
|
||||
|
@ -42,6 +43,7 @@ import org.session.libsignal.utilities.toHexString
|
|||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.MuteDialog
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.calls.WebRtcTestsActivity
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
|
@ -138,6 +140,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
|||
lifecycleScope.launchWhenCreated {
|
||||
// web rtc channel handling
|
||||
for (message in WebRtcUtils.SIGNAL_QUEUE) {
|
||||
|
||||
val sender = Address.fromSerialized(message.sender!!)
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
val set = WebRtcUtils.callCache[sender] ?: mutableSetOf()
|
||||
|
@ -156,37 +159,21 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
|||
show(this@HomeActivity.supportFragmentManager,"call-sheet")
|
||||
}
|
||||
}
|
||||
ICE_CANDIDATES -> {
|
||||
// do nothing, already have candidates saved
|
||||
}
|
||||
END_CALL -> {
|
||||
// do nothing, maybe clear the callCache or something
|
||||
// dismiss the call sheet
|
||||
supportFragmentManager.findFragmentByTag("call-sheet")?.let { callSheet ->
|
||||
if (callSheet is BottomSheetDialogFragment) {
|
||||
callSheet.dismiss()
|
||||
}
|
||||
}
|
||||
// clear the callCache for this sender
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
WebRtcUtils.callCache[sender] = mutableSetOf()
|
||||
}
|
||||
sendBroadcast(Intent(WebRtcTestsActivity.ACTION_END))
|
||||
}
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
// val intent = Intent(this@HomeActivity, WebRtcTestsActivity::class.java)
|
||||
// val bundle = bundleOf(
|
||||
// WebRtcTestsActivity.EXTRA_ADDRESS to sender,
|
||||
// )
|
||||
// if (message.sdps.isNotEmpty() && message.sdpMids.isEmpty()) {
|
||||
// // offer message
|
||||
// Log.d("Loki-RTC", "answer receive")
|
||||
// val sdps = message.sdps
|
||||
// intent.action = WebRtcTestsActivity.ACTION_ANSWER
|
||||
// bundle.putStringArray(WebRtcTestsActivity.EXTRA_SDP, sdps.toTypedArray())
|
||||
// } else if (message.sdpMids.isNotEmpty()) {
|
||||
// // ice candidates message
|
||||
// Log.d("Loki-RTC", "update ice intent")
|
||||
// val sdpMLineIndexes = message.sdpMLineIndexes
|
||||
// val sdpMids = message.sdpMids
|
||||
// val sdps = message.sdps
|
||||
// intent.action = WebRtcTestsActivity.ACTION_UPDATE_ICE
|
||||
// bundle.putStringArray(WebRtcTestsActivity.EXTRA_SDP, sdps.toTypedArray())
|
||||
// bundle.putIntArray(WebRtcTestsActivity.EXTRA_SDP_MLINE_INDEXES, sdpMLineIndexes.toIntArray())
|
||||
// bundle.putStringArray(WebRtcTestsActivity.EXTRA_SDP_MIDS, sdpMids.toTypedArray())
|
||||
// }
|
||||
//
|
||||
// intent.putExtras(bundle)
|
||||
// startActivity(intent)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launchWhenStarted {
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
package org.thoughtcrime.securesms.webrtc
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.*
|
||||
import kotlinx.android.synthetic.main.fragment_call_bottom_sheet.*
|
||||
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.nameTextView
|
||||
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.profilePictureView
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.calls.WebRtcTestsActivity
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
|
||||
class CallBottomSheet: BottomSheetDialogFragment() {
|
||||
|
@ -19,6 +26,8 @@ class CallBottomSheet: BottomSheetDialogFragment() {
|
|||
const val ARGUMENT_TYPE = "CallBottomSheet_TYPE"
|
||||
}
|
||||
|
||||
private lateinit var address: Address
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -30,9 +39,8 @@ class CallBottomSheet: BottomSheetDialogFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val address = arguments?.getParcelable<Address>(ARGUMENT_ADDRESS) ?: return dismiss()
|
||||
address = arguments?.getParcelable(ARGUMENT_ADDRESS) ?: return dismiss()
|
||||
val sdp = arguments?.getStringArray(ARGUMENT_SDP) ?: return dismiss()
|
||||
val type = arguments?.getString(ARGUMENT_TYPE) ?: return dismiss()
|
||||
val recipient = Recipient.from(requireContext(), address, false)
|
||||
profilePictureView.publicKey = address.serialize()
|
||||
profilePictureView.glide = GlideApp.with(this)
|
||||
|
@ -41,5 +49,23 @@ class CallBottomSheet: BottomSheetDialogFragment() {
|
|||
|
||||
nameTextView.text = recipient.name ?: address.serialize()
|
||||
|
||||
acceptButton.setOnClickListener {
|
||||
val intent = Intent(requireContext(), WebRtcTestsActivity::class.java)
|
||||
val bundle = bundleOf(
|
||||
WebRtcTestsActivity.EXTRA_ADDRESS to address,
|
||||
)
|
||||
intent.action = WebRtcTestsActivity.ACTION_ANSWER
|
||||
bundle.putStringArray(WebRtcTestsActivity.EXTRA_SDP, sdp)
|
||||
|
||||
intent.putExtras(bundle)
|
||||
startActivity(intent)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
declineButton.setOnClickListener {
|
||||
MessageSender.sendNonDurably(CallMessage.endCall(), address)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@ class CallMessage(): ControlMessage() {
|
|||
|
||||
override val ttl: Long = 5 * 60 * 1000
|
||||
|
||||
override fun isValid(): Boolean = super.isValid() && type != null && !sdps.isNullOrEmpty()
|
||||
override fun isValid(): Boolean = super.isValid() && type != null
|
||||
&& (!sdps.isNullOrEmpty() || type == SignalServiceProtos.CallMessage.Type.END_CALL)
|
||||
|
||||
constructor(type: SignalServiceProtos.CallMessage.Type,
|
||||
sdps: List<String>,
|
||||
|
@ -28,6 +29,8 @@ class CallMessage(): ControlMessage() {
|
|||
companion object {
|
||||
const val TAG = "CallMessage"
|
||||
|
||||
fun endCall() = CallMessage(SignalServiceProtos.CallMessage.Type.END_CALL, emptyList(), emptyList(), emptyList())
|
||||
|
||||
fun fromProto(proto: SignalServiceProtos.Content): CallMessage? {
|
||||
val callMessageProto = if (proto.hasCallMessage()) proto.callMessage else return null
|
||||
val type = callMessageProto.type
|
||||
|
@ -56,4 +59,32 @@ class CallMessage(): ControlMessage() {
|
|||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as CallMessage
|
||||
|
||||
if (type != other.type) return false
|
||||
if (sdps != other.sdps) return false
|
||||
if (sdpMLineIndexes != other.sdpMLineIndexes) return false
|
||||
if (sdpMids != other.sdpMids) return false
|
||||
if (isSelfSendValid != other.isSelfSendValid) return false
|
||||
if (ttl != other.ttl) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = type?.hashCode() ?: 0
|
||||
result = 31 * result + sdps.hashCode()
|
||||
result = 31 * result + sdpMLineIndexes.hashCode()
|
||||
result = 31 * result + sdpMids.hashCode()
|
||||
result = 31 * result + isSelfSendValid.hashCode()
|
||||
result = 31 * result + ttl.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue