Call transfer: prepare code for consult feature

This commit is contained in:
ganfra 2021-05-25 15:21:54 +02:00
parent a9c61dc309
commit 8eeae51cc6
8 changed files with 75 additions and 11 deletions

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.api.session.call
import java.util.UUID
object CallIdGenerator {
fun generate() = UUID.randomUUID().toString()
}

View file

@ -92,7 +92,10 @@ interface MxCall : MxCallDetail {
/** /**
* Send a m.call.replaces event to initiate call transfer. * Send a m.call.replaces event to initiate call transfer.
*/ */
suspend fun transfer(targetUserId: String, targetRoomId: String?) suspend fun transfer(targetUserId: String,
targetRoomId: String?,
createCallId: String?,
awaitCallId: String?)
fun addListener(listener: StateListener) fun addListener(listener: StateListener)
fun removeListener(listener: StateListener) fun removeListener(listener: StateListener)

View file

@ -56,6 +56,9 @@ data class CallHangupContent(
@Json(name = "user_hangup") @Json(name = "user_hangup")
USER_HANGUP, USER_HANGUP,
@Json(name = "replaced")
REPLACED,
@Json(name = "user_media_failed") @Json(name = "user_media_failed")
USER_MEDIA_FAILED, USER_MEDIA_FAILED,

View file

@ -42,7 +42,7 @@ data class CallReplacesContent(
* (possibly waiting for user confirmation) and then continues the transfer in this room. * (possibly waiting for user confirmation) and then continues the transfer in this room.
* If absent, the transferee contacts the Matrix User ID given in the target_user field in a room of its choosing. * If absent, the transferee contacts the Matrix User ID given in the target_user field in a room of its choosing.
*/ */
@Json(name = "target_room") val targerRoomId: String? = null, @Json(name = "target_room") val targetRoomId: String? = null,
/** /**
* An object giving information about the transfer target * An object giving information about the transfer target
*/ */

View file

@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.session.call package org.matrix.android.sdk.internal.session.call
import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.session.call.CallIdGenerator
import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
@ -63,7 +64,7 @@ internal class MxCallFactory @Inject constructor(
fun createOutgoingCall(roomId: String, opponentUserId: String, isVideoCall: Boolean): MxCall { fun createOutgoingCall(roomId: String, opponentUserId: String, isVideoCall: Boolean): MxCall {
return MxCallImpl( return MxCallImpl(
callId = UUID.randomUUID().toString(), callId = CallIdGenerator.generate(),
isOutgoing = true, isOutgoing = true,
roomId = roomId, roomId = roomId,
userId = userId, userId = userId,

View file

@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.session.call.model package org.matrix.android.sdk.internal.session.call.model
import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.session.call.CallIdGenerator
import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Content
@ -202,7 +203,10 @@ internal class MxCallImpl(
.also { eventSenderProcessor.postEvent(it) } .also { eventSenderProcessor.postEvent(it) }
} }
override suspend fun transfer(targetUserId: String, targetRoomId: String?) { override suspend fun transfer(targetUserId: String,
targetRoomId: String?,
createCallId: String?,
awaitCallId: String?) {
val profileInfoParams = GetProfileInfoTask.Params(targetUserId) val profileInfoParams = GetProfileInfoTask.Params(targetUserId)
val profileInfo = try { val profileInfo = try {
getProfileInfoTask.execute(profileInfoParams) getProfileInfoTask.execute(profileInfoParams)
@ -213,15 +217,16 @@ internal class MxCallImpl(
CallReplacesContent( CallReplacesContent(
callId = callId, callId = callId,
partyId = ourPartyId, partyId = ourPartyId,
replacementId = UUID.randomUUID().toString(), replacementId = CallIdGenerator.generate(),
version = MxCall.VOIP_PROTO_VERSION.toString(), version = MxCall.VOIP_PROTO_VERSION.toString(),
targetUser = CallReplacesContent.TargetUser( targetUser = CallReplacesContent.TargetUser(
id = targetUserId, id = targetUserId,
displayName = profileInfo?.get(ProfileService.DISPLAY_NAME_KEY) as? String, displayName = profileInfo?.get(ProfileService.DISPLAY_NAME_KEY) as? String,
avatarUrl = profileInfo?.get(ProfileService.AVATAR_URL_KEY) as? String avatarUrl = profileInfo?.get(ProfileService.AVATAR_URL_KEY) as? String
), ),
targerRoomId = targetRoomId, targetRoomId = targetRoomId,
createCall = UUID.randomUUID().toString() awaitCall = awaitCallId,
createCall = createCallId
) )
.let { createEventAndLocalEcho(type = EventType.CALL_REPLACES, roomId = roomId, content = it.toContent()) } .let { createEventAndLocalEcho(type = EventType.CALL_REPLACES, roomId = roomId, content = it.toContent()) }
.also { eventSenderProcessor.postEvent(it) } .also { eventSenderProcessor.postEvent(it) }

View file

@ -75,7 +75,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
override fun handle(action: CallTransferAction) { override fun handle(action: CallTransferAction) {
when (action) { when (action) {
is CallTransferAction.ConnectWithUserId -> connectWithUserId(action) is CallTransferAction.ConnectWithUserId -> connectWithUserId(action)
is CallTransferAction.ConnectWithPhoneNumber -> connectWithPhoneNumber(action) is CallTransferAction.ConnectWithPhoneNumber -> connectWithPhoneNumber(action)
}.exhaustive }.exhaustive
} }
@ -84,7 +84,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
viewModelScope.launch { viewModelScope.launch {
try { try {
_viewEvents.post(CallTransferViewEvents.Loading) _viewEvents.post(CallTransferViewEvents.Loading)
call?.mxCall?.transfer(action.selectedUserId, null) call?.transferToUser(action.selectedUserId, null)
_viewEvents.post(CallTransferViewEvents.Dismiss) _viewEvents.post(CallTransferViewEvents.Dismiss)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(CallTransferViewEvents.FailToTransfer) _viewEvents.post(CallTransferViewEvents.FailToTransfer)
@ -97,7 +97,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
try { try {
_viewEvents.post(CallTransferViewEvents.Loading) _viewEvents.post(CallTransferViewEvents.Loading)
val result = dialPadLookup.lookupPhoneNumber(action.phoneNumber) val result = dialPadLookup.lookupPhoneNumber(action.phoneNumber)
call?.mxCall?.transfer(result.userId, result.roomId) call?.transferToUser(result.userId, result.roomId)
_viewEvents.post(CallTransferViewEvents.Dismiss) _viewEvents.post(CallTransferViewEvents.Dismiss)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(CallTransferViewEvents.FailToTransfer) _viewEvents.post(CallTransferViewEvents.FailToTransfer)

View file

@ -45,6 +45,7 @@ import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.call.CallIdGenerator
import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
@ -268,7 +269,7 @@ class WebRtcCall(val mxCall: MxCall,
sessionScope?.launch(dispatcher) { sessionScope?.launch(dispatcher) {
when (mode) { when (mode) {
VectorCallActivity.INCOMING_ACCEPT -> { VectorCallActivity.INCOMING_ACCEPT -> {
internalAcceptIncomingCall() internalAcceptIncomingCall()
} }
VectorCallActivity.INCOMING_RINGING -> { VectorCallActivity.INCOMING_RINGING -> {
@ -286,6 +287,34 @@ class WebRtcCall(val mxCall: MxCall,
} }
} }
suspend fun transferToUser(targetUserId: String, targetRoomId: String?) {
mxCall.transfer(
targetUserId = targetUserId,
targetRoomId = targetRoomId,
createCallId = CallIdGenerator.generate(),
awaitCallId = null
)
endCall(true, CallHangupContent.Reason.REPLACED)
}
suspend fun transferToCall(transferTargetCall: WebRtcCall) {
val newCallId = CallIdGenerator.generate()
transferTargetCall.mxCall.transfer(
targetUserId = this.mxCall.opponentUserId,
targetRoomId = null,
createCallId = null,
awaitCallId = newCallId
)
this.mxCall.transfer(
transferTargetCall.mxCall.opponentUserId,
targetRoomId = null,
createCallId = newCallId,
awaitCallId = null
)
endCall(true, CallHangupContent.Reason.REPLACED)
transferTargetCall.endCall(true, CallHangupContent.Reason.REPLACED)
}
fun acceptIncomingCall() { fun acceptIncomingCall() {
sessionScope?.launch { sessionScope?.launch {
Timber.v("## VOIP acceptIncomingCall from state ${mxCall.state}") Timber.v("## VOIP acceptIncomingCall from state ${mxCall.state}")