davidliu
Committed by GitHub

separate room creation from connect (#28)

* separate room creation from connect

* fix tests
1 package io.livekit.android 1 package io.livekit.android
2 2
3 -import io.livekit.android.room.participant.AudioTrackPublishDefaults  
4 -import io.livekit.android.room.participant.VideoTrackPublishDefaults  
5 -import io.livekit.android.room.track.LocalAudioTrackOptions  
6 -import io.livekit.android.room.track.LocalVideoTrackOptions  
7 import org.webrtc.PeerConnection 3 import org.webrtc.PeerConnection
8 4
9 5
10 data class ConnectOptions( 6 data class ConnectOptions(
11 /** Auto subscribe to room tracks upon connect, defaults to true */ 7 /** Auto subscribe to room tracks upon connect, defaults to true */
12 val autoSubscribe: Boolean = true, 8 val autoSubscribe: Boolean = true,
13 - /**  
14 - * Automatically manage quality of subscribed video tracks, subscribe to the  
15 - * an appropriate resolution based on the size of the video elements that tracks  
16 - * are attached to.  
17 - *  
18 - * Also observes the visibility of attached tracks and pauses receiving data  
19 - * if they are not visible.  
20 - */  
21 - val autoManageVideo: Boolean = false,  
22 9
23 val iceServers: List<PeerConnection.IceServer>? = null, 10 val iceServers: List<PeerConnection.IceServer>? = null,
24 val rtcConfig: PeerConnection.RTCConfiguration? = null, 11 val rtcConfig: PeerConnection.RTCConfiguration? = null,
@@ -30,11 +17,6 @@ data class ConnectOptions( @@ -30,11 +17,6 @@ data class ConnectOptions(
30 * capture and publish video track on connect, defaults to false 17 * capture and publish video track on connect, defaults to false
31 */ 18 */
32 val video: Boolean = false, 19 val video: Boolean = false,
33 -  
34 - val audioTrackCaptureDefaults: LocalAudioTrackOptions? = null,  
35 - val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null,  
36 - val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null,  
37 - val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null,  
38 ) { 20 ) {
39 internal var reconnect: Boolean = false 21 internal var reconnect: Boolean = false
40 } 22 }
@@ -26,51 +26,52 @@ class LiveKit { @@ -26,51 +26,52 @@ class LiveKit {
26 } 26 }
27 } 27 }
28 28
29 - /**  
30 - * Connect to a LiveKit room  
31 - * @param url URL to LiveKit server (i.e. ws://mylivekitdeploy.io)  
32 - * @param listener Listener to Room events. LiveKit interactions take place with these callbacks  
33 - */  
34 - suspend fun connect( 29 + fun create(
35 appContext: Context, 30 appContext: Context,
36 - url: String,  
37 - token: String,  
38 - options: ConnectOptions?,  
39 - listener: RoomListener? 31 + options: RoomOptions = RoomOptions(),
40 ): Room { 32 ): Room {
41 val ctx = appContext.applicationContext 33 val ctx = appContext.applicationContext
42 val component = DaggerLiveKitComponent 34 val component = DaggerLiveKitComponent
43 .factory() 35 .factory()
44 .create(ctx) 36 .create(ctx)
45 37
46 - val room = component.roomFactory()  
47 - .create(ctx)  
48 - room.listener = listener  
49 - room.connect(url, token, options) 38 + val room = component.roomFactory().create(ctx)
50 39
51 - options?.audioTrackCaptureDefaults?.let {  
52 - room.localParticipant.audioTrackCaptureDefaults = it 40 + options.audioTrackCaptureDefaults?.let {
  41 + room.audioTrackCaptureDefaults = it
53 } 42 }
54 - options?.videoTrackCaptureDefaults?.let {  
55 - room.localParticipant.videoTrackCaptureDefaults = it 43 + options.videoTrackCaptureDefaults?.let {
  44 + room.videoTrackCaptureDefaults = it
56 } 45 }
57 46
58 - options?.audioTrackPublishDefaults?.let {  
59 - room.localParticipant.audioTrackPublishDefaults = it 47 + options.audioTrackPublishDefaults?.let {
  48 + room.audioTrackPublishDefaults = it
60 } 49 }
61 - options?.videoTrackPublishDefaults?.let {  
62 - room.localParticipant.videoTrackPublishDefaults = it 50 + options.videoTrackPublishDefaults?.let {
  51 + room.videoTrackPublishDefaults = it
63 } 52 }
64 - room.autoManageVideo = options?.autoManageVideo ?: false 53 + room.autoManageVideo = options.autoManageVideo
65 54
66 - if (options?.audio == true) {  
67 - val audioTrack = room.localParticipant.createAudioTrack()  
68 - room.localParticipant.publishAudioTrack(audioTrack)  
69 - }  
70 - if (options?.video == true) {  
71 - val videoTrack = room.localParticipant.createVideoTrack()  
72 - room.localParticipant.publishVideoTrack(videoTrack)  
73 - } 55 + return room
  56 + }
  57 +
  58 + /**
  59 + * Connect to a LiveKit room
  60 + * @param url URL to LiveKit server (i.e. ws://mylivekitdeploy.io)
  61 + * @param listener Listener to Room events. LiveKit interactions take place with these callbacks
  62 + */
  63 + suspend fun connect(
  64 + appContext: Context,
  65 + url: String,
  66 + token: String,
  67 + options: ConnectOptions = ConnectOptions(),
  68 + roomOptions: RoomOptions = RoomOptions(),
  69 + listener: RoomListener?
  70 + ): Room {
  71 + val room = create(appContext)
  72 +
  73 + room.listener = listener
  74 + room.connect(url, token, options)
74 return room 75 return room
75 } 76 }
76 77
  1 +package io.livekit.android
  2 +
  3 +import io.livekit.android.room.participant.AudioTrackPublishDefaults
  4 +import io.livekit.android.room.participant.VideoTrackPublishDefaults
  5 +import io.livekit.android.room.track.LocalAudioTrackOptions
  6 +import io.livekit.android.room.track.LocalVideoTrackOptions
  7 +
  8 +data class RoomOptions(
  9 + /**
  10 + * Automatically manage quality of subscribed video tracks, subscribe to the
  11 + * an appropriate resolution based on the size of the video elements that tracks
  12 + * are attached to.
  13 + *
  14 + * Also observes the visibility of attached tracks and pauses receiving data
  15 + * if they are not visible.
  16 + */
  17 + val autoManageVideo: Boolean = false,
  18 +
  19 + val audioTrackCaptureDefaults: LocalAudioTrackOptions? = null,
  20 + val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null,
  21 + val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null,
  22 + val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null,
  23 +)
@@ -88,7 +88,7 @@ internal constructor( @@ -88,7 +88,7 @@ internal constructor(
88 client.listener = this 88 client.listener = this
89 } 89 }
90 90
91 - suspend fun join(url: String, token: String, options: ConnectOptions?): LivekitRtc.JoinResponse { 91 + suspend fun join(url: String, token: String, options: ConnectOptions): LivekitRtc.JoinResponse {
92 sessionUrl = url 92 sessionUrl = url
93 sessionToken = token 93 sessionToken = token
94 val joinResponse = client.join(url, token, options) 94 val joinResponse = client.join(url, token, options)
@@ -80,10 +80,34 @@ constructor( @@ -80,10 +80,34 @@ constructor(
80 var metadata: String? by flowDelegate(null) 80 var metadata: String? by flowDelegate(null)
81 private set 81 private set
82 82
  83 + /**
  84 + * Automatically manage quality of subscribed video tracks, subscribe to the
  85 + * an appropriate resolution based on the size of the video elements that tracks
  86 + * are attached to.
  87 + *
  88 + * Also observes the visibility of attached tracks and pauses receiving data
  89 + * if they are not visible.
  90 + */
83 var autoManageVideo: Boolean = false 91 var autoManageVideo: Boolean = false
  92 +
  93 + /**
  94 + * Default options to use when creating an audio track.
  95 + */
84 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults 96 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults
  97 +
  98 + /**
  99 + * Default options to use when publishing an audio track.
  100 + */
85 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults 101 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults
  102 +
  103 + /**
  104 + * Default options to use when creating a video track.
  105 + */
86 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults 106 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults
  107 +
  108 + /**
  109 + * Default options to use when publishing a video track.
  110 + */
87 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults 111 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults
88 112
89 lateinit var localParticipant: LocalParticipant 113 lateinit var localParticipant: LocalParticipant
@@ -103,13 +127,12 @@ constructor( @@ -103,13 +127,12 @@ constructor(
103 get() = mutableActiveSpeakers 127 get() = mutableActiveSpeakers
104 128
105 private var hasLostConnectivity: Boolean = false 129 private var hasLostConnectivity: Boolean = false
106 - suspend fun connect(url: String, token: String, options: ConnectOptions?) { 130 + suspend fun connect(url: String, token: String, options: ConnectOptions = ConnectOptions()) {
107 if (this::coroutineScope.isInitialized) { 131 if (this::coroutineScope.isInitialized) {
108 coroutineScope.cancel() 132 coroutineScope.cancel()
109 } 133 }
110 coroutineScope = CoroutineScope(defaultDispatcher + SupervisorJob()) 134 coroutineScope = CoroutineScope(defaultDispatcher + SupervisorJob())
111 state = State.CONNECTING 135 state = State.CONNECTING
112 - ::state.flow  
113 val response = engine.join(url, token, options) 136 val response = engine.join(url, token, options)
114 LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" } 137 LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" }
115 138
@@ -134,6 +157,15 @@ constructor( @@ -134,6 +157,15 @@ constructor(
134 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 157 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
135 .build() 158 .build()
136 cm.registerNetworkCallback(networkRequest, this) 159 cm.registerNetworkCallback(networkRequest, this)
  160 +
  161 + if (options.audio) {
  162 + val audioTrack = localParticipant.createAudioTrack()
  163 + localParticipant.publishAudioTrack(audioTrack)
  164 + }
  165 + if (options.video) {
  166 + val videoTrack = localParticipant.createVideoTrack()
  167 + localParticipant.publishVideoTrack(videoTrack)
  168 + }
137 } 169 }
138 170
139 fun disconnect() { 171 fun disconnect() {
@@ -62,7 +62,7 @@ constructor( @@ -62,7 +62,7 @@ constructor(
62 suspend fun join( 62 suspend fun join(
63 url: String, 63 url: String,
64 token: String, 64 token: String,
65 - options: ConnectOptions?, 65 + options: ConnectOptions = ConnectOptions(),
66 ) : LivekitRtc.JoinResponse { 66 ) : LivekitRtc.JoinResponse {
67 val joinResponse = connect(url,token, options) 67 val joinResponse = connect(url,token, options)
68 return (joinResponse as Either.Left).value 68 return (joinResponse as Either.Left).value
@@ -80,7 +80,7 @@ constructor( @@ -80,7 +80,7 @@ constructor(
80 suspend fun connect( 80 suspend fun connect(
81 url: String, 81 url: String,
82 token: String, 82 token: String,
83 - options: ConnectOptions? 83 + options: ConnectOptions
84 ) : Either<LivekitRtc.JoinResponse, Unit> { 84 ) : Either<LivekitRtc.JoinResponse, Unit> {
85 var wsUrlString = "$url/rtc" + 85 var wsUrlString = "$url/rtc" +
86 "?protocol=$PROTOCOL_VERSION" + 86 "?protocol=$PROTOCOL_VERSION" +
@@ -88,17 +88,15 @@ constructor( @@ -88,17 +88,15 @@ constructor(
88 "&sdk=$SDK_TYPE" + 88 "&sdk=$SDK_TYPE" +
89 "&version=${Version.CLIENT_VERSION}" 89 "&version=${Version.CLIENT_VERSION}"
90 isReconnecting = false 90 isReconnecting = false
91 - if (options != null) {  
92 - wsUrlString += "&auto_subscribe="  
93 - wsUrlString += if (options.autoSubscribe) {  
94 - "1"  
95 - } else {  
96 - "0"  
97 - }  
98 - if (options.reconnect) {  
99 - wsUrlString += "&reconnect=1"  
100 - isReconnecting = true  
101 - } 91 + wsUrlString += "&auto_subscribe="
  92 + wsUrlString += if (options.autoSubscribe) {
  93 + "1"
  94 + } else {
  95 + "0"
  96 + }
  97 + if (options.reconnect) {
  98 + wsUrlString += "&reconnect=1"
  99 + isReconnecting = true
102 } 100 }
103 101
104 LKLog.i { "connecting to $wsUrlString" } 102 LKLog.i { "connecting to $wsUrlString" }
@@ -4,12 +4,10 @@ import android.content.Context @@ -4,12 +4,10 @@ import android.content.Context
4 import androidx.test.core.app.ApplicationProvider 4 import androidx.test.core.app.ApplicationProvider
5 import io.livekit.android.coroutines.TestCoroutineRule 5 import io.livekit.android.coroutines.TestCoroutineRule
6 import io.livekit.android.events.EventCollector 6 import io.livekit.android.events.EventCollector
7 -import io.livekit.android.events.FlowCollector  
8 import io.livekit.android.events.RoomEvent 7 import io.livekit.android.events.RoomEvent
9 import io.livekit.android.mock.MockWebsocketFactory 8 import io.livekit.android.mock.MockWebsocketFactory
10 import io.livekit.android.mock.dagger.DaggerTestLiveKitComponent 9 import io.livekit.android.mock.dagger.DaggerTestLiveKitComponent
11 import io.livekit.android.room.participant.ConnectionQuality 10 import io.livekit.android.room.participant.ConnectionQuality
12 -import io.livekit.android.util.flow  
13 import io.livekit.android.util.toOkioByteString 11 import io.livekit.android.util.toOkioByteString
14 import kotlinx.coroutines.ExperimentalCoroutinesApi 12 import kotlinx.coroutines.ExperimentalCoroutinesApi
15 import kotlinx.coroutines.launch 13 import kotlinx.coroutines.launch
@@ -53,7 +51,6 @@ class RoomMockE2ETest { @@ -53,7 +51,6 @@ class RoomMockE2ETest {
53 room.connect( 51 room.connect(
54 url = "http://www.example.com", 52 url = "http://www.example.com",
55 token = "", 53 token = "",
56 - options = null  
57 ) 54 )
58 } 55 }
59 56
@@ -77,7 +77,6 @@ class RoomTest { @@ -77,7 +77,6 @@ class RoomTest {
77 room.connect( 77 room.connect(
78 url = "http://www.example.com", 78 url = "http://www.example.com",
79 token = "", 79 token = "",
80 - options = null  
81 ) 80 )
82 } 81 }
83 runBlockingTest { 82 runBlockingTest {
@@ -71,7 +71,7 @@ class SignalClientTest { @@ -71,7 +71,7 @@ class SignalClientTest {
71 @Test 71 @Test
72 fun joinAndResponse() { 72 fun joinAndResponse() {
73 val job = coroutineScope.async { 73 val job = coroutineScope.async {
74 - client.join(EXAMPLE_URL, "", null) 74 + client.join(EXAMPLE_URL, "")
75 } 75 }
76 76
77 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) 77 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
@@ -102,7 +102,7 @@ class SignalClientTest { @@ -102,7 +102,7 @@ class SignalClientTest {
102 client.listener = listener 102 client.listener = listener
103 103
104 val job = coroutineScope.async { 104 val job = coroutineScope.async {
105 - client.join(EXAMPLE_URL, "", null) 105 + client.join(EXAMPLE_URL, "")
106 } 106 }
107 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) 107 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
108 client.onMessage(wsFactory.ws, JOIN.toOkioByteString()) 108 client.onMessage(wsFactory.ws, JOIN.toOkioByteString())
@@ -119,7 +119,7 @@ class SignalClientTest { @@ -119,7 +119,7 @@ class SignalClientTest {
119 client.listener = listener 119 client.listener = listener
120 120
121 val job = coroutineScope.async { 121 val job = coroutineScope.async {
122 - client.join(EXAMPLE_URL, "", null) 122 + client.join(EXAMPLE_URL, "")
123 } 123 }
124 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) 124 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
125 client.onMessage(wsFactory.ws, JOIN.toOkioByteString()) 125 client.onMessage(wsFactory.ws, JOIN.toOkioByteString())
@@ -6,6 +6,7 @@ import androidx.lifecycle.* @@ -6,6 +6,7 @@ import androidx.lifecycle.*
6 import com.github.ajalt.timberkt.Timber 6 import com.github.ajalt.timberkt.Timber
7 import io.livekit.android.ConnectOptions 7 import io.livekit.android.ConnectOptions
8 import io.livekit.android.LiveKit 8 import io.livekit.android.LiveKit
  9 +import io.livekit.android.RoomOptions
9 import io.livekit.android.room.Room 10 import io.livekit.android.room.Room
10 import io.livekit.android.room.RoomListener 11 import io.livekit.android.room.RoomListener
11 import io.livekit.android.room.participant.Participant 12 import io.livekit.android.room.participant.Participant
@@ -70,10 +71,8 @@ class CallViewModel( @@ -70,10 +71,8 @@ class CallViewModel(
70 application, 71 application,
71 url, 72 url,
72 token, 73 token,
73 - ConnectOptions(  
74 - autoManageVideo = true,  
75 - ),  
76 - this@CallViewModel 74 + roomOptions = RoomOptions(autoManageVideo = true),
  75 + listener = this@CallViewModel
77 ) 76 )
78 77
79 // Create and publish audio/video tracks 78 // Create and publish audio/video tracks