David Zhao

Support setting autosubscribe to false, refactored ConnectOptions

1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4"> 2 <project version="4">
3 <component name="CompilerConfiguration"> 3 <component name="CompilerConfiguration">
4 - <bytecodeTargetLevel target="11" /> 4 + <bytecodeTargetLevel target="12" />
5 </component> 5 </component>
6 </project> 6 </project>
@@ -11,7 +11,7 @@ buildscript { @@ -11,7 +11,7 @@ buildscript {
11 11
12 } 12 }
13 dependencies { 13 dependencies {
14 - classpath 'com.android.tools.build:gradle:7.0.0-alpha15' 14 + classpath 'com.android.tools.build:gradle:7.0.0-beta02'
15 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
16 classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" 16 classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
17 classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" 17 classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
@@ -15,8 +15,6 @@ android { @@ -15,8 +15,6 @@ android {
15 defaultConfig { 15 defaultConfig {
16 minSdkVersion 21 16 minSdkVersion 21
17 targetSdkVersion 30 17 targetSdkVersion 30
18 - versionCode 1  
19 - versionName VERSION_NAME  
20 18
21 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 consumerProguardFiles 'consumer-rules.pro' 20 consumerProguardFiles 'consumer-rules.pro'
1 package io.livekit.android 1 package io.livekit.android
2 2
3 3
4 -data class ConnectOptions(  
5 - val placeholder: Unit = Unit  
6 -)  
  4 +class ConnectOptions(
  5 + var autoSubscribe: Boolean = true
  6 +) {
  7 + internal var reconnect: Boolean = false
  8 +}
@@ -16,7 +16,7 @@ class LiveKit { @@ -16,7 +16,7 @@ class LiveKit {
16 appContext: Context, 16 appContext: Context,
17 url: String, 17 url: String,
18 token: String, 18 token: String,
19 - options: ConnectOptions, 19 + options: ConnectOptions?,
20 listener: RoomListener? 20 listener: RoomListener?
21 ): Room { 21 ): Room {
22 val ctx = appContext.applicationContext 22 val ctx = appContext.applicationContext
@@ -25,9 +25,9 @@ class LiveKit { @@ -25,9 +25,9 @@ class LiveKit {
25 .create(ctx) 25 .create(ctx)
26 26
27 val room = component.roomFactory() 27 val room = component.roomFactory()
28 - .create(options, ctx) 28 + .create(ctx)
29 room.listener = listener 29 room.listener = listener
30 - room.connect(url, token) 30 + room.connect(url, token, options)
31 31
32 return room 32 return room
33 } 33 }
1 package io.livekit.android.room 1 package io.livekit.android.room
2 2
3 import com.github.ajalt.timberkt.Timber 3 import com.github.ajalt.timberkt.Timber
  4 +import io.livekit.android.ConnectOptions
4 import io.livekit.android.dagger.InjectionNames 5 import io.livekit.android.dagger.InjectionNames
5 import io.livekit.android.room.track.TrackException 6 import io.livekit.android.room.track.TrackException
6 import io.livekit.android.room.util.* 7 import io.livekit.android.room.util.*
@@ -27,10 +28,10 @@ import kotlin.coroutines.suspendCoroutine @@ -27,10 +28,10 @@ import kotlin.coroutines.suspendCoroutine
27 class RTCEngine 28 class RTCEngine
28 @Inject 29 @Inject
29 constructor( 30 constructor(
30 - val client: RTCClient, 31 + val client: SignalClient,
31 private val pctFactory: PeerConnectionTransport.Factory, 32 private val pctFactory: PeerConnectionTransport.Factory,
32 @Named(InjectionNames.DISPATCHER_IO) ioDispatcher: CoroutineDispatcher, 33 @Named(InjectionNames.DISPATCHER_IO) ioDispatcher: CoroutineDispatcher,
33 -) : RTCClient.Listener, DataChannel.Observer { 34 +) : SignalClient.Listener, DataChannel.Observer {
34 var listener: Listener? = null 35 var listener: Listener? = null
35 internal var iceState: IceState = IceState.DISCONNECTED 36 internal var iceState: IceState = IceState.DISCONNECTED
36 set(value) { 37 set(value) {
@@ -74,10 +75,10 @@ constructor( @@ -74,10 +75,10 @@ constructor(
74 client.listener = this 75 client.listener = this
75 } 76 }
76 77
77 - fun join(url: String, token: String) { 78 + fun join(url: String, token: String, options: ConnectOptions?) {
78 sessionUrl = url 79 sessionUrl = url
79 sessionToken = token 80 sessionToken = token
80 - client.join(url, token) 81 + client.join(url, token, options)
81 } 82 }
82 83
83 suspend fun addTrack(cid: String, name: String, kind: LivekitModels.TrackType): LivekitModels.TrackInfo { 84 suspend fun addTrack(cid: String, name: String, kind: LivekitModels.TrackType): LivekitModels.TrackInfo {
@@ -123,7 +124,9 @@ constructor( @@ -123,7 +124,9 @@ constructor(
123 coroutineScope.launch { 124 coroutineScope.launch {
124 delay(startDelay) 125 delay(startDelay)
125 if (iceState != IceState.DISCONNECTED && sessionUrl != null && sessionToken != null) { 126 if (iceState != IceState.DISCONNECTED && sessionUrl != null && sessionToken != null) {
126 - client.join(sessionUrl!!, sessionToken!!, true) 127 + val opts = ConnectOptions()
  128 + opts.reconnect = true
  129 + client.join(sessionUrl!!, sessionToken!!, opts)
127 } 130 }
128 } 131 }
129 } 132 }
@@ -208,7 +211,7 @@ constructor( @@ -208,7 +211,7 @@ constructor(
208 } 211 }
209 212
210 if (iceServers.isEmpty()) { 213 if (iceServers.isEmpty()) {
211 - iceServers.addAll(RTCClient.DEFAULT_ICE_SERVERS) 214 + iceServers.addAll(SignalClient.DEFAULT_ICE_SERVERS)
212 } 215 }
213 info.iceServersList.forEach { 216 info.iceServersList.forEach {
214 Timber.e{ "username = \"${it.username}\""} 217 Timber.e{ "username = \"${it.username}\""}
@@ -26,7 +26,6 @@ import kotlin.coroutines.suspendCoroutine @@ -26,7 +26,6 @@ import kotlin.coroutines.suspendCoroutine
26 class Room 26 class Room
27 @AssistedInject 27 @AssistedInject
28 constructor( 28 constructor(
29 - @Assisted private val connectOptions: ConnectOptions,  
30 @Assisted private val context: Context, 29 @Assisted private val context: Context,
31 private val engine: RTCEngine, 30 private val engine: RTCEngine,
32 private val eglBase: EglBase, 31 private val eglBase: EglBase,
@@ -65,9 +64,9 @@ constructor( @@ -65,9 +64,9 @@ constructor(
65 64
66 private var hasLostConnectivity: Boolean = false 65 private var hasLostConnectivity: Boolean = false
67 private var connectContinuation: Continuation<Unit>? = null 66 private var connectContinuation: Continuation<Unit>? = null
68 - suspend fun connect(url: String, token: String) { 67 + suspend fun connect(url: String, token: String, options: ConnectOptions?) {
69 state = State.CONNECTING 68 state = State.CONNECTING
70 - engine.join(url, token) 69 + engine.join(url, token, options)
71 val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 70 val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
72 val networkRequest = NetworkRequest.Builder() 71 val networkRequest = NetworkRequest.Builder()
73 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 72 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
@@ -180,7 +179,7 @@ constructor( @@ -180,7 +179,7 @@ constructor(
180 */ 179 */
181 @AssistedFactory 180 @AssistedFactory
182 interface Factory { 181 interface Factory {
183 - fun create(connectOptions: ConnectOptions, context: Context): Room 182 + fun create(context: Context): Room
184 } 183 }
185 184
186 //------------------------------------- NetworkCallback -------------------------------------// 185 //------------------------------------- NetworkCallback -------------------------------------//
@@ -2,6 +2,7 @@ package io.livekit.android.room @@ -2,6 +2,7 @@ package io.livekit.android.room
2 2
3 import com.github.ajalt.timberkt.Timber 3 import com.github.ajalt.timberkt.Timber
4 import com.google.protobuf.util.JsonFormat 4 import com.google.protobuf.util.JsonFormat
  5 +import io.livekit.android.ConnectOptions
5 import io.livekit.android.dagger.InjectionNames 6 import io.livekit.android.dagger.InjectionNames
6 import io.livekit.android.util.safe 7 import io.livekit.android.util.safe
7 import kotlinx.serialization.decodeFromString 8 import kotlinx.serialization.decodeFromString
@@ -25,7 +26,7 @@ import javax.inject.Named @@ -25,7 +26,7 @@ import javax.inject.Named
25 * SignalClient to LiveKit WS servers 26 * SignalClient to LiveKit WS servers
26 * @suppress 27 * @suppress
27 */ 28 */
28 -class RTCClient 29 +class SignalClient
29 @Inject 30 @Inject
30 constructor( 31 constructor(
31 private val websocketFactory: WebSocket.Factory, 32 private val websocketFactory: WebSocket.Factory,
@@ -44,15 +45,25 @@ constructor( @@ -44,15 +45,25 @@ constructor(
44 fun join( 45 fun join(
45 url: String, 46 url: String,
46 token: String, 47 token: String,
47 - reconnect: Boolean = false 48 + options: ConnectOptions?,
48 ) { 49 ) {
49 var wsUrlString = "$url/rtc?protocol=$PROTOCOL_VERSION&access_token=$token" 50 var wsUrlString = "$url/rtc?protocol=$PROTOCOL_VERSION&access_token=$token"
50 - if (reconnect) {  
51 - wsUrlString += "&reconnect=1" 51 + isReconnecting = false
  52 + if (options != null) {
  53 + wsUrlString += "&auto_subscribe="
  54 + wsUrlString += if (options.autoSubscribe) {
  55 + "1"
  56 + } else {
  57 + "0"
  58 + }
  59 + if (options.reconnect) {
  60 + wsUrlString += "&reconnect=1"
  61 + isReconnecting = true
  62 + }
52 } 63 }
  64 +
53 Timber.i { "connecting to $wsUrlString" } 65 Timber.i { "connecting to $wsUrlString" }
54 66
55 - isReconnecting = reconnect  
56 isConnected = false 67 isConnected = false
57 currentWs?.cancel() 68 currentWs?.cancel()
58 69
1 package io.livekit.android.room.participant 1 package io.livekit.android.room.participant
2 2
3 import com.github.ajalt.timberkt.Timber 3 import com.github.ajalt.timberkt.Timber
4 -import io.livekit.android.room.RTCClient 4 +import io.livekit.android.room.SignalClient
5 import io.livekit.android.room.track.* 5 import io.livekit.android.room.track.*
6 import io.livekit.android.util.CloseableCoroutineScope 6 import io.livekit.android.util.CloseableCoroutineScope
7 import kotlinx.coroutines.SupervisorJob 7 import kotlinx.coroutines.SupervisorJob
@@ -13,14 +13,14 @@ import org.webrtc.MediaStreamTrack @@ -13,14 +13,14 @@ import org.webrtc.MediaStreamTrack
13 import org.webrtc.VideoTrack 13 import org.webrtc.VideoTrack
14 14
15 class RemoteParticipant( 15 class RemoteParticipant(
16 - val rtcClient: RTCClient, 16 + val signalClient: SignalClient,
17 sid: String, 17 sid: String,
18 identity: String? = null, 18 identity: String? = null,
19 ) : Participant(sid, identity) { 19 ) : Participant(sid, identity) {
20 /** 20 /**
21 * @suppress 21 * @suppress
22 */ 22 */
23 - constructor(rtcClient: RTCClient, info: LivekitModels.ParticipantInfo) : this(rtcClient, info.sid, info.identity) { 23 + constructor(signalClient: SignalClient, info: LivekitModels.ParticipantInfo) : this(signalClient, info.sid, info.identity) {
24 updateFromInfo(info) 24 updateFromInfo(info)
25 } 25 }
26 26
@@ -44,7 +44,7 @@ class RemoteTrackPublication( @@ -44,7 +44,7 @@ class RemoteTrackPublication(
44 unsubscribed = !subscribed 44 unsubscribed = !subscribed
45 val participant = this.participant.get() as? RemoteParticipant ?: return 45 val participant = this.participant.get() as? RemoteParticipant ?: return
46 46
47 - participant.rtcClient.sendUpdateSubscription(sid, !unsubscribed, videoQuality) 47 + participant.signalClient.sendUpdateSubscription(sid, !unsubscribed, videoQuality)
48 } 48 }
49 49
50 /** 50 /**
@@ -72,6 +72,6 @@ class RemoteTrackPublication( @@ -72,6 +72,6 @@ class RemoteTrackPublication(
72 private fun sendUpdateTrackSettings() { 72 private fun sendUpdateTrackSettings() {
73 val participant = this.participant.get() as? RemoteParticipant ?: return 73 val participant = this.participant.get() as? RemoteParticipant ?: return
74 74
75 - participant.rtcClient.sendUpdateTrackSettings(sid, disabled, videoQuality) 75 + participant.signalClient.sendUpdateTrackSettings(sid, disabled, videoQuality)
76 } 76 }
77 } 77 }
1 package io.livekit.android.room.participant 1 package io.livekit.android.room.participant
2 2
3 -import io.livekit.android.room.RTCClient 3 +import io.livekit.android.room.SignalClient
4 import livekit.LivekitModels 4 import livekit.LivekitModels
5 import org.junit.Assert.* 5 import org.junit.Assert.*
6 import org.junit.Before 6 import org.junit.Before
@@ -9,13 +9,13 @@ import org.mockito.Mockito @@ -9,13 +9,13 @@ import org.mockito.Mockito
9 9
10 class RemoteParticipantTest { 10 class RemoteParticipantTest {
11 11
12 - lateinit var rtcClient: RTCClient 12 + lateinit var signalClient: SignalClient
13 lateinit var participant: RemoteParticipant 13 lateinit var participant: RemoteParticipant
14 14
15 @Before 15 @Before
16 fun setup() { 16 fun setup() {
17 - rtcClient = Mockito.mock(RTCClient::class.java)  
18 - participant = RemoteParticipant(rtcClient, "sid") 17 + signalClient = Mockito.mock(SignalClient::class.java)
  18 + participant = RemoteParticipant(signalClient, "sid")
19 } 19 }
20 20
21 @Test 21 @Test
@@ -24,7 +24,7 @@ class RemoteParticipantTest { @@ -24,7 +24,7 @@ class RemoteParticipantTest {
24 .addTracks(TRACK_INFO) 24 .addTracks(TRACK_INFO)
25 .build() 25 .build()
26 26
27 - participant = RemoteParticipant(rtcClient, info) 27 + participant = RemoteParticipant(signalClient, info)
28 28
29 assertEquals(1, participant.tracks.values.size) 29 assertEquals(1, participant.tracks.values.size)
30 assertNotNull(participant.getTrackPublication(TRACK_INFO.sid)) 30 assertNotNull(participant.getTrackPublication(TRACK_INFO.sid))