mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
VoIP: start to handle call transfer in SDK
This commit is contained in:
parent
69cc4f83bb
commit
9c5fe81792
10 changed files with 160 additions and 9 deletions
|
@ -35,7 +35,11 @@ data class MatrixConfiguration(
|
|||
* Optional proxy to connect to the matrix servers
|
||||
* You can create one using for instance Proxy(proxyType, InetSocketAddress.createUnresolved(hostname, port)
|
||||
*/
|
||||
val proxy: Proxy? = null
|
||||
val proxy: Proxy? = null,
|
||||
/**
|
||||
* True to advertise support for call transfers to other parties on Matrix calls.
|
||||
*/
|
||||
val supportsCallTransfer: Boolean = true
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.api.session.call
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
@ -42,6 +43,8 @@ interface MxCall : MxCallDetail {
|
|||
var opponentPartyId: Optional<String>?
|
||||
var opponentVersion: Int
|
||||
|
||||
var capabilities: CallCapabilities?
|
||||
|
||||
var state: CallState
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,6 +72,7 @@ object EventType {
|
|||
const val CALL_NEGOTIATE = "m.call.negotiate"
|
||||
const val CALL_REJECT = "m.call.reject"
|
||||
const val CALL_HANGUP = "m.call.hangup"
|
||||
const val CALL_REPLACES = "m.call.replaces"
|
||||
|
||||
// Key share events
|
||||
const val ROOM_KEY_REQUEST = "m.room_key_request"
|
||||
|
|
|
@ -39,7 +39,11 @@ data class CallAnswerContent(
|
|||
/**
|
||||
* Required. The version of the VoIP specification this messages adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
@Json(name = "version") override val version: String?,
|
||||
/**
|
||||
* Capability advertisement.
|
||||
*/
|
||||
@Json(name= "capabilities") val capabilities: CallCapabilities? = null
|
||||
): CallSignallingContent {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallCapabilities(
|
||||
/**
|
||||
* If set to true, states that the sender of the event supports the m.call.replaces event and therefore supports
|
||||
* being transferred to another destination
|
||||
*/
|
||||
@Json(name = "m.call.transferee") val transferee: Boolean? = null
|
||||
)
|
||||
|
||||
fun CallCapabilities?.supportCallTransfer() = this?.transferee.orFalse()
|
|
@ -49,7 +49,11 @@ data class CallInviteContent(
|
|||
/**
|
||||
* The field should be added for all invites where the target is a specific user
|
||||
*/
|
||||
@Json(name = "invitee") val invitee: String? = null
|
||||
@Json(name = "invitee") val invitee: String? = null,
|
||||
/**
|
||||
* Capability advertisement.
|
||||
*/
|
||||
@Json(name= "capabilities") val capabilities: CallCapabilities? = null
|
||||
|
||||
): CallSignallingContent {
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2020 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.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This event is sent to signal the intent of a participant in a call to replace the call with another,
|
||||
* such that the other participant ends up in a call with a new user.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallReplacesContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* An identifier for the call replacement itself, generated by the transferor.
|
||||
*/
|
||||
@Json(name = "replacement_id") val replacementId: String? = null,
|
||||
/**
|
||||
* Optional. If specified, the transferee client waits for an invite to this room and joins it (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.
|
||||
*/
|
||||
@Json(name = "target_room") val targerRoomId: String? = null,
|
||||
/**
|
||||
* An object giving information about the transfer target
|
||||
*/
|
||||
@Json(name = "target_user") val targetUser: TargetUser? = null,
|
||||
/**
|
||||
* If specified, gives the call ID for the transferee's client to use when placing the replacement call.
|
||||
* Mutually exclusive with await_call
|
||||
*/
|
||||
@Json(name = "create_call") val createCall: String? = null,
|
||||
/**
|
||||
* If specified, gives the call ID that the transferee's client should wait for.
|
||||
* Mutually exclusive with create_call.
|
||||
*/
|
||||
@Json(name = "await_call") val awaitCall: String? = null,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this messages adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
): CallSignallingContent {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TargetUser(
|
||||
/**
|
||||
* Required. The matrix user ID of the transfer target
|
||||
*/
|
||||
@Json(name = "id") val id: String,
|
||||
/**
|
||||
* Optional. The display name of the transfer target.
|
||||
*/
|
||||
@Json(name = "display_name") val displayName: String,
|
||||
/**
|
||||
* Optional. The avatar URL of the transfer target.
|
||||
*/
|
||||
@Json(name = "avatar_url") val avatarUrl: String
|
||||
|
||||
)
|
||||
}
|
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
|||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
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
|
||||
|
@ -185,6 +186,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
|||
call.apply {
|
||||
opponentPartyId = Optional.from(content.partyId)
|
||||
opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
|
||||
capabilities = content.capabilities ?: CallCapabilities()
|
||||
}
|
||||
callListenersDispatcher.onCallAnswerReceived(content)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
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.CallInviteContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
|
@ -32,6 +34,7 @@ internal class MxCallFactory @Inject constructor(
|
|||
@DeviceId private val deviceId: String?,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
private val matrixConfiguration: MatrixConfiguration,
|
||||
@UserId private val userId: String
|
||||
) {
|
||||
|
||||
|
@ -46,10 +49,12 @@ internal class MxCallFactory @Inject constructor(
|
|||
opponentUserId = opponentUserId,
|
||||
isVideoCall = content.isVideo(),
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
eventSenderProcessor = eventSenderProcessor,
|
||||
matrixConfiguration = matrixConfiguration
|
||||
).apply {
|
||||
opponentPartyId = Optional.from(content.partyId)
|
||||
opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
|
||||
capabilities = content.capabilities ?: CallCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +68,8 @@ internal class MxCallFactory @Inject constructor(
|
|||
opponentUserId = opponentUserId,
|
||||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
eventSenderProcessor = eventSenderProcessor,
|
||||
matrixConfiguration = matrixConfiguration
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.call.model
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
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.events.model.Content
|
||||
|
@ -27,6 +28,7 @@ import org.matrix.android.sdk.api.session.events.model.toContent
|
|||
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
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
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
|
||||
|
@ -35,8 +37,8 @@ import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerConten
|
|||
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.room.send.queue.EventSenderProcessor
|
||||
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
|
||||
|
||||
internal class MxCallImpl(
|
||||
|
@ -48,11 +50,13 @@ internal class MxCallImpl(
|
|||
override val isVideoCall: Boolean,
|
||||
override val ourPartyId: String,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
private val matrixConfiguration: MatrixConfiguration
|
||||
) : MxCall {
|
||||
|
||||
override var opponentPartyId: Optional<String>? = null
|
||||
override var opponentVersion: Int = MxCall.VOIP_PROTO_VERSION
|
||||
override var capabilities: CallCapabilities? = null
|
||||
|
||||
override var state: CallState = CallState.Idle
|
||||
set(value) {
|
||||
|
@ -98,7 +102,8 @@ internal class MxCallImpl(
|
|||
partyId = ourPartyId,
|
||||
lifetime = DefaultCallSignalingService.CALL_TIMEOUT_MS,
|
||||
offer = CallInviteContent.Offer(sdp = sdpString),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString(),
|
||||
capabilities = buildCapabilities()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
|
@ -158,7 +163,8 @@ internal class MxCallImpl(
|
|||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
answer = CallAnswerContent.Answer(sdp = sdpString),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString(),
|
||||
capabilities = buildCapabilities()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_ANSWER, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
|
@ -203,4 +209,12 @@ internal class MxCallImpl(
|
|||
)
|
||||
.also { localEchoEventFactory.createLocalEcho(it) }
|
||||
}
|
||||
|
||||
private fun buildCapabilities(): CallCapabilities? {
|
||||
return if (matrixConfiguration.supportsCallTransfer) {
|
||||
CallCapabilities(true)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue