mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
VoIP: add select answer
This commit is contained in:
parent
ba11ca0e9d
commit
03e89743b4
@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
|
||||
interface CallListener {
|
||||
/**
|
||||
@ -45,5 +46,10 @@ interface CallListener {
|
||||
*/
|
||||
fun onCallRejectReceived(callRejectContent: CallRejectContent)
|
||||
|
||||
/**
|
||||
* Called when an answer has been selected
|
||||
*/
|
||||
fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent)
|
||||
|
||||
fun onCallManagedByOtherSession(callId: String)
|
||||
}
|
||||
|
@ -51,6 +51,11 @@ interface MxCall : MxCallDetail {
|
||||
*/
|
||||
fun accept(sdp: SessionDescription)
|
||||
|
||||
/**
|
||||
* This has to be sent by the caller's client once it has chosen an answer.
|
||||
*/
|
||||
fun selectAnswer()
|
||||
|
||||
/**
|
||||
* Reject an incoming call
|
||||
*/
|
||||
|
@ -40,7 +40,8 @@ data class CallHangupContent(
|
||||
/**
|
||||
* Optional error reason for the hangup. This should not be provided when the user naturally ends or rejects the call.
|
||||
* When there was an error in the call negotiation, this should be `ice_failed` for when ICE negotiation fails
|
||||
* or `invite_timeout` for when the other party did not answer in time. One of: ["ice_failed", "invite_timeout"]
|
||||
* or `invite_timeout` for when the other party did not answer in time.
|
||||
* One of: ["ice_failed", "invite_timeout"]
|
||||
*/
|
||||
@Json(name = "reason") val reason: Reason? = null
|
||||
) : CallSignallingContent {
|
||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
|
||||
/**
|
||||
* Dispatch each method safely to all listeners.
|
||||
@ -54,6 +55,10 @@ class CallListenersDispatcher(private val listeners: Set<CallListener>) : CallLi
|
||||
it.onCallManagedByOtherSession(callId)
|
||||
}
|
||||
|
||||
override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) = dispatch {
|
||||
it.onCallSelectAnswerReceived(callSelectAnswerContent)
|
||||
}
|
||||
|
||||
private fun dispatch(lambda: (CallListener) -> Unit) {
|
||||
listeners.toList().forEach {
|
||||
tryOrNull {
|
||||
|
@ -31,6 +31,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSignallingContent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.NoOpCancellable
|
||||
@ -152,9 +153,31 @@ internal class DefaultCallSignalingService @Inject constructor(
|
||||
EventType.CALL_CANDIDATES -> {
|
||||
handleCallCandidatesEvent(event)
|
||||
}
|
||||
EventType.CALL_SELECT_ANSWER -> {
|
||||
handleCallSelectAnswerEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCallSelectAnswerEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallSelectAnswerContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
if (call.isOutgoing) {
|
||||
Timber.v("Got selectAnswer for an outbound call: ignoring")
|
||||
return
|
||||
}
|
||||
val selectedPartyId = content.selectedPartyId
|
||||
if (selectedPartyId == null) {
|
||||
Timber.w("Got nonsensical select_answer with null selected_party_id: ignoring")
|
||||
return
|
||||
}
|
||||
callListenersDispatcher.onCallSelectAnswerReceived(content)
|
||||
}
|
||||
|
||||
private fun handleCallCandidatesEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallCandidatesContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
@ -185,7 +208,7 @@ internal class DefaultCallSignalingService @Inject constructor(
|
||||
val content = event.getClearContent().toModel<CallHangupContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.state != CallState.Terminated) {
|
||||
// Need to check for party_id?
|
||||
// Need to check for party_id?
|
||||
activeCallHandler.removeCall(content.callId)
|
||||
callListenersDispatcher.onCallHangupReceived(content)
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
|
||||
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
|
||||
@ -143,6 +144,7 @@ internal class MxCallImpl(
|
||||
CallHangupContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
reason = CallHangupContent.Reason.USER_HANGUP
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
@ -162,6 +164,19 @@ internal class MxCallImpl(
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override fun selectAnswer() {
|
||||
Timber.v("## VOIP select answer $callId")
|
||||
if (isOutgoing) return
|
||||
state = CallState.Answering
|
||||
CallSelectAnswerContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
selectedPartyId = opponentPartyId?.getOrNull()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_SELECT_ANSWER, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
private fun createEventAndLocalEcho(localId: String = LocalEcho.createLocalEchoId(), type: String, roomId: String, content: Content): Event {
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
|
@ -31,6 +31,7 @@ import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import io.reactivex.subjects.ReplaySubject
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
@ -43,6 +44,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
import org.webrtc.AudioSource
|
||||
import org.webrtc.AudioTrack
|
||||
import org.webrtc.Camera1Enumerator
|
||||
@ -303,6 +305,10 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
callContext.peerConnection?.setLocalDescription(object : SdpObserverAdapter() {}, p0)
|
||||
// send offer to peer
|
||||
currentCall?.mxCall?.offerSdp(p0)
|
||||
|
||||
if(currentCall?.mxCall?.opponentPartyId?.hasValue().orFalse()){
|
||||
currentCall?.mxCall?.selectAnswer()
|
||||
}
|
||||
}
|
||||
}, constraints)
|
||||
}
|
||||
@ -884,6 +890,21 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
||||
endCall(false)
|
||||
}
|
||||
|
||||
override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) {
|
||||
val call = currentCall ?: return
|
||||
if (call.mxCall.callId != callSelectAnswerContent.callId) return Unit.also {
|
||||
Timber.w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}")
|
||||
}
|
||||
val selectedPartyId = callSelectAnswerContent.selectedPartyId
|
||||
if (selectedPartyId != call.mxCall.ourPartyId) {
|
||||
Timber.i("Got select_answer for party ID ${selectedPartyId}: we are party ID ${call.mxCall.ourPartyId}.");
|
||||
// The other party has picked somebody else's answer
|
||||
call.mxCall.state = CallState.Terminated
|
||||
endCall(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCallManagedByOtherSession(callId: String) {
|
||||
Timber.v("## VOIP onCallManagedByOtherSession: $callId")
|
||||
currentCall = null
|
||||
|
Loading…
Reference in New Issue
Block a user