davidliu
Committed by GitHub

Add rpc handler methods to Room class for convenience (#663)

  1 +---
  2 +"client-sdk-android": patch
  3 +---
  4 +
  5 +Add rpc handler methods to Room class for convenience.
@@ -47,6 +47,7 @@ import io.livekit.android.room.metrics.collectMetrics @@ -47,6 +47,7 @@ import io.livekit.android.room.metrics.collectMetrics
47 import io.livekit.android.room.network.NetworkCallbackManagerFactory 47 import io.livekit.android.room.network.NetworkCallbackManagerFactory
48 import io.livekit.android.room.participant.* 48 import io.livekit.android.room.participant.*
49 import io.livekit.android.room.provisions.LKObjects 49 import io.livekit.android.room.provisions.LKObjects
  50 +import io.livekit.android.room.rpc.RpcManager
50 import io.livekit.android.room.track.* 51 import io.livekit.android.room.track.*
51 import io.livekit.android.room.types.toSDKType 52 import io.livekit.android.room.types.toSDKType
52 import io.livekit.android.room.util.ConnectionWarmer 53 import io.livekit.android.room.util.ConnectionWarmer
@@ -69,6 +70,7 @@ import livekit.org.webrtc.audio.AudioDeviceModule @@ -69,6 +70,7 @@ import livekit.org.webrtc.audio.AudioDeviceModule
69 import java.net.URI 70 import java.net.URI
70 import java.util.Date 71 import java.util.Date
71 import javax.inject.Named 72 import javax.inject.Named
  73 +import kotlin.time.Duration
72 74
73 class Room 75 class Room
74 @AssistedInject 76 @AssistedInject
@@ -108,7 +110,7 @@ constructor( @@ -108,7 +110,7 @@ constructor(
108 private val connectionWarmer: ConnectionWarmer, 110 private val connectionWarmer: ConnectionWarmer,
109 private val audioRecordPrewarmer: AudioRecordPrewarmer, 111 private val audioRecordPrewarmer: AudioRecordPrewarmer,
110 private val incomingDataStreamManager: IncomingDataStreamManager, 112 private val incomingDataStreamManager: IncomingDataStreamManager,
111 -) : RTCEngine.Listener, ParticipantListener, IncomingDataStreamManager by incomingDataStreamManager { 113 +) : RTCEngine.Listener, ParticipantListener, RpcManager, IncomingDataStreamManager by incomingDataStreamManager {
112 114
113 private lateinit var coroutineScope: CoroutineScope 115 private lateinit var coroutineScope: CoroutineScope
114 private val eventBus = BroadcastEventBus<RoomEvent>() 116 private val eventBus = BroadcastEventBus<RoomEvent>()
@@ -1040,6 +1042,19 @@ constructor( @@ -1040,6 +1042,19 @@ constructor(
1040 }, 1042 },
1041 ) 1043 )
1042 1044
  1045 + // ----------------------------------- RpcManager ------------------------------------//
  1046 + override suspend fun registerRpcMethod(method: String, handler: RpcHandler) {
  1047 + localParticipant.registerRpcMethod(method, handler)
  1048 + }
  1049 +
  1050 + override fun unregisterRpcMethod(method: String) {
  1051 + localParticipant.unregisterRpcMethod(method)
  1052 + }
  1053 +
  1054 + override suspend fun performRpc(destinationIdentity: Participant.Identity, method: String, payload: String, responseTimeout: Duration): String {
  1055 + return localParticipant.performRpc(destinationIdentity, method, payload, responseTimeout)
  1056 + }
  1057 +
1043 // ----------------------------------- RTCEngine.Listener ------------------------------------// 1058 // ----------------------------------- RTCEngine.Listener ------------------------------------//
1044 1059
1045 /** 1060 /**
@@ -109,7 +109,9 @@ internal constructor( @@ -109,7 +109,9 @@ internal constructor(
109 @Named(InjectionNames.SENDER) 109 @Named(InjectionNames.SENDER)
110 private val capabilitiesGetter: CapabilitiesGetter, 110 private val capabilitiesGetter: CapabilitiesGetter,
111 private val outgoingDataStreamManager: OutgoingDataStreamManager, 111 private val outgoingDataStreamManager: OutgoingDataStreamManager,
112 -) : Participant(Sid(""), null, coroutineDispatcher), OutgoingDataStreamManager by outgoingDataStreamManager { 112 +) : Participant(Sid(""), null, coroutineDispatcher),
  113 + OutgoingDataStreamManager by outgoingDataStreamManager,
  114 + RpcManager {
113 115
114 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults 116 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults
115 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults 117 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults
@@ -988,7 +990,7 @@ internal constructor( @@ -988,7 +990,7 @@ internal constructor(
988 * @see performRpc 990 * @see performRpc
989 */ 991 */
990 @Suppress("RedundantSuspendModifier") 992 @Suppress("RedundantSuspendModifier")
991 - suspend fun registerRpcMethod( 993 + override suspend fun registerRpcMethod(
992 method: String, 994 method: String,
993 handler: RpcHandler, 995 handler: RpcHandler,
994 ) { 996 ) {
@@ -1000,7 +1002,7 @@ internal constructor( @@ -1000,7 +1002,7 @@ internal constructor(
1000 * 1002 *
1001 * @param method The name of the RPC method to unregister 1003 * @param method The name of the RPC method to unregister
1002 */ 1004 */
1003 - fun unregisterRpcMethod( 1005 + override fun unregisterRpcMethod(
1004 method: String, 1006 method: String,
1005 ) { 1007 ) {
1006 this.rpcHandlers.remove(method) 1008 this.rpcHandlers.remove(method)
@@ -1056,11 +1058,11 @@ internal constructor( @@ -1056,11 +1058,11 @@ internal constructor(
1056 * @return The response payload. 1058 * @return The response payload.
1057 * @throws RpcError on failure. Details in [RpcError.message]. 1059 * @throws RpcError on failure. Details in [RpcError.message].
1058 */ 1060 */
1059 - suspend fun performRpc( 1061 + override suspend fun performRpc(
1060 destinationIdentity: Identity, 1062 destinationIdentity: Identity,
1061 method: String, 1063 method: String,
1062 payload: String, 1064 payload: String,
1063 - responseTimeout: Duration = 10.seconds, 1065 + responseTimeout: Duration,
1064 ): String = coroutineScope { 1066 ): String = coroutineScope {
1065 val maxRoundTripLatency = 2.seconds 1067 val maxRoundTripLatency = 2.seconds
1066 1068
@@ -16,8 +16,78 @@ @@ -16,8 +16,78 @@
16 16
17 package io.livekit.android.room.rpc 17 package io.livekit.android.room.rpc
18 18
19 -class RpcManager { 19 +import io.livekit.android.room.participant.Participant.Identity
  20 +import io.livekit.android.room.participant.RpcHandler
  21 +import io.livekit.android.room.participant.RpcInvocationData
  22 +import io.livekit.android.rpc.RpcError
  23 +import kotlin.time.Duration
  24 +import kotlin.time.Duration.Companion.seconds
  25 +
  26 +interface RpcManager {
20 companion object { 27 companion object {
21 const val RPC_VERSION = 1 28 const val RPC_VERSION = 1
22 } 29 }
  30 +
  31 + /**
  32 + * Establishes the participant as a receiver for calls of the specified RPC method.
  33 + * Will overwrite any existing callback for the same method.
  34 + *
  35 + * Example:
  36 + * ```kt
  37 + * room.registerRpcMethod("greet") { (requestId, callerIdentity, payload, responseTimeout) ->
  38 + * Log.i("TAG", "Received greeting from ${callerIdentity}: ${payload}")
  39 + *
  40 + * // Return a string
  41 + * "Hello, ${callerIdentity}!"
  42 + * }
  43 + * ```
  44 + *
  45 + * The handler receives an [RpcInvocationData] with the following parameters:
  46 + * - `requestId`: A unique identifier for this RPC request
  47 + * - `callerIdentity`: The identity of the RemoteParticipant who initiated the RPC call
  48 + * - `payload`: The data sent by the caller (as a string)
  49 + * - `responseTimeout`: The maximum time available to return a response
  50 + *
  51 + * The handler should return a string.
  52 + * If unable to respond within [RpcInvocationData.responseTimeout], the request will result in an error on the caller's side.
  53 + *
  54 + * You may throw errors of type [RpcError] with a string `message` in the handler,
  55 + * and they will be received on the caller's side with the message intact.
  56 + * Other errors thrown in your handler will not be transmitted as-is, and will instead arrive to the caller as `1500` ("Application Error").
  57 + *
  58 + * @param method The name of the indicated RPC method
  59 + * @param handler Will be invoked when an RPC request for this method is received
  60 + * @see RpcHandler
  61 + * @see RpcInvocationData
  62 + * @see performRpc
  63 + */
  64 + @Suppress("RedundantSuspendModifier")
  65 + suspend fun registerRpcMethod(
  66 + method: String,
  67 + handler: RpcHandler,
  68 + )
  69 +
  70 + /**
  71 + * Unregisters a previously registered RPC method.
  72 + *
  73 + * @param method The name of the RPC method to unregister
  74 + */
  75 + fun unregisterRpcMethod(method: String)
  76 +
  77 + /**
  78 + * Initiate an RPC call to a remote participant
  79 + * @param destinationIdentity The identity of the destination participant.
  80 + * @param method The method name to call.
  81 + * @param payload The payload to pass to the method.
  82 + * @param responseTimeout Timeout for receiving a response after initial connection.
  83 + * Defaults to 10000. Max value of UInt.MAX_VALUE milliseconds.
  84 + * @return The response payload.
  85 + * @throws RpcError on failure. Details in [RpcError.message].
  86 + */
  87 + suspend fun performRpc(
  88 + destinationIdentity: Identity,
  89 + method: String,
  90 + payload: String,
  91 + responseTimeout: Duration = 10.seconds,
  92 + ): String
23 } 93 }