Create a MxCall interface to better handle call
This commit is contained in:
parent
24a9931abd
commit
03b9904b07
@ -17,40 +17,15 @@
|
||||
package im.vector.matrix.android.api.session.call
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
|
||||
interface CallService {
|
||||
|
||||
fun getTurnServer(callback: MatrixCallback<TurnServer?>)
|
||||
|
||||
/**
|
||||
* Start a call
|
||||
* Send offer SDP to the other participant.
|
||||
* @param callId a callId that the caller can create, it will be used to identify the call for other methods
|
||||
* Create an outgoing call
|
||||
*/
|
||||
fun startCall(callId: String, roomId: String, sdp: SessionDescription, callback: MatrixCallback<String>)
|
||||
|
||||
/**
|
||||
* Accept an incoming call
|
||||
* Send answer SDP to the other participant.
|
||||
*/
|
||||
fun pickUp(callId: String, roomId: String, sdp: SessionDescription, callback: MatrixCallback<String>)
|
||||
|
||||
/**
|
||||
* Send Ice candidate to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidates(callId: String, roomId: String, candidates: List<IceCandidate>)
|
||||
|
||||
/**
|
||||
* Send removed ICE candidates to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>)
|
||||
|
||||
/**
|
||||
* Send a hangup event
|
||||
*/
|
||||
fun hangup(callId: String, roomId: String)
|
||||
fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall
|
||||
|
||||
fun addCallListener(listener: CallsListener)
|
||||
|
||||
|
@ -41,7 +41,7 @@ interface CallsListener {
|
||||
// */
|
||||
// fun onCallHangUp(peerSignalingClient: PeerSignalingClient)
|
||||
|
||||
fun onCallInviteReceived(signalingRoomId: String, fromUserId: String, callInviteContent: CallInviteContent)
|
||||
fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent)
|
||||
|
||||
fun onCallAnswerReceived(callAnswerContent: CallAnswerContent)
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.call
|
||||
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
|
||||
interface MxCallDetail {
|
||||
val isOutgoing: Boolean
|
||||
val roomId: String
|
||||
val otherUserId: String
|
||||
val isVideoCall: Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Define both an incoming call and on outgoing call
|
||||
*/
|
||||
interface MxCall : MxCallDetail {
|
||||
/**
|
||||
* Pick Up the incoming call
|
||||
* It has no effect on outgoing call
|
||||
*/
|
||||
fun accept(sdp: SessionDescription)
|
||||
|
||||
/**
|
||||
* Reject an incoming call
|
||||
* It's an alias to hangUp
|
||||
*/
|
||||
fun reject() = hangUp()
|
||||
|
||||
/**
|
||||
* End the call
|
||||
*/
|
||||
fun hangUp()
|
||||
|
||||
/**
|
||||
* Start a call
|
||||
* Send offer SDP to the other participant.
|
||||
*/
|
||||
fun offerSdp(sdp: SessionDescription)
|
||||
|
||||
/**
|
||||
* Send Ice candidate to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidates(candidates: List<IceCandidate>)
|
||||
|
||||
/**
|
||||
* Send removed ICE candidates to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidateRemovals(candidates: List<IceCandidate>)
|
||||
}
|
@ -20,24 +20,20 @@ import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.extensions.tryThis
|
||||
import im.vector.matrix.android.api.session.call.CallService
|
||||
import im.vector.matrix.android.api.session.call.CallsListener
|
||||
import im.vector.matrix.android.api.session.call.MxCall
|
||||
import im.vector.matrix.android.api.session.call.TurnServer
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.api.session.events.model.UnsignedData
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallCandidatesContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.call.model.MxCallImpl
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.send.RoomEventSender
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
@ -54,71 +50,17 @@ internal class DefaultCallService @Inject constructor(
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun startCall(callId: String, roomId: String, sdp: SessionDescription, callback: MatrixCallback<String>) {
|
||||
val eventContent = CallInviteContent(
|
||||
callId = callId,
|
||||
lifetime = CALL_TIMEOUT_MS,
|
||||
offer = CallInviteContent.Offer(sdp = sdp.description)
|
||||
override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
|
||||
return MxCallImpl(
|
||||
callId = UUID.randomUUID().toString(),
|
||||
isOutgoing = true,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
otherUserId = otherUserId,
|
||||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
roomEventSender = roomEventSender
|
||||
)
|
||||
|
||||
createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = eventContent.toContent()).let { event ->
|
||||
roomEventSender.sendEvent(event)
|
||||
// sendEventTask
|
||||
// .configureWith(
|
||||
// SendEventTask.Params(event = event, cryptoService = cryptoService)
|
||||
// ) {
|
||||
// this.callback = callback
|
||||
// }.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun pickUp(callId: String, roomId: String, sdp: SessionDescription, callback: MatrixCallback<String>) {
|
||||
val eventContent = CallAnswerContent(
|
||||
callId = callId,
|
||||
answer = CallAnswerContent.Answer(sdp = sdp.description)
|
||||
)
|
||||
|
||||
createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = eventContent.toContent()).let { event ->
|
||||
roomEventSender.sendEvent(event)
|
||||
// sendEventTask
|
||||
// .configureWith(
|
||||
// SendEventTask.Params(event = event, cryptoService = cryptoService)
|
||||
// ) {
|
||||
// this.callback = callback
|
||||
// }.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidates(callId: String, roomId: String, candidates: List<IceCandidate>) {
|
||||
val eventContent = CallCandidatesContent(
|
||||
callId = callId,
|
||||
candidates = candidates.map {
|
||||
CallCandidatesContent.Candidate(
|
||||
sdpMid = it.sdpMid,
|
||||
sdpMLineIndex = it.sdpMLineIndex.toString(),
|
||||
candidate = it.sdp
|
||||
)
|
||||
}
|
||||
)
|
||||
createEventAndLocalEcho(type = EventType.CALL_CANDIDATES, roomId = roomId, content = eventContent.toContent()).let { event ->
|
||||
roomEventSender.sendEvent(event)
|
||||
// sendEventTask
|
||||
// .configureWith(
|
||||
// SendEventTask.Params(event = event, cryptoService = cryptoService)
|
||||
// ) {
|
||||
// this.callback = callback
|
||||
// }.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>) {
|
||||
}
|
||||
|
||||
override fun hangup(callId: String, roomId: String) {
|
||||
val eventContent = CallHangupContent(callId = callId)
|
||||
createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = eventContent.toContent()).let { event ->
|
||||
roomEventSender.sendEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addCallListener(listener: CallsListener) {
|
||||
@ -137,8 +79,18 @@ internal class DefaultCallService @Inject constructor(
|
||||
}
|
||||
}
|
||||
EventType.CALL_INVITE -> {
|
||||
event.getClearContent().toModel<CallInviteContent>()?.let {
|
||||
onCallInvite(event.roomId ?: "", event.senderId ?: "", it)
|
||||
event.getClearContent().toModel<CallInviteContent>()?.let { content ->
|
||||
val incomingCall = MxCallImpl(
|
||||
callId = content.callId ?: return@let,
|
||||
isOutgoing = false,
|
||||
roomId = event.roomId ?: return@let,
|
||||
userId = userId,
|
||||
otherUserId = event.senderId ?: return@let,
|
||||
isVideoCall = content.isVideo(),
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
roomEventSender = roomEventSender
|
||||
)
|
||||
onCallInvite(incomingCall, content)
|
||||
}
|
||||
}
|
||||
EventType.CALL_HANGUP -> {
|
||||
@ -165,31 +117,17 @@ internal class DefaultCallService @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallInvite(roomId: String, fromUserId: String, invite: CallInviteContent) {
|
||||
private fun onCallInvite(incomingCall: MxCall, invite: CallInviteContent) {
|
||||
// Ignore the invitation from current user
|
||||
if (fromUserId == userId) return
|
||||
if (incomingCall.otherUserId == userId) return
|
||||
|
||||
callListeners.toList().forEach {
|
||||
tryThis {
|
||||
it.onCallInviteReceived(roomId, fromUserId, invite)
|
||||
it.onCallInviteReceived(incomingCall, invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEventAndLocalEcho(localId: String = LocalEcho.createLocalEchoId(), type: String, roomId: String, content: Content): Event {
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = System.currentTimeMillis(),
|
||||
senderId = userId,
|
||||
eventId = localId,
|
||||
type = type,
|
||||
content = content,
|
||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||
).also {
|
||||
localEchoEventFactory.createLocalEcho(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CALL_TIMEOUT_MS = 120_000
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.call.model
|
||||
|
||||
import im.vector.matrix.android.api.session.call.MxCall
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.api.session.events.model.UnsignedData
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallCandidatesContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||
import im.vector.matrix.android.internal.session.call.DefaultCallService
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.send.RoomEventSender
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
|
||||
internal class MxCallImpl(
|
||||
val callId: String,
|
||||
override val isOutgoing: Boolean,
|
||||
override val roomId: String,
|
||||
private val userId: String,
|
||||
override val otherUserId: String,
|
||||
override val isVideoCall: Boolean,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val roomEventSender: RoomEventSender
|
||||
) : MxCall {
|
||||
|
||||
override fun offerSdp(sdp: SessionDescription) {
|
||||
if (!isOutgoing) return
|
||||
|
||||
CallInviteContent(
|
||||
callId = callId,
|
||||
lifetime = DefaultCallService.CALL_TIMEOUT_MS,
|
||||
offer = CallInviteContent.Offer(sdp = sdp.description)
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = it.toContent()) }
|
||||
.also { roomEventSender.sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidates(candidates: List<IceCandidate>) {
|
||||
CallCandidatesContent(
|
||||
callId = callId,
|
||||
candidates = candidates.map {
|
||||
CallCandidatesContent.Candidate(
|
||||
sdpMid = it.sdpMid,
|
||||
sdpMLineIndex = it.sdpMLineIndex.toString(),
|
||||
candidate = it.sdp
|
||||
)
|
||||
}
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_CANDIDATES, roomId = roomId, content = it.toContent()) }
|
||||
.also { roomEventSender.sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidateRemovals(candidates: List<IceCandidate>) {
|
||||
}
|
||||
|
||||
override fun hangUp() {
|
||||
CallHangupContent(
|
||||
callId = callId
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) }
|
||||
.also { roomEventSender.sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun accept(sdp: SessionDescription) {
|
||||
if (isOutgoing) return
|
||||
|
||||
CallAnswerContent(
|
||||
callId = callId,
|
||||
answer = CallAnswerContent.Answer(sdp = sdp.description)
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = it.toContent()) }
|
||||
.also { roomEventSender.sendEvent(it) }
|
||||
}
|
||||
|
||||
private fun createEventAndLocalEcho(localId: String = LocalEcho.createLocalEchoId(), type: String, roomId: String, content: Content): Event {
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = System.currentTimeMillis(),
|
||||
senderId = userId,
|
||||
eventId = localId,
|
||||
type = type,
|
||||
content = content,
|
||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||
)
|
||||
.also { localEchoEventFactory.createLocalEcho(it) }
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ import butterknife.BindView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import im.vector.matrix.android.api.session.call.EglUtils
|
||||
import im.vector.matrix.android.api.session.call.MxCallDetail
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
@ -92,8 +93,6 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
||||
|
||||
private val iceCandidateSource: PublishSubject<IceCandidate> = PublishSubject.create()
|
||||
|
||||
|
||||
|
||||
var callHeadsUpService: CallHeadsUpService? = null
|
||||
private val serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
@ -363,7 +362,7 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
||||
//peerConnectionManager.answerReceived("", sdp)
|
||||
// peerConnection?.setRemoteDescription(object : SdpObserverAdapter() {}, sdp)
|
||||
}
|
||||
is VectorCallViewEvents.CallHangup -> {
|
||||
is VectorCallViewEvents.CallHangup -> {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@ -416,9 +415,9 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
||||
// mandatory.add(MediaConstraints.KeyValuePair("googHighpassFilter", "true"))
|
||||
// }
|
||||
|
||||
fun newIntent(context: Context, roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean): Intent {
|
||||
fun newIntent(context: Context, mxCall: MxCallDetail): Intent {
|
||||
return Intent(context, VectorCallActivity::class.java).apply {
|
||||
putExtra(MvRx.KEY_ARG, CallArgs(roomId, participantUserId, isIncomingCall, isVideoCall))
|
||||
putExtra(MvRx.KEY_ARG, CallArgs(mxCall.roomId, mxCall.otherUserId, !mxCall.isOutgoing, mxCall.isVideoCall))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -447,6 +446,5 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
||||
}
|
||||
|
||||
override fun sendOffer(sessionDescription: SessionDescription) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.call.CallsListener
|
||||
import im.vector.matrix.android.api.session.call.MxCall
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||
@ -62,7 +63,7 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallInviteReceived(signalingRoomId: String, fromUserId: String, callInviteContent: CallInviteContent) {
|
||||
override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) {
|
||||
}
|
||||
|
||||
override fun onCallHangupReceived(callHangupContent: CallHangupContent) {
|
||||
|
@ -22,10 +22,11 @@ import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.extensions.tryThis
|
||||
import im.vector.matrix.android.api.session.call.CallsListener
|
||||
import im.vector.matrix.android.api.session.call.EglUtils
|
||||
import im.vector.matrix.android.api.session.call.MxCall
|
||||
import im.vector.matrix.android.api.session.call.MxCallDetail
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||
@ -53,7 +54,6 @@ import org.webrtc.VideoSource
|
||||
import org.webrtc.VideoTrack
|
||||
import timber.log.Timber
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
@ -114,10 +114,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
|
||||
var callHeadsUpService: CallHeadsUpService? = null
|
||||
|
||||
private var callId: String? = null
|
||||
private var signalingRoomId: String? = null
|
||||
private var participantUserId: String? = null
|
||||
private var isVideoCall: Boolean? = null
|
||||
private var currentCall: MxCall? = null
|
||||
|
||||
private val serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
@ -275,11 +272,8 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
.subscribe {
|
||||
// omit empty :/
|
||||
if (it.isNotEmpty()) {
|
||||
Timber.v("## Sending local ice candidates to callId: $callId roomId: $signalingRoomId")
|
||||
sessionHolder
|
||||
.getActiveSession()
|
||||
.callService()
|
||||
.sendLocalIceCandidates(callId ?: "", signalingRoomId ?: "", it)
|
||||
Timber.v("## Sending local ice candidates to call")
|
||||
currentCall?.sendLocalIceCandidates(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,11 +298,8 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
peerConnection?.setLocalDescription(object : SdpObserverAdapter() {
|
||||
override fun onSetSuccess() {
|
||||
Timber.v("## setLocalDescription success")
|
||||
val id = UUID.randomUUID().toString()
|
||||
callId = id
|
||||
Timber.v("## sending offer to callId: $id roomId: $signalingRoomId")
|
||||
sessionHolder.getActiveSession().callService().startCall(id, signalingRoomId
|
||||
?: "", sessionDescription, object : MatrixCallback<String> {})
|
||||
Timber.v("## sending offer")
|
||||
currentCall?.offerSdp(sessionDescription)
|
||||
}
|
||||
}, sessionDescription)
|
||||
}
|
||||
@ -330,7 +321,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
|
||||
localMediaStream = peerConnectionFactory?.createLocalMediaStream("ARDAMS") // magic value?
|
||||
|
||||
if (isVideoCall == true) {
|
||||
if (currentCall?.isVideoCall == true) {
|
||||
val cameraIterator = if (Camera2Enumerator.isSupported(context)) Camera2Enumerator(context) else Camera1Enumerator(false)
|
||||
val frontCamera = cameraIterator.deviceNames
|
||||
?.firstOrNull { cameraIterator.isFrontFacing(it) }
|
||||
@ -417,55 +408,55 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun startOutgoingCall(context: Context, signalingRoomId: String, participantUserId: String, isVideoCall: Boolean) {
|
||||
this.signalingRoomId = signalingRoomId
|
||||
this.participantUserId = participantUserId
|
||||
this.isVideoCall = isVideoCall
|
||||
fun startOutgoingCall(context: Context, signalingRoomId: String, otherUserId: String, isVideoCall: Boolean) {
|
||||
val createdCall = sessionHolder.getSafeActiveSession()?.callService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return
|
||||
currentCall = createdCall
|
||||
|
||||
startHeadsUpService(signalingRoomId, sessionHolder.getActiveSession().myUserId, false, isVideoCall)
|
||||
context.startActivity(VectorCallActivity.newIntent(context, signalingRoomId, participantUserId, false, isVideoCall))
|
||||
startHeadsUpService(createdCall)
|
||||
context.startActivity(VectorCallActivity.newIntent(context, createdCall))
|
||||
|
||||
startCall()
|
||||
sendSdpOffer()
|
||||
}
|
||||
|
||||
override fun onCallInviteReceived(signalingRoomId: String, fromUserId: String, callInviteContent: CallInviteContent) {
|
||||
this.callId = callInviteContent.callId
|
||||
this.signalingRoomId = signalingRoomId
|
||||
this.participantUserId = fromUserId
|
||||
this.isVideoCall = callInviteContent.isVideo()
|
||||
override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) {
|
||||
// TODO What if a call is currently active?
|
||||
if (currentCall != null) {
|
||||
Timber.w("TODO: Automatically reject incoming call?")
|
||||
return
|
||||
}
|
||||
|
||||
startHeadsUpService(signalingRoomId, fromUserId, true, callInviteContent.isVideo())
|
||||
context.startActivity(VectorCallActivity.newIntent(context, signalingRoomId, fromUserId, false, callInviteContent.isVideo()))
|
||||
currentCall = mxCall
|
||||
|
||||
startHeadsUpService(mxCall)
|
||||
context.startActivity(VectorCallActivity.newIntent(context, mxCall))
|
||||
|
||||
startCall()
|
||||
}
|
||||
|
||||
private fun startHeadsUpService(roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean) {
|
||||
val callHeadsUpServiceIntent = CallHeadsUpService.newInstance(context, roomId, participantUserId, isIncomingCall, isVideoCall)
|
||||
private fun startHeadsUpService(mxCall: MxCallDetail) {
|
||||
val callHeadsUpServiceIntent = CallHeadsUpService.newInstance(context, mxCall)
|
||||
ContextCompat.startForegroundService(context, callHeadsUpServiceIntent)
|
||||
|
||||
context.bindService(Intent(context, CallHeadsUpService::class.java), serviceConnection, 0)
|
||||
}
|
||||
|
||||
fun endCall() {
|
||||
if (callId != null && signalingRoomId != null) {
|
||||
sessionHolder.getActiveSession().callService().hangup(callId!!, signalingRoomId!!)
|
||||
}
|
||||
currentCall?.hangUp()
|
||||
currentCall = null
|
||||
close()
|
||||
}
|
||||
|
||||
override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
|
||||
this.callId = callAnswerContent.callId
|
||||
|
||||
executor.execute {
|
||||
Timber.v("## answerReceived $callId")
|
||||
Timber.v("## answerReceived")
|
||||
val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp)
|
||||
peerConnection?.setRemoteDescription(object : SdpObserverAdapter() {}, sdp)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallHangupReceived(callHangupContent: CallHangupContent) {
|
||||
currentCall = null
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import im.vector.matrix.android.api.session.call.MxCallDetail
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.features.call.VectorCallActivity
|
||||
|
||||
@ -50,7 +51,7 @@ class CallHeadsUpService : Service() {
|
||||
|
||||
createNotificationChannel()
|
||||
|
||||
val title = callHeadsUpServiceArgs?.participantUserId ?: ""
|
||||
val title = callHeadsUpServiceArgs?.otherUserId ?: ""
|
||||
val description = when {
|
||||
callHeadsUpServiceArgs?.isIncomingCall == false -> getString(R.string.call_ring)
|
||||
callHeadsUpServiceArgs?.isVideoCall == true -> getString(R.string.incoming_video_call)
|
||||
@ -133,8 +134,8 @@ class CallHeadsUpService : Service() {
|
||||
|
||||
private const val NOTIFICATION_ID = 999
|
||||
|
||||
fun newInstance(context: Context, roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean): Intent {
|
||||
val args = CallHeadsUpServiceArgs(roomId, participantUserId, isIncomingCall, isVideoCall)
|
||||
fun newInstance(context: Context, mxCall: MxCallDetail): Intent {
|
||||
val args = CallHeadsUpServiceArgs(mxCall.roomId, mxCall.otherUserId, !mxCall.isOutgoing, mxCall.isVideoCall)
|
||||
return Intent(context, CallHeadsUpService::class.java).apply {
|
||||
putExtra(EXTRA_CALL_HEADS_UP_SERVICE_PARAMS, args)
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import kotlinx.android.parcel.Parcelize
|
||||
@Parcelize
|
||||
data class CallHeadsUpServiceArgs(
|
||||
val roomId: String,
|
||||
val participantUserId: String,
|
||||
val otherUserId: String,
|
||||
val isIncomingCall: Boolean,
|
||||
val isVideoCall: Boolean
|
||||
) : Parcelable
|
||||
|
Loading…
x
Reference in New Issue
Block a user