David Liu

local tracks

@@ -37,6 +37,7 @@ android { @@ -37,6 +37,7 @@ android {
37 } 37 }
38 kotlinOptions { 38 kotlinOptions {
39 freeCompilerArgs = ["-Xinline-classes"] 39 freeCompilerArgs = ["-Xinline-classes"]
  40 + jvmTarget = java_version
40 } 41 }
41 } 42 }
42 43
  1 +package io.livekit.android.room.track
  2 +
  3 +class AudioOptions {
  4 +}
  1 +package io.livekit.android.room.track
  2 +
  3 +data class DataTrackOptions(
  4 + val ordered: Boolean = true,
  5 + val maxPacketLifetime: Int = -1,
  6 + val maxRetransmits: Int = -1,
  7 + val name: String
  8 +)
  1 +package io.livekit.android.room.track
  2 +
  3 +class LocalAudioTrack(
  4 + name: String,
  5 + audioOptions: AudioOptions? = null,
  6 + rtcTrack: org.webrtc.AudioTrack
  7 +) : AudioTrack(name, rtcTrack) {
  8 + var sid: Sid? = null
  9 + internal set
  10 + var audioOptions = audioOptions
  11 + private set
  12 +}
  1 +package io.livekit.android.room.track
  2 +
  3 +import org.webrtc.DataChannel
  4 +import java.nio.ByteBuffer
  5 +
  6 +class LocalDataTrack(
  7 + val options: DataTrackOptions,
  8 + rtcTrack: DataChannel
  9 +) : DataTrack(options.name, rtcTrack) {
  10 + var sid: Sid? = null
  11 + internal set
  12 +
  13 + fun sendString(message: String) {
  14 + val byteBuffer = ByteBuffer.wrap(message.toByteArray())
  15 + val buffer = DataChannel.Buffer(byteBuffer, false)
  16 + rtcTrack.send(buffer)
  17 + }
  18 +
  19 + fun sendBytes(byteBuffer: ByteBuffer) {
  20 + val buffer = DataChannel.Buffer(byteBuffer, true)
  21 + rtcTrack.send(buffer)
  22 + }
  23 +}
  1 +package io.livekit.android.room.track
  2 +
  3 +import android.content.Context
  4 +import com.github.ajalt.timberkt.Timber
  5 +import org.webrtc.*
  6 +import java.util.*
  7 +
  8 +
  9 +class LocalVideoTrack(
  10 + private val capturer: VideoCapturer,
  11 + private val source: VideoSource,
  12 + name: String,
  13 + rtcTrack: org.webrtc.VideoTrack
  14 +) : VideoTrack(name, rtcTrack) {
  15 + var sid: Sid? = null
  16 +
  17 + companion object {
  18 + internal fun track(
  19 + peerConnectionFactory: PeerConnectionFactory,
  20 + context: Context,
  21 + enabled: Boolean,
  22 + name: String
  23 + ): LocalVideoTrack {
  24 + val source = peerConnectionFactory.createVideoSource(false)
  25 + val capturer = createVideoCapturer(context) ?: TODO()
  26 + val rootEglBase = EglBase.create()
  27 + capturer.initialize(
  28 + SurfaceTextureHelper.create("CaptureThread", rootEglBase.eglBaseContext),
  29 + context,
  30 + source.capturerObserver
  31 + )
  32 + val track = peerConnectionFactory.createVideoTrack(UUID.randomUUID().toString(), source)
  33 + track.setEnabled(enabled)
  34 +
  35 + return LocalVideoTrack(
  36 + capturer = capturer,
  37 + source = source,
  38 + name = name,
  39 + rtcTrack = track,
  40 + )
  41 + }
  42 +
  43 + private fun createVideoCapturer(context: Context): VideoCapturer? {
  44 + val videoCapturer: VideoCapturer? = if (Camera2Enumerator.isSupported(context)) {
  45 + createCameraCapturer(Camera2Enumerator(context))
  46 + } else {
  47 + createCameraCapturer(Camera1Enumerator(true))
  48 + }
  49 + if (videoCapturer == null) {
  50 + Timber.d { "Failed to open camera" }
  51 + return null
  52 + }
  53 + return videoCapturer
  54 + }
  55 +
  56 + private fun createCameraCapturer(enumerator: CameraEnumerator): VideoCapturer? {
  57 + val deviceNames = enumerator.deviceNames
  58 +
  59 + // First, try to find front facing camera
  60 + for (deviceName in deviceNames) {
  61 + if (enumerator.isFrontFacing(deviceName)) {
  62 + Timber.v { "Creating front facing camera capturer." }
  63 + val videoCapturer = enumerator.createCapturer(deviceName, null)
  64 + if (videoCapturer != null) {
  65 + return videoCapturer
  66 + }
  67 + }
  68 + }
  69 +
  70 + // Front facing camera not found, try something else
  71 + for (deviceName in deviceNames) {
  72 + if (!enumerator.isFrontFacing(deviceName)) {
  73 + Timber.v { "Creating other camera capturer." }
  74 + val videoCapturer = enumerator.createCapturer(deviceName, null)
  75 + if (videoCapturer != null) {
  76 + return videoCapturer
  77 + }
  78 + }
  79 + }
  80 + return null
  81 + }
  82 +
  83 + }
  84 +}