davidliu
Committed by GitHub

separate room creation from connect (#28)

* separate room creation from connect

* fix tests
package io.livekit.android
import io.livekit.android.room.participant.AudioTrackPublishDefaults
import io.livekit.android.room.participant.VideoTrackPublishDefaults
import io.livekit.android.room.track.LocalAudioTrackOptions
import io.livekit.android.room.track.LocalVideoTrackOptions
import org.webrtc.PeerConnection
data class ConnectOptions(
/** Auto subscribe to room tracks upon connect, defaults to true */
val autoSubscribe: Boolean = true,
/**
* Automatically manage quality of subscribed video tracks, subscribe to the
* an appropriate resolution based on the size of the video elements that tracks
* are attached to.
*
* Also observes the visibility of attached tracks and pauses receiving data
* if they are not visible.
*/
val autoManageVideo: Boolean = false,
val iceServers: List<PeerConnection.IceServer>? = null,
val rtcConfig: PeerConnection.RTCConfiguration? = null,
... ... @@ -30,11 +17,6 @@ data class ConnectOptions(
* capture and publish video track on connect, defaults to false
*/
val video: Boolean = false,
val audioTrackCaptureDefaults: LocalAudioTrackOptions? = null,
val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null,
val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null,
val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null,
) {
internal var reconnect: Boolean = false
}
... ...
... ... @@ -26,51 +26,52 @@ class LiveKit {
}
}
/**
* Connect to a LiveKit room
* @param url URL to LiveKit server (i.e. ws://mylivekitdeploy.io)
* @param listener Listener to Room events. LiveKit interactions take place with these callbacks
*/
suspend fun connect(
fun create(
appContext: Context,
url: String,
token: String,
options: ConnectOptions?,
listener: RoomListener?
options: RoomOptions = RoomOptions(),
): Room {
val ctx = appContext.applicationContext
val component = DaggerLiveKitComponent
.factory()
.create(ctx)
val room = component.roomFactory()
.create(ctx)
room.listener = listener
room.connect(url, token, options)
val room = component.roomFactory().create(ctx)
options?.audioTrackCaptureDefaults?.let {
room.localParticipant.audioTrackCaptureDefaults = it
options.audioTrackCaptureDefaults?.let {
room.audioTrackCaptureDefaults = it
}
options?.videoTrackCaptureDefaults?.let {
room.localParticipant.videoTrackCaptureDefaults = it
options.videoTrackCaptureDefaults?.let {
room.videoTrackCaptureDefaults = it
}
options?.audioTrackPublishDefaults?.let {
room.localParticipant.audioTrackPublishDefaults = it
options.audioTrackPublishDefaults?.let {
room.audioTrackPublishDefaults = it
}
options?.videoTrackPublishDefaults?.let {
room.localParticipant.videoTrackPublishDefaults = it
options.videoTrackPublishDefaults?.let {
room.videoTrackPublishDefaults = it
}
room.autoManageVideo = options?.autoManageVideo ?: false
room.autoManageVideo = options.autoManageVideo
if (options?.audio == true) {
val audioTrack = room.localParticipant.createAudioTrack()
room.localParticipant.publishAudioTrack(audioTrack)
}
if (options?.video == true) {
val videoTrack = room.localParticipant.createVideoTrack()
room.localParticipant.publishVideoTrack(videoTrack)
return room
}
/**
* Connect to a LiveKit room
* @param url URL to LiveKit server (i.e. ws://mylivekitdeploy.io)
* @param listener Listener to Room events. LiveKit interactions take place with these callbacks
*/
suspend fun connect(
appContext: Context,
url: String,
token: String,
options: ConnectOptions = ConnectOptions(),
roomOptions: RoomOptions = RoomOptions(),
listener: RoomListener?
): Room {
val room = create(appContext)
room.listener = listener
room.connect(url, token, options)
return room
}
... ...
package io.livekit.android
import io.livekit.android.room.participant.AudioTrackPublishDefaults
import io.livekit.android.room.participant.VideoTrackPublishDefaults
import io.livekit.android.room.track.LocalAudioTrackOptions
import io.livekit.android.room.track.LocalVideoTrackOptions
data class RoomOptions(
/**
* Automatically manage quality of subscribed video tracks, subscribe to the
* an appropriate resolution based on the size of the video elements that tracks
* are attached to.
*
* Also observes the visibility of attached tracks and pauses receiving data
* if they are not visible.
*/
val autoManageVideo: Boolean = false,
val audioTrackCaptureDefaults: LocalAudioTrackOptions? = null,
val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null,
val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null,
val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null,
)
\ No newline at end of file
... ...
... ... @@ -88,7 +88,7 @@ internal constructor(
client.listener = this
}
suspend fun join(url: String, token: String, options: ConnectOptions?): LivekitRtc.JoinResponse {
suspend fun join(url: String, token: String, options: ConnectOptions): LivekitRtc.JoinResponse {
sessionUrl = url
sessionToken = token
val joinResponse = client.join(url, token, options)
... ...
... ... @@ -80,10 +80,34 @@ constructor(
var metadata: String? by flowDelegate(null)
private set
/**
* Automatically manage quality of subscribed video tracks, subscribe to the
* an appropriate resolution based on the size of the video elements that tracks
* are attached to.
*
* Also observes the visibility of attached tracks and pauses receiving data
* if they are not visible.
*/
var autoManageVideo: Boolean = false
/**
* Default options to use when creating an audio track.
*/
var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults
/**
* Default options to use when publishing an audio track.
*/
var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults
/**
* Default options to use when creating a video track.
*/
var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults
/**
* Default options to use when publishing a video track.
*/
var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults
lateinit var localParticipant: LocalParticipant
... ... @@ -103,13 +127,12 @@ constructor(
get() = mutableActiveSpeakers
private var hasLostConnectivity: Boolean = false
suspend fun connect(url: String, token: String, options: ConnectOptions?) {
suspend fun connect(url: String, token: String, options: ConnectOptions = ConnectOptions()) {
if (this::coroutineScope.isInitialized) {
coroutineScope.cancel()
}
coroutineScope = CoroutineScope(defaultDispatcher + SupervisorJob())
state = State.CONNECTING
::state.flow
val response = engine.join(url, token, options)
LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" }
... ... @@ -134,6 +157,15 @@ constructor(
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
cm.registerNetworkCallback(networkRequest, this)
if (options.audio) {
val audioTrack = localParticipant.createAudioTrack()
localParticipant.publishAudioTrack(audioTrack)
}
if (options.video) {
val videoTrack = localParticipant.createVideoTrack()
localParticipant.publishVideoTrack(videoTrack)
}
}
fun disconnect() {
... ...
... ... @@ -62,7 +62,7 @@ constructor(
suspend fun join(
url: String,
token: String,
options: ConnectOptions?,
options: ConnectOptions = ConnectOptions(),
) : LivekitRtc.JoinResponse {
val joinResponse = connect(url,token, options)
return (joinResponse as Either.Left).value
... ... @@ -80,7 +80,7 @@ constructor(
suspend fun connect(
url: String,
token: String,
options: ConnectOptions?
options: ConnectOptions
) : Either<LivekitRtc.JoinResponse, Unit> {
var wsUrlString = "$url/rtc" +
"?protocol=$PROTOCOL_VERSION" +
... ... @@ -88,7 +88,6 @@ constructor(
"&sdk=$SDK_TYPE" +
"&version=${Version.CLIENT_VERSION}"
isReconnecting = false
if (options != null) {
wsUrlString += "&auto_subscribe="
wsUrlString += if (options.autoSubscribe) {
"1"
... ... @@ -99,7 +98,6 @@ constructor(
wsUrlString += "&reconnect=1"
isReconnecting = true
}
}
LKLog.i { "connecting to $wsUrlString" }
... ...
... ... @@ -4,12 +4,10 @@ import android.content.Context
import androidx.test.core.app.ApplicationProvider
import io.livekit.android.coroutines.TestCoroutineRule
import io.livekit.android.events.EventCollector
import io.livekit.android.events.FlowCollector
import io.livekit.android.events.RoomEvent
import io.livekit.android.mock.MockWebsocketFactory
import io.livekit.android.mock.dagger.DaggerTestLiveKitComponent
import io.livekit.android.room.participant.ConnectionQuality
import io.livekit.android.util.flow
import io.livekit.android.util.toOkioByteString
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
... ... @@ -53,7 +51,6 @@ class RoomMockE2ETest {
room.connect(
url = "http://www.example.com",
token = "",
options = null
)
}
... ...
... ... @@ -77,7 +77,6 @@ class RoomTest {
room.connect(
url = "http://www.example.com",
token = "",
options = null
)
}
runBlockingTest {
... ...
... ... @@ -71,7 +71,7 @@ class SignalClientTest {
@Test
fun joinAndResponse() {
val job = coroutineScope.async {
client.join(EXAMPLE_URL, "", null)
client.join(EXAMPLE_URL, "")
}
client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
... ... @@ -102,7 +102,7 @@ class SignalClientTest {
client.listener = listener
val job = coroutineScope.async {
client.join(EXAMPLE_URL, "", null)
client.join(EXAMPLE_URL, "")
}
client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
client.onMessage(wsFactory.ws, JOIN.toOkioByteString())
... ... @@ -119,7 +119,7 @@ class SignalClientTest {
client.listener = listener
val job = coroutineScope.async {
client.join(EXAMPLE_URL, "", null)
client.join(EXAMPLE_URL, "")
}
client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
client.onMessage(wsFactory.ws, JOIN.toOkioByteString())
... ...
... ... @@ -6,6 +6,7 @@ import androidx.lifecycle.*
import com.github.ajalt.timberkt.Timber
import io.livekit.android.ConnectOptions
import io.livekit.android.LiveKit
import io.livekit.android.RoomOptions
import io.livekit.android.room.Room
import io.livekit.android.room.RoomListener
import io.livekit.android.room.participant.Participant
... ... @@ -70,10 +71,8 @@ class CallViewModel(
application,
url,
token,
ConnectOptions(
autoManageVideo = true,
),
this@CallViewModel
roomOptions = RoomOptions(autoManageVideo = true),
listener = this@CallViewModel
)
// Create and publish audio/video tracks
... ...