David Liu

publish local tracks upon connecting

... ... @@ -2,5 +2,7 @@ package io.livekit.android
data class ConnectOptions(
val isSecure: Boolean = true
val isSecure: Boolean = true,
val sendAudio: Boolean = true,
val sendVideo: Boolean = true,
)
\ No newline at end of file
... ...
... ... @@ -3,6 +3,11 @@ package io.livekit.android
import android.content.Context
import io.livekit.android.dagger.DaggerLiveKitComponent
import io.livekit.android.room.Room
import io.livekit.android.room.track.LocalAudioTrack
import io.livekit.android.room.track.LocalVideoTrack
import org.webrtc.EglBase
import org.webrtc.MediaConstraints
import org.webrtc.PeerConnectionFactory
class LiveKit {
companion object {
... ... @@ -23,7 +28,42 @@ class LiveKit {
room.listener = listener
room.connect(url, token, options.isSecure)
val localParticipant = room.localParticipant
if (localParticipant != null) {
val factory = component.peerConnectionFactory()
if (options.sendAudio) {
localParticipant.publishAudioTrack(createLocalAudioTrack(factory))
}
if (options.sendVideo) {
localParticipant.publishVideoTrack(
createLocalVideoTrack(
factory,
appContext,
component.eglBase()
)
)
}
}
return room
}
private fun createLocalVideoTrack(
peerConnectionFactory: PeerConnectionFactory,
context: Context,
rootEglBase: EglBase,
): LocalVideoTrack {
return LocalVideoTrack.track(
peerConnectionFactory,
context,
true,
"LiveKit Video",
rootEglBase
)
}
private fun createLocalAudioTrack(factory: PeerConnectionFactory): LocalAudioTrack {
val audioConstraints = MediaConstraints()
return LocalAudioTrack.createTrack(factory, audioConstraints)
}
}
}
... ...
... ... @@ -4,6 +4,8 @@ import android.content.Context
import dagger.BindsInstance
import dagger.Component
import io.livekit.android.room.Room
import org.webrtc.EglBase
import org.webrtc.PeerConnectionFactory
import javax.inject.Singleton
@Singleton
... ... @@ -19,6 +21,10 @@ interface LiveKitComponent {
fun roomFactory(): Room.Factory
fun peerConnectionFactory(): PeerConnectionFactory
fun eglBase(): EglBase
@Component.Factory
interface Factory {
fun create(@BindsInstance appContext: Context): LiveKitComponent
... ...
package io.livekit.android.room
import com.github.ajalt.timberkt.Timber
import livekit.Rtc
import org.webrtc.*
... ... @@ -22,6 +23,7 @@ class PublisherTransportObserver(
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState?) {
val state = newState ?: throw NullPointerException("unexpected null new state, what do?")
Timber.v { "onIceConnection new state: $newState" }
if (state == PeerConnection.IceConnectionState.CONNECTED && !engine.iceConnected) {
engine.iceConnected = true
} else if (state == PeerConnection.IceConnectionState.DISCONNECTED) {
... ...
... ... @@ -36,9 +36,9 @@ constructor(
var iceConnected: Boolean = false
set(value) {
field = value
if (field) {
// TODO get rid of this assertion
listener?.onJoin(joinResponse!!)
val savedJoinResponse = joinResponse
if (field && savedJoinResponse != null) {
listener?.onJoin(savedJoinResponse)
joinResponse = null
}
}
... ... @@ -90,6 +90,7 @@ constructor(
}
fun close() {
coroutineScope.close()
publisher.close()
subscriber.close()
client.close()
... ... @@ -110,6 +111,7 @@ constructor(
}
}
Timber.v { "sdp offer = $sdpOffer, description: ${sdpOffer.description}, type: ${sdpOffer.type}" }
when (val outcome = publisher.peerConnection.setLocalDescription(sdpOffer)) {
is Either.Right -> {
Timber.d { "error setting local description: ${outcome.value}" }
... ...
... ... @@ -14,6 +14,9 @@ import io.livekit.android.room.util.unpackedTrackLabel
import livekit.Model
import livekit.Rtc
import org.webrtc.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class Room
@AssistedInject
... ... @@ -53,12 +56,15 @@ constructor(
val activeSpeakers: List<Participant>
get() = mutableActiveSpeakers
private var connectContinuation: Continuation<Unit>? = null
suspend fun connect(url: String, token: String, isSecure: Boolean) {
if (localParticipant != null) {
Timber.d { "Attempting to connect to room when already connected." }
return
}
engine.join(url, token, isSecure)
return suspendCoroutine { connectContinuation = it }
}
fun disconnect() {
... ... @@ -170,6 +176,8 @@ constructor(
}
}
connectContinuation?.resume(Unit)
connectContinuation = null
listener?.onConnect(this)
}
... ... @@ -192,7 +200,7 @@ constructor(
participant.addSubscribedDataTrack(channel, trackSid, name)
}
override fun onPublishLocalTrack(cid: String, track: Model.TrackInfo) {
override fun onPublishLocalTrack(cid: Track.Cid, track: Model.TrackInfo) {
}
... ...
... ... @@ -6,6 +6,7 @@ import io.livekit.android.room.track.*
import livekit.Model
import org.webrtc.DataChannel
import org.webrtc.RtpTransceiver
import java.util.*
class LocalParticipant(sid: Sid, name: String? = null) :
Participant(sid, name) {
... ... @@ -17,7 +18,7 @@ class LocalParticipant(sid: Sid, name: String? = null) :
this.engine = engine
}
private val streamId = "stream"
private val streamId = UUID.randomUUID().toString()
val localAudioTrackPublications
get() = audioTracks.values.toList()
... ...
package io.livekit.android.room.track
import org.webrtc.MediaConstraints
import org.webrtc.PeerConnectionFactory
class LocalAudioTrack(
name: String,
audioOptions: AudioOptions? = null,
... ... @@ -9,4 +12,20 @@ class LocalAudioTrack(
internal set
var audioOptions = audioOptions
private set
companion object {
fun createTrack(
factory: PeerConnectionFactory,
audioConstraints: MediaConstraints,
name: String = ""
): LocalAudioTrack {
val audioSource = factory.createAudioSource(audioConstraints)
val rtcAudioTrack =
factory.createAudioTrack("phone_audio_track_id", audioSource)
rtcAudioTrack.setEnabled(true)
return LocalAudioTrack(name = name, rtcTrack = rtcAudioTrack)
}
}
}
\ No newline at end of file
... ...