VoIP: add call transfer method

This commit is contained in:
ganfra 2020-12-17 17:05:39 +01:00 committed by ganfra
parent 9c5fe81792
commit 8797d7562d
4 changed files with 44 additions and 5 deletions

View file

@ -89,6 +89,11 @@ interface MxCall : MxCallDetail {
*/
fun sendLocalIceCandidateRemovals(candidates: List<CallCandidate>)
/**
* Send a m.call.replaces event to initiate call transfer.
*/
suspend fun transfer(targetUserId: String, targetRoomId: String?)
fun addListener(listener: StateListener)
fun removeListener(listener: StateListener)

View file

@ -71,11 +71,11 @@ data class CallReplacesContent(
/**
* Optional. The display name of the transfer target.
*/
@Json(name = "display_name") val displayName: String,
@Json(name = "display_name") val displayName: String?,
/**
* Optional. The avatar URL of the transfer target.
*/
@Json(name = "avatar_url") val avatarUrl: String
@Json(name = "avatar_url") val avatarUrl: String?
)
}

View file

@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.call.model.MxCallImpl
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
import java.math.BigDecimal
@ -35,6 +36,7 @@ internal class MxCallFactory @Inject constructor(
private val localEchoEventFactory: LocalEchoEventFactory,
private val eventSenderProcessor: EventSenderProcessor,
private val matrixConfiguration: MatrixConfiguration,
private val getProfileInfoTask: GetProfileInfoTask,
@UserId private val userId: String
) {
@ -50,7 +52,8 @@ internal class MxCallFactory @Inject constructor(
isVideoCall = content.isVideo(),
localEchoEventFactory = localEchoEventFactory,
eventSenderProcessor = eventSenderProcessor,
matrixConfiguration = matrixConfiguration
matrixConfiguration = matrixConfiguration,
getProfileInfoTask = getProfileInfoTask
).apply {
opponentPartyId = Optional.from(content.partyId)
opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
@ -69,7 +72,8 @@ internal class MxCallFactory @Inject constructor(
isVideoCall = isVideoCall,
localEchoEventFactory = localEchoEventFactory,
eventSenderProcessor = eventSenderProcessor,
matrixConfiguration = matrixConfiguration
matrixConfiguration = matrixConfiguration,
getProfileInfoTask = getProfileInfoTask
)
}
}

View file

@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.UnsignedData
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
@ -33,13 +34,16 @@ 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.CallNegotiateContent
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
import org.matrix.android.sdk.api.session.room.model.call.SdpType
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
import timber.log.Timber
import java.util.UUID
internal class MxCallImpl(
override val callId: String,
@ -51,7 +55,8 @@ internal class MxCallImpl(
override val ourPartyId: String,
private val localEchoEventFactory: LocalEchoEventFactory,
private val eventSenderProcessor: EventSenderProcessor,
private val matrixConfiguration: MatrixConfiguration
private val matrixConfiguration: MatrixConfiguration,
private val getProfileInfoTask: GetProfileInfoTask
) : MxCall {
override var opponentPartyId: Optional<String>? = null
@ -197,6 +202,31 @@ internal class MxCallImpl(
.also { eventSenderProcessor.postEvent(it) }
}
override suspend fun transfer(targetUserId: String, targetRoomId: String?) {
val profileInfoParams = GetProfileInfoTask.Params(targetUserId)
val profileInfo = try {
getProfileInfoTask.execute(profileInfoParams)
} catch (failure: Throwable) {
Timber.v("Fail fetching profile info of $targetUserId while transferring call")
null
}
CallReplacesContent(
callId = callId,
partyId = ourPartyId,
replacementId = UUID.randomUUID().toString(),
version = MxCall.VOIP_PROTO_VERSION.toString(),
targetUser = CallReplacesContent.TargetUser(
id = targetUserId,
displayName = profileInfo?.get(ProfileService.DISPLAY_NAME_KEY) as? String,
avatarUrl = profileInfo?.get(ProfileService.AVATAR_URL_KEY) as? String
),
targerRoomId = targetRoomId,
createCall = UUID.randomUUID().toString()
)
.let { createEventAndLocalEcho(type = EventType.CALL_REPLACES, 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,