davidliu
Committed by GitHub

Updates for 2.0.0 (#353)

* Prefix webrtc to avoid collisions with other libraries

* Prepare for v2.0.0

* Move test webrtc files as well

* Revert java target to Java 1.8

* Remove LiveKit.connect method

* Rename participant's track variables to trackPublication to accurately reflect type

* update protocol submodule

* Change remoteParticipants to identity keys

Also add in the Participant Sid/Identity value classes to prevent mistakes

* change publishData to take in Identity type

* Move to android-prefixed webrtc library

* Make inline value classes serializable

* Fix publishdata send to identity destination

* Support sync stream id

* Remap LivekitModels.VideoQuality to VideoQuality enum

The new VideoQuality enum exposes only the ones that should be used by consumers

* Suspend function for getSid

* spotless

* fix compile

* Add documentation and internal visibility for internal classes
正在显示 100 个修改的文件 包含 813 行增加563 行删除

要显示太多修改。

为保证性能只显示 100 of 100+ 个文件。

@@ -57,7 +57,11 @@ subprojects { @@ -57,7 +57,11 @@ subprojects {
57 } 57 }
58 kotlin { 58 kotlin {
59 target("src/*/java/**/*.kt") 59 target("src/*/java/**/*.kt")
60 - targetExclude("src/*/java/**/ReentrantMutex.kt") // Different license 60 + targetExclude(
  61 + "src/*/java/**/ReentrantMutex.kt", // Different license
  62 + "src/*/java/**/TextureViewRenderer.kt", // Different license
  63 + "src/*/java/**/FlowDelegate.kt", // Different license
  64 + )
61 ktlint("0.50.0") 65 ktlint("0.50.0")
62 .setEditorConfigPath("$rootDir/.editorconfig") 66 .setEditorConfigPath("$rootDir/.editorconfig")
63 licenseHeaderFile(rootProject.file("LicenseHeaderFile.txt")) 67 licenseHeaderFile(rootProject.file("LicenseHeaderFile.txt"))
@@ -65,7 +65,7 @@ ext { @@ -65,7 +65,7 @@ ext {
65 "kotlin": "org.mockito.kotlin:mockito-kotlin:4.0.0", 65 "kotlin": "org.mockito.kotlin:mockito-kotlin:4.0.0",
66 ], 66 ],
67 robolectric : 'org.robolectric:robolectric:4.10.2', 67 robolectric : 'org.robolectric:robolectric:4.10.2',
68 - 68 + turbine : 'app.cash.turbine:turbine:1.0.0',
69 ] 69 ]
70 annotations = [ 70 annotations = [
71 ] 71 ]
@@ -23,7 +23,8 @@ kotlin.code.style=official @@ -23,7 +23,8 @@ kotlin.code.style=official
23 ############################################################### 23 ###############################################################
24 24
25 GROUP=io.livekit 25 GROUP=io.livekit
26 -VERSION_NAME=1.6.0 26 +VERSION_NAME=2.0.0-SNAPSHOT
  27 +
27 28
28 POM_DESCRIPTION=LiveKit Android SDK, WebRTC Rooms 29 POM_DESCRIPTION=LiveKit Android SDK, WebRTC Rooms
29 30
@@ -147,7 +147,7 @@ dependencies { @@ -147,7 +147,7 @@ dependencies {
147 implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 147 implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
148 implementation deps.coroutines.lib 148 implementation deps.coroutines.lib
149 implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:${versions.serialization}" 149 implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:${versions.serialization}"
150 - api 'io.github.webrtc-sdk:android:114.5735.05' 150 + api 'io.github.webrtc-sdk:android-prefixed:114.5735.07'
151 api "com.squareup.okhttp3:okhttp:4.12.0" 151 api "com.squareup.okhttp3:okhttp:4.12.0"
152 api 'com.github.davidliu:audioswitch:89582c47c9a04c62f90aa5e57251af4800a62c9a' 152 api 'com.github.davidliu:audioswitch:89582c47c9a04c62f90aa5e57251af4800a62c9a'
153 implementation deps.androidx.annotation 153 implementation deps.androidx.annotation
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 22
23 # WebRTC 23 # WebRTC
24 ######################################### 24 #########################################
25 --keep class org.webrtc.** { *; } 25 +-keep class livekit.org.webrtc.** { *; }
26 26
27 # NIST sdp parser 27 # NIST sdp parser
28 ######################################### 28 #########################################
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,8 +17,12 @@ @@ -17,8 +17,12 @@
17 package io.livekit.android 17 package io.livekit.android
18 18
19 import io.livekit.android.room.ProtocolVersion 19 import io.livekit.android.room.ProtocolVersion
20 -import org.webrtc.PeerConnection 20 +import io.livekit.android.room.Room
  21 +import livekit.org.webrtc.PeerConnection
21 22
  23 +/**
  24 + * Options for using with [Room.connect].
  25 + */
22 data class ConnectOptions( 26 data class ConnectOptions(
23 /** Auto subscribe to room tracks upon connect, defaults to true */ 27 /** Auto subscribe to room tracks upon connect, defaults to true */
24 val autoSubscribe: Boolean = true, 28 val autoSubscribe: Boolean = true,
@@ -48,7 +52,7 @@ data class ConnectOptions( @@ -48,7 +52,7 @@ data class ConnectOptions(
48 /** 52 /**
49 * the protocol version to use with the server. 53 * the protocol version to use with the server.
50 */ 54 */
51 - val protocolVersion: ProtocolVersion = ProtocolVersion.v9 55 + val protocolVersion: ProtocolVersion = ProtocolVersion.v12,
52 ) { 56 ) {
53 internal var reconnect: Boolean = false 57 internal var reconnect: Boolean = false
54 internal var participantSid: String? = null 58 internal var participantSid: String? = null
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,15 +21,12 @@ import android.content.Context @@ -21,15 +21,12 @@ import android.content.Context
21 import io.livekit.android.dagger.DaggerLiveKitComponent 21 import io.livekit.android.dagger.DaggerLiveKitComponent
22 import io.livekit.android.dagger.RTCModule 22 import io.livekit.android.dagger.RTCModule
23 import io.livekit.android.dagger.create 23 import io.livekit.android.dagger.create
24 -import io.livekit.android.room.ProtocolVersion  
25 import io.livekit.android.room.Room 24 import io.livekit.android.room.Room
26 -import io.livekit.android.room.RoomListener  
27 import io.livekit.android.util.LKLog 25 import io.livekit.android.util.LKLog
28 import io.livekit.android.util.LoggingLevel 26 import io.livekit.android.util.LoggingLevel
29 import timber.log.Timber 27 import timber.log.Timber
30 28
31 -class LiveKit {  
32 - companion object { 29 +object LiveKit {
33 /** 30 /**
34 * [LoggingLevel] to use for Livekit logs. Set to [LoggingLevel.OFF] to turn off logs. 31 * [LoggingLevel] to use for Livekit logs. Set to [LoggingLevel.OFF] to turn off logs.
35 * 32 *
@@ -109,31 +106,4 @@ class LiveKit { @@ -109,31 +106,4 @@ class LiveKit {
109 106
110 return room 107 return room
111 } 108 }
112 -  
113 - /**  
114 - * Connect to a LiveKit room  
115 - * @param url URL to LiveKit server (i.e. ws://mylivekitdeploy.io)  
116 - * @param listener Listener to Room events. LiveKit interactions take place with these callbacks  
117 - */  
118 - @Deprecated("Use LiveKit.create and Room.connect instead. This is limited to max protocol 7.")  
119 - suspend fun connect(  
120 - appContext: Context,  
121 - url: String,  
122 - token: String,  
123 - options: ConnectOptions = ConnectOptions(),  
124 - roomOptions: RoomOptions = RoomOptions(),  
125 - listener: RoomListener? = null,  
126 - overrides: LiveKitOverrides = LiveKitOverrides(),  
127 - ): Room {  
128 - val room = create(appContext, roomOptions, overrides)  
129 -  
130 - room.listener = listener  
131 -  
132 - val protocolVersion = maxOf(options.protocolVersion, ProtocolVersion.v7)  
133 - val connectOptions = options.copy(protocolVersion = protocolVersion)  
134 -  
135 - room.connect(url, token, connectOptions)  
136 - return room  
137 - }  
138 - }  
139 } 109 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@ import io.livekit.android.audio.AudioHandler @@ -23,12 +23,12 @@ import io.livekit.android.audio.AudioHandler
23 import io.livekit.android.audio.AudioSwitchHandler 23 import io.livekit.android.audio.AudioSwitchHandler
24 import io.livekit.android.audio.NoAudioHandler 24 import io.livekit.android.audio.NoAudioHandler
25 import io.livekit.android.room.Room 25 import io.livekit.android.room.Room
  26 +import livekit.org.webrtc.EglBase
  27 +import livekit.org.webrtc.VideoDecoderFactory
  28 +import livekit.org.webrtc.VideoEncoderFactory
  29 +import livekit.org.webrtc.audio.AudioDeviceModule
  30 +import livekit.org.webrtc.audio.JavaAudioDeviceModule
26 import okhttp3.OkHttpClient 31 import okhttp3.OkHttpClient
27 -import org.webrtc.EglBase  
28 -import org.webrtc.VideoDecoderFactory  
29 -import org.webrtc.VideoEncoderFactory  
30 -import org.webrtc.audio.AudioDeviceModule  
31 -import org.webrtc.audio.JavaAudioDeviceModule  
32 32
33 /** 33 /**
34 * Overrides to replace LiveKit internally used components with custom implementations. 34 * Overrides to replace LiveKit internally used components with custom implementations.
@@ -65,6 +65,9 @@ data class LiveKitOverrides( @@ -65,6 +65,9 @@ data class LiveKitOverrides(
65 val eglBase: EglBase? = null, 65 val eglBase: EglBase? = null,
66 ) 66 )
67 67
  68 +/**
  69 + * Options for customizing the audio settings of LiveKit.
  70 + */
68 class AudioOptions( 71 class AudioOptions(
69 /** 72 /**
70 * Override the default output [AudioType]. 73 * Override the default output [AudioType].
@@ -103,6 +106,9 @@ class AudioOptions( @@ -103,6 +106,9 @@ class AudioOptions(
103 val javaAudioDeviceModuleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)? = null, 106 val javaAudioDeviceModuleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)? = null,
104 ) 107 )
105 108
  109 +/**
  110 + * Audio types for customizing the audio of LiveKit.
  111 + */
106 sealed class AudioType( 112 sealed class AudioType(
107 val audioMode: Int, 113 val audioMode: Int,
108 val audioAttributes: AudioAttributes, 114 val audioAttributes: AudioAttributes,
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,6 +16,12 @@ @@ -16,6 +16,12 @@
16 16
17 package io.livekit.android 17 package io.livekit.android
18 18
  19 +/**
  20 + * Version information about LiveKit
  21 + */
19 object Version { 22 object Version {
  23 + /**
  24 + * The current LiveKit SDK version.
  25 + */
20 const val CLIENT_VERSION = BuildConfig.VERSION_NAME 26 const val CLIENT_VERSION = BuildConfig.VERSION_NAME
21 } 27 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -76,6 +76,9 @@ constructor(context: Context) : AudioHandler { @@ -76,6 +76,9 @@ constructor(context: Context) : AudioHandler {
76 onAudioFocusChangeListener?.onAudioFocusChange(it) 76 onAudioFocusChangeListener?.onAudioFocusChange(it)
77 } 77 }
78 78
  79 + /**
  80 + * Set this to listen to audio focus changes.
  81 + */
79 var onAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null 82 var onAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null
80 83
81 override fun start() { 84 override fun start() {
@@ -98,6 +101,16 @@ constructor(context: Context) : AudioHandler { @@ -98,6 +101,16 @@ constructor(context: Context) : AudioHandler {
98 } 101 }
99 } 102 }
100 103
  104 + /**
  105 + * Creates the request used when requesting audio focus.
  106 + *
  107 + * The default implementation creates an audio focus request based on the
  108 + * settings of this object.
  109 + *
  110 + * Only used on Android O and upwards. On lower platforms,
  111 + * the request will be made using the [audioStreamType] and [focusMode]
  112 + * settings.
  113 + */
101 @RequiresApi(Build.VERSION_CODES.O) 114 @RequiresApi(Build.VERSION_CODES.O)
102 open fun createAudioRequest(): AudioFocusRequest { 115 open fun createAudioRequest(): AudioFocusRequest {
103 return AudioFocusRequest.Builder(focusMode) 116 return AudioFocusRequest.Builder(focusMode)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -183,12 +183,21 @@ constructor(private val context: Context) : AudioHandler { @@ -183,12 +183,21 @@ constructor(private val context: Context) : AudioHandler {
183 } 183 }
184 } 184 }
185 185
  186 + /**
  187 + * The currently selected audio device, or null if none (or this handler is not started).
  188 + */
186 val selectedAudioDevice: AudioDevice? 189 val selectedAudioDevice: AudioDevice?
187 get() = audioSwitch?.selectedAudioDevice 190 get() = audioSwitch?.selectedAudioDevice
188 191
  192 + /**
  193 + * The available audio devices. This requires calling [start] before it is populated.
  194 + */
189 val availableAudioDevices: List<AudioDevice> 195 val availableAudioDevices: List<AudioDevice>
190 get() = audioSwitch?.availableAudioDevices ?: listOf() 196 get() = audioSwitch?.availableAudioDevices ?: listOf()
191 197
  198 + /**
  199 + * Select a specific audio device.
  200 + */
192 fun selectDevice(audioDevice: AudioDevice?) { 201 fun selectDevice(audioDevice: AudioDevice?) {
193 if (Looper.myLooper() == Looper.getMainLooper()) { 202 if (Looper.myLooper() == Looper.getMainLooper()) {
194 audioSwitch?.selectDevice(audioDevice) 203 audioSwitch?.selectDevice(audioDevice)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import javax.inject.Singleton @@ -30,7 +30,7 @@ import javax.inject.Singleton
30 * @suppress 30 * @suppress
31 */ 31 */
32 @Module 32 @Module
33 -object AudioHandlerModule { 33 +internal object AudioHandlerModule {
34 34
35 @Provides 35 @Provides
36 fun audioOutputType( 36 fun audioOutputType(
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import javax.inject.Named @@ -25,7 +25,7 @@ import javax.inject.Named
25 * @suppress 25 * @suppress
26 */ 26 */
27 @Module 27 @Module
28 -object CoroutinesModule { 28 +internal object CoroutinesModule {
29 @Provides 29 @Provides
30 @Named(InjectionNames.DISPATCHER_DEFAULT) 30 @Named(InjectionNames.DISPATCHER_DEFAULT)
31 fun defaultDispatcher() = Dispatchers.Default 31 fun defaultDispatcher() = Dispatchers.Default
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,10 +16,7 @@ @@ -16,10 +16,7 @@
16 16
17 package io.livekit.android.dagger 17 package io.livekit.android.dagger
18 18
19 -/**  
20 - * @suppress  
21 - */  
22 -object InjectionNames { 19 +internal object InjectionNames {
23 20
24 /** 21 /**
25 * @see [kotlinx.coroutines.Dispatchers.Default] 22 * @see [kotlinx.coroutines.Dispatchers.Default]
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,11 +21,8 @@ import dagger.Provides @@ -21,11 +21,8 @@ import dagger.Provides
21 import dagger.Reusable 21 import dagger.Reusable
22 import kotlinx.serialization.json.Json 22 import kotlinx.serialization.json.Json
23 23
24 -/**  
25 - * @suppress  
26 - */  
27 @Module 24 @Module
28 -object JsonFormatModule { 25 +internal object JsonFormatModule {
29 @Provides 26 @Provides
30 @Reusable 27 @Reusable
31 fun kotlinSerializationJson(): Json = 28 fun kotlinSerializationJson(): Json =
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@ import dagger.BindsInstance @@ -21,8 +21,8 @@ import dagger.BindsInstance
21 import dagger.Component 21 import dagger.Component
22 import io.livekit.android.LiveKitOverrides 22 import io.livekit.android.LiveKitOverrides
23 import io.livekit.android.room.Room 23 import io.livekit.android.room.Room
24 -import org.webrtc.EglBase  
25 -import org.webrtc.PeerConnectionFactory 24 +import livekit.org.webrtc.EglBase
  25 +import livekit.org.webrtc.PeerConnectionFactory
26 import javax.inject.Singleton 26 import javax.inject.Singleton
27 27
28 @Singleton 28 @Singleton
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,11 +21,8 @@ import dagger.Provides @@ -21,11 +21,8 @@ import dagger.Provides
21 import io.livekit.android.memory.CloseableManager 21 import io.livekit.android.memory.CloseableManager
22 import javax.inject.Singleton 22 import javax.inject.Singleton
23 23
24 -/**  
25 - * @suppress  
26 - */  
27 @Module 24 @Module
28 -object MemoryModule { 25 +internal object MemoryModule {
29 26
30 @Singleton 27 @Singleton
31 @Provides 28 @Provides
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -24,11 +24,8 @@ import io.livekit.android.LiveKitOverrides @@ -24,11 +24,8 @@ import io.livekit.android.LiveKitOverrides
24 import javax.inject.Named 24 import javax.inject.Named
25 25
26 @SuppressLint("KotlinNullnessAnnotation") 26 @SuppressLint("KotlinNullnessAnnotation")
27 -/**  
28 - * @suppress  
29 - */  
30 @Module 27 @Module
31 -class OverridesModule(private val overrides: LiveKitOverrides) { 28 +internal class OverridesModule(private val overrides: LiveKitOverrides) {
32 29
33 @Provides 30 @Provides
34 @Named(InjectionNames.OVERRIDE_OKHTTP) 31 @Named(InjectionNames.OVERRIDE_OKHTTP)
@@ -30,20 +30,17 @@ import io.livekit.android.util.LKLog @@ -30,20 +30,17 @@ import io.livekit.android.util.LKLog
30 import io.livekit.android.util.LoggingLevel 30 import io.livekit.android.util.LoggingLevel
31 import io.livekit.android.webrtc.CustomVideoDecoderFactory 31 import io.livekit.android.webrtc.CustomVideoDecoderFactory
32 import io.livekit.android.webrtc.CustomVideoEncoderFactory 32 import io.livekit.android.webrtc.CustomVideoEncoderFactory
33 -import org.webrtc.*  
34 -import org.webrtc.audio.AudioDeviceModule  
35 -import org.webrtc.audio.JavaAudioDeviceModule 33 +import livekit.org.webrtc.*
  34 +import livekit.org.webrtc.audio.AudioDeviceModule
  35 +import livekit.org.webrtc.audio.JavaAudioDeviceModule
36 import timber.log.Timber 36 import timber.log.Timber
37 import javax.inject.Named 37 import javax.inject.Named
38 import javax.inject.Singleton 38 import javax.inject.Singleton
39 39
40 -typealias CapabilitiesGetter = @JvmSuppressWildcards (MediaStreamTrack.MediaType) -> RtpCapabilities 40 +internal typealias CapabilitiesGetter = @JvmSuppressWildcards (MediaStreamTrack.MediaType) -> RtpCapabilities
41 41
42 -/**  
43 - * @suppress  
44 - */  
45 @Module 42 @Module
46 -object RTCModule { 43 +internal object RTCModule {
47 44
48 /** 45 /**
49 * Certain classes require libwebrtc to be initialized prior to use. 46 * Certain classes require libwebrtc to be initialized prior to use.
@@ -55,6 +52,7 @@ object RTCModule { @@ -55,6 +52,7 @@ object RTCModule {
55 PeerConnectionFactory.initialize( 52 PeerConnectionFactory.initialize(
56 PeerConnectionFactory.InitializationOptions 53 PeerConnectionFactory.InitializationOptions
57 .builder(appContext) 54 .builder(appContext)
  55 + .setNativeLibraryName("lkjingle_peerconnection_so")
58 .setInjectableLogger( 56 .setInjectableLogger(
59 { s, severity, s2 -> 57 { s, severity, s2 ->
60 if (!LiveKit.enableWebRTCLogging) { 58 if (!LiveKit.enableWebRTCLogging) {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -28,11 +28,8 @@ import okhttp3.WebSocket @@ -28,11 +28,8 @@ import okhttp3.WebSocket
28 import javax.inject.Named 28 import javax.inject.Named
29 import javax.inject.Singleton 29 import javax.inject.Singleton
30 30
31 -/**  
32 - * @suppress  
33 - */  
34 @Module 31 @Module
35 -object WebModule { 32 +internal object WebModule {
36 @Provides 33 @Provides
37 @Singleton 34 @Singleton
38 fun okHttpClient( 35 fun okHttpClient(
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import dagger.assisted.AssistedInject @@ -22,6 +22,7 @@ import dagger.assisted.AssistedInject
22 import io.livekit.android.events.RoomEvent 22 import io.livekit.android.events.RoomEvent
23 import io.livekit.android.room.Room 23 import io.livekit.android.room.Room
24 import io.livekit.android.room.participant.LocalParticipant 24 import io.livekit.android.room.participant.LocalParticipant
  25 +import io.livekit.android.room.participant.Participant
25 import io.livekit.android.room.participant.RemoteParticipant 26 import io.livekit.android.room.participant.RemoteParticipant
26 import io.livekit.android.room.track.LocalAudioTrack 27 import io.livekit.android.room.track.LocalAudioTrack
27 import io.livekit.android.room.track.LocalVideoTrack 28 import io.livekit.android.room.track.LocalVideoTrack
@@ -30,13 +31,13 @@ import io.livekit.android.room.track.RemoteVideoTrack @@ -30,13 +31,13 @@ import io.livekit.android.room.track.RemoteVideoTrack
30 import io.livekit.android.room.track.Track 31 import io.livekit.android.room.track.Track
31 import io.livekit.android.room.track.TrackPublication 32 import io.livekit.android.room.track.TrackPublication
32 import io.livekit.android.util.LKLog 33 import io.livekit.android.util.LKLog
33 -import org.webrtc.FrameCryptor  
34 -import org.webrtc.FrameCryptor.FrameCryptionState  
35 -import org.webrtc.FrameCryptorAlgorithm  
36 -import org.webrtc.FrameCryptorFactory  
37 -import org.webrtc.PeerConnectionFactory  
38 -import org.webrtc.RtpReceiver  
39 -import org.webrtc.RtpSender 34 +import livekit.org.webrtc.FrameCryptor
  35 +import livekit.org.webrtc.FrameCryptor.FrameCryptionState
  36 +import livekit.org.webrtc.FrameCryptorAlgorithm
  37 +import livekit.org.webrtc.FrameCryptorFactory
  38 +import livekit.org.webrtc.PeerConnectionFactory
  39 +import livekit.org.webrtc.RtpReceiver
  40 +import livekit.org.webrtc.RtpSender
40 41
41 class E2EEManager 42 class E2EEManager
42 @AssistedInject 43 @AssistedInject
@@ -47,7 +48,7 @@ constructor( @@ -47,7 +48,7 @@ constructor(
47 private var room: Room? = null 48 private var room: Room? = null
48 private var keyProvider: KeyProvider 49 private var keyProvider: KeyProvider
49 private var peerConnectionFactory: PeerConnectionFactory 50 private var peerConnectionFactory: PeerConnectionFactory
50 - private var frameCryptors = mutableMapOf<Pair<String, String>, FrameCryptor>() 51 + private var frameCryptors = mutableMapOf<Pair<String, Participant.Identity>, FrameCryptor>()
51 private var algorithm: FrameCryptorAlgorithm = FrameCryptorAlgorithm.AES_GCM 52 private var algorithm: FrameCryptorAlgorithm = FrameCryptorAlgorithm.AES_GCM
52 private lateinit var emitEvent: (roomEvent: RoomEvent) -> Unit? 53 private lateinit var emitEvent: (roomEvent: RoomEvent) -> Unit?
53 var enabled: Boolean = false 54 var enabled: Boolean = false
@@ -69,7 +70,7 @@ constructor( @@ -69,7 +70,7 @@ constructor(
69 this.enabled = true 70 this.enabled = true
70 this.room = room 71 this.room = room
71 this.emitEvent = emitEvent 72 this.emitEvent = emitEvent
72 - this.room?.localParticipant?.tracks?.forEach() { item -> 73 + this.room?.localParticipant?.trackPublications?.forEach() { item ->
73 var participant = this.room!!.localParticipant 74 var participant = this.room!!.localParticipant
74 var publication = item.value 75 var publication = item.value
75 if (publication.track != null) { 76 if (publication.track != null) {
@@ -78,7 +79,7 @@ constructor( @@ -78,7 +79,7 @@ constructor(
78 } 79 }
79 this.room?.remoteParticipants?.forEach() { item -> 80 this.room?.remoteParticipants?.forEach() { item ->
80 var participant = item.value 81 var participant = item.value
81 - participant.tracks.forEach() { item -> 82 + participant.trackPublications.forEach() { item ->
82 var publication = item.value 83 var publication = item.value
83 if (publication.track != null) { 84 if (publication.track != null) {
84 addSubscribedTrack(publication.track!!, publication, participant, room) 85 addSubscribedTrack(publication.track!!, publication, participant, room)
@@ -169,11 +170,11 @@ constructor( @@ -169,11 +170,11 @@ constructor(
169 } 170 }
170 } 171 }
171 172
172 - private fun addRtpSender(sender: RtpSender, participantId: String, trackId: String, kind: String): FrameCryptor { 173 + private fun addRtpSender(sender: RtpSender, participantId: Participant.Identity, trackId: String, kind: String): FrameCryptor {
173 var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpSender( 174 var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpSender(
174 peerConnectionFactory, 175 peerConnectionFactory,
175 sender, 176 sender,
176 - participantId, 177 + participantId.value,
177 algorithm, 178 algorithm,
178 keyProvider.rtcKeyProvider, 179 keyProvider.rtcKeyProvider,
179 ) 180 )
@@ -183,11 +184,11 @@ constructor( @@ -183,11 +184,11 @@ constructor(
183 return frameCryptor 184 return frameCryptor
184 } 185 }
185 186
186 - private fun addRtpReceiver(receiver: RtpReceiver, participantId: String, trackId: String, kind: String): FrameCryptor { 187 + private fun addRtpReceiver(receiver: RtpReceiver, participantId: Participant.Identity, trackId: String, kind: String): FrameCryptor {
187 var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpReceiver( 188 var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpReceiver(
188 peerConnectionFactory, 189 peerConnectionFactory,
189 receiver, 190 receiver,
190 - participantId, 191 + participantId.value,
191 algorithm, 192 algorithm,
192 keyProvider.rtcKeyProvider, 193 keyProvider.rtcKeyProvider,
193 ) 194 )
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@ @@ -17,8 +17,8 @@
17 package io.livekit.android.e2ee 17 package io.livekit.android.e2ee
18 18
19 import io.livekit.android.util.LKLog 19 import io.livekit.android.util.LKLog
20 -import org.webrtc.FrameCryptorFactory  
21 -import org.webrtc.FrameCryptorKeyProvider 20 +import livekit.org.webrtc.FrameCryptorFactory
  21 +import livekit.org.webrtc.FrameCryptorKeyProvider
22 22
23 class KeyInfo 23 class KeyInfo
24 constructor(var participantId: String, var keyIndex: Int, var key: String) { 24 constructor(var participantId: String, var keyIndex: Int, var key: String) {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,12 +16,16 @@ @@ -16,12 +16,16 @@
16 16
17 package io.livekit.android.events 17 package io.livekit.android.events
18 18
  19 +import kotlinx.coroutines.flow.Flow
19 import kotlinx.coroutines.flow.SharedFlow 20 import kotlinx.coroutines.flow.SharedFlow
20 21
21 interface EventListenable<out T> { 22 interface EventListenable<out T> {
22 val events: SharedFlow<T> 23 val events: SharedFlow<T>
23 } 24 }
24 25
  26 +/**
  27 + * @see [Flow.collect]
  28 + */
25 suspend inline fun <T> EventListenable<T>.collect(crossinline action: suspend (value: T) -> Unit) { 29 suspend inline fun <T> EventListenable<T>.collect(crossinline action: suspend (value: T) -> Unit) {
26 events.collect { value -> action(value) } 30 events.collect { value -> action(value) }
27 } 31 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -232,7 +232,7 @@ enum class DisconnectReason { @@ -232,7 +232,7 @@ enum class DisconnectReason {
232 JOIN_FAILURE, 232 JOIN_FAILURE,
233 } 233 }
234 234
235 -fun LivekitModels.DisconnectReason?.convert(): DisconnectReason { 235 +internal fun LivekitModels.DisconnectReason?.convert(): DisconnectReason {
236 return when (this) { 236 return when (this) {
237 LivekitModels.DisconnectReason.CLIENT_INITIATED -> DisconnectReason.CLIENT_INITIATED 237 LivekitModels.DisconnectReason.CLIENT_INITIATED -> DisconnectReason.CLIENT_INITIATED
238 LivekitModels.DisconnectReason.DUPLICATE_IDENTITY -> DisconnectReason.DUPLICATE_IDENTITY 238 LivekitModels.DisconnectReason.DUPLICATE_IDENTITY -> DisconnectReason.DUPLICATE_IDENTITY
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ package io.livekit.android.memory @@ -19,7 +19,7 @@ package io.livekit.android.memory
19 import java.io.Closeable 19 import java.io.Closeable
20 20
21 /** 21 /**
22 - * @hide 22 + * @suppress
23 */ 23 */
24 class CloseableManager : Closeable { 24 class CloseableManager : Closeable {
25 25
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.memory 17 package io.livekit.android.memory
18 18
19 -import org.webrtc.SurfaceTextureHelper 19 +import livekit.org.webrtc.SurfaceTextureHelper
20 import java.io.Closeable 20 import java.io.Closeable
21 21
22 internal class SurfaceTextureHelperCloser(private val surfaceTextureHelper: SurfaceTextureHelper) : Closeable { 22 internal class SurfaceTextureHelperCloser(private val surfaceTextureHelper: SurfaceTextureHelper) : Closeable {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import android.content.Context @@ -20,7 +20,7 @@ import android.content.Context
20 import android.util.AttributeSet 20 import android.util.AttributeSet
21 import android.view.View 21 import android.view.View
22 import io.livekit.android.room.track.video.ViewVisibility 22 import io.livekit.android.room.track.video.ViewVisibility
23 -import org.webrtc.SurfaceViewRenderer 23 +import livekit.org.webrtc.SurfaceViewRenderer
24 24
25 open class SurfaceViewRenderer : SurfaceViewRenderer, ViewVisibility.Notifier { 25 open class SurfaceViewRenderer : SurfaceViewRenderer, ViewVisibility.Notifier {
26 constructor(context: Context) : super(context) 26 constructor(context: Context) : super(context)
@@ -19,8 +19,8 @@ import android.view.SurfaceHolder @@ -19,8 +19,8 @@ import android.view.SurfaceHolder
19 import android.view.TextureView 19 import android.view.TextureView
20 import android.view.View 20 import android.view.View
21 import io.livekit.android.room.track.video.ViewVisibility 21 import io.livekit.android.room.track.video.ViewVisibility
22 -import org.webrtc.*  
23 -import org.webrtc.RendererCommon.* 22 +import livekit.org.webrtc.*
  23 +import livekit.org.webrtc.RendererCommon.*
24 import java.util.concurrent.CountDownLatch 24 import java.util.concurrent.CountDownLatch
25 25
26 /** 26 /**
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import android.content.Context @@ -20,8 +20,8 @@ import android.content.Context
20 import android.hardware.camera2.CameraManager 20 import android.hardware.camera2.CameraManager
21 import android.os.Handler 21 import android.os.Handler
22 import android.os.Looper 22 import android.os.Looper
23 -import org.webrtc.Camera1Enumerator  
24 -import org.webrtc.Camera2Enumerator 23 +import livekit.org.webrtc.Camera1Enumerator
  24 +import livekit.org.webrtc.Camera2Enumerator
25 25
26 object DeviceManager { 26 object DeviceManager {
27 27
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,8 +18,5 @@ package io.livekit.android.room @@ -18,8 +18,5 @@ package io.livekit.android.room
18 18
19 import kotlinx.serialization.Serializable 19 import kotlinx.serialization.Serializable
20 20
21 -/**  
22 - * @suppress  
23 - */  
24 @Serializable 21 @Serializable
25 -data class IceCandidateJSON(val candidate: String, val sdpMLineIndex: Int, val sdpMid: String?) 22 +internal data class IceCandidateJSON(val candidate: String, val sdpMLineIndex: Int, val sdpMid: String?)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -40,9 +40,9 @@ import kotlinx.coroutines.CoroutineDispatcher @@ -40,9 +40,9 @@ import kotlinx.coroutines.CoroutineDispatcher
40 import kotlinx.coroutines.CoroutineScope 40 import kotlinx.coroutines.CoroutineScope
41 import kotlinx.coroutines.SupervisorJob 41 import kotlinx.coroutines.SupervisorJob
42 import kotlinx.coroutines.runBlocking 42 import kotlinx.coroutines.runBlocking
43 -import org.webrtc.*  
44 -import org.webrtc.PeerConnection.RTCConfiguration  
45 -import org.webrtc.PeerConnection.SignalingState 43 +import livekit.org.webrtc.*
  44 +import livekit.org.webrtc.PeerConnection.RTCConfiguration
  45 +import livekit.org.webrtc.PeerConnection.SignalingState
46 import java.util.concurrent.atomic.AtomicBoolean 46 import java.util.concurrent.atomic.AtomicBoolean
47 import javax.inject.Named 47 import javax.inject.Named
48 import kotlin.contracts.ExperimentalContracts 48 import kotlin.contracts.ExperimentalContracts
@@ -459,7 +459,7 @@ internal data class TrackBitrateInfo( @@ -459,7 +459,7 @@ internal data class TrackBitrateInfo(
459 val maxBitrate: Long, 459 val maxBitrate: Long,
460 ) 460 )
461 461
462 -sealed class TrackBitrateInfoKey { 462 +internal sealed class TrackBitrateInfoKey {
463 data class Cid(val value: String) : TrackBitrateInfoKey() 463 data class Cid(val value: String) : TrackBitrateInfoKey()
464 data class Transceiver(val value: RtpTransceiver) : TrackBitrateInfoKey() 464 data class Transceiver(val value: RtpTransceiver) : TrackBitrateInfoKey()
465 } 465 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -19,19 +19,16 @@ package io.livekit.android.room @@ -19,19 +19,16 @@ package io.livekit.android.room
19 import io.livekit.android.util.LKLog 19 import io.livekit.android.util.LKLog
20 import io.livekit.android.webrtc.peerconnection.executeOnRTCThread 20 import io.livekit.android.webrtc.peerconnection.executeOnRTCThread
21 import livekit.LivekitRtc 21 import livekit.LivekitRtc
22 -import org.webrtc.CandidatePairChangeEvent  
23 -import org.webrtc.DataChannel  
24 -import org.webrtc.IceCandidate  
25 -import org.webrtc.MediaStream  
26 -import org.webrtc.PeerConnection  
27 -import org.webrtc.RtpReceiver  
28 -import org.webrtc.RtpTransceiver  
29 -import org.webrtc.SessionDescription  
30 -  
31 -/**  
32 - * @suppress  
33 - */  
34 -class PublisherTransportObserver( 22 +import livekit.org.webrtc.CandidatePairChangeEvent
  23 +import livekit.org.webrtc.DataChannel
  24 +import livekit.org.webrtc.IceCandidate
  25 +import livekit.org.webrtc.MediaStream
  26 +import livekit.org.webrtc.PeerConnection
  27 +import livekit.org.webrtc.RtpReceiver
  28 +import livekit.org.webrtc.RtpTransceiver
  29 +import livekit.org.webrtc.SessionDescription
  30 +
  31 +internal class PublisherTransportObserver(
35 private val engine: RTCEngine, 32 private val engine: RTCEngine,
36 private val client: SignalClient, 33 private val client: SignalClient,
37 ) : PeerConnection.Observer, PeerConnectionTransport.Listener { 34 ) : PeerConnection.Observer, PeerConnectionTransport.Listener {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -44,9 +44,9 @@ import livekit.LivekitModels @@ -44,9 +44,9 @@ import livekit.LivekitModels
44 import livekit.LivekitRtc 44 import livekit.LivekitRtc
45 import livekit.LivekitRtc.JoinResponse 45 import livekit.LivekitRtc.JoinResponse
46 import livekit.LivekitRtc.ReconnectResponse 46 import livekit.LivekitRtc.ReconnectResponse
47 -import org.webrtc.*  
48 -import org.webrtc.PeerConnection.RTCConfiguration  
49 -import org.webrtc.RtpTransceiver.RtpTransceiverInit 47 +import livekit.org.webrtc.*
  48 +import livekit.org.webrtc.PeerConnection.RTCConfiguration
  49 +import livekit.org.webrtc.RtpTransceiver.RtpTransceiverInit
50 import java.net.ConnectException 50 import java.net.ConnectException
51 import java.nio.ByteBuffer 51 import java.nio.ByteBuffer
52 import javax.inject.Inject 52 import javax.inject.Inject
@@ -266,6 +266,7 @@ internal constructor( @@ -266,6 +266,7 @@ internal constructor(
266 cid: String, 266 cid: String,
267 name: String, 267 name: String,
268 kind: LivekitModels.TrackType, 268 kind: LivekitModels.TrackType,
  269 + stream: String?,
269 builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(), 270 builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(),
270 ): LivekitModels.TrackInfo { 271 ): LivekitModels.TrackInfo {
271 if (pendingTrackResolvers[cid] != null) { 272 if (pendingTrackResolvers[cid] != null) {
@@ -274,7 +275,13 @@ internal constructor( @@ -274,7 +275,13 @@ internal constructor(
274 // Suspend until signal client receives message confirming track publication. 275 // Suspend until signal client receives message confirming track publication.
275 return suspendCoroutine { cont -> 276 return suspendCoroutine { cont ->
276 pendingTrackResolvers[cid] = cont 277 pendingTrackResolvers[cid] = cont
277 - client.sendAddTrack(cid, name, kind, builder) 278 + client.sendAddTrack(
  279 + cid = cid,
  280 + name = name,
  281 + type = kind,
  282 + stream = stream,
  283 + builder = builder,
  284 + )
278 } 285 }
279 } 286 }
280 287
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -41,14 +41,19 @@ import io.livekit.android.room.participant.* @@ -41,14 +41,19 @@ import io.livekit.android.room.participant.*
41 import io.livekit.android.room.track.* 41 import io.livekit.android.room.track.*
42 import io.livekit.android.util.FlowObservable 42 import io.livekit.android.util.FlowObservable
43 import io.livekit.android.util.LKLog 43 import io.livekit.android.util.LKLog
  44 +import io.livekit.android.util.flow
44 import io.livekit.android.util.flowDelegate 45 import io.livekit.android.util.flowDelegate
45 import io.livekit.android.util.invoke 46 import io.livekit.android.util.invoke
46 import io.livekit.android.webrtc.getFilteredStats 47 import io.livekit.android.webrtc.getFilteredStats
47 import kotlinx.coroutines.* 48 import kotlinx.coroutines.*
  49 +import kotlinx.coroutines.flow.filterNotNull
  50 +import kotlinx.coroutines.flow.first
  51 +import kotlinx.serialization.Serializable
48 import livekit.LivekitModels 52 import livekit.LivekitModels
49 import livekit.LivekitRtc 53 import livekit.LivekitRtc
50 -import org.webrtc.* 54 +import livekit.org.webrtc.*
51 import javax.inject.Named 55 import javax.inject.Named
  56 +import kotlin.jvm.Throws
52 57
53 class Room 58 class Room
54 @AssistedInject 59 @AssistedInject
@@ -92,15 +97,35 @@ constructor( @@ -92,15 +97,35 @@ constructor(
92 SERVER_LEAVE, 97 SERVER_LEAVE,
93 } 98 }
94 99
  100 + @Serializable
95 @JvmInline 101 @JvmInline
96 value class Sid(val sid: String) 102 value class Sid(val sid: String)
97 103
98 @Deprecated("Use events instead.") 104 @Deprecated("Use events instead.")
99 var listener: RoomListener? = null 105 var listener: RoomListener? = null
100 106
  107 + /**
  108 + * The session id of the room.
  109 + *
  110 + * Note: the sid may not be populated immediately upon [connect],
  111 + * so using the suspend function [getSid] or listening to the flow
  112 + * `room::sid.flow` is highly advised.
  113 + */
101 @FlowObservable 114 @FlowObservable
102 @get:FlowObservable 115 @get:FlowObservable
103 var sid: Sid? by flowDelegate(null) 116 var sid: Sid? by flowDelegate(null)
  117 + private set
  118 +
  119 + /**
  120 + * Gets the sid of the room.
  121 + *
  122 + * If the sid is not yet available, will suspend until received.
  123 + */
  124 + suspend fun getSid(): Sid {
  125 + return this@Room::sid.flow
  126 + .filterNotNull()
  127 + .first()
  128 + }
104 129
105 @FlowObservable 130 @FlowObservable
106 @get:FlowObservable 131 @get:FlowObservable
@@ -193,13 +218,15 @@ constructor( @@ -193,13 +218,15 @@ constructor(
193 internalListener = this@Room 218 internalListener = this@Room
194 } 219 }
195 220
196 - private var mutableRemoteParticipants by flowDelegate(emptyMap<String, RemoteParticipant>()) 221 + private var mutableRemoteParticipants by flowDelegate(emptyMap<Participant.Identity, RemoteParticipant>())
197 222
198 @FlowObservable 223 @FlowObservable
199 @get:FlowObservable 224 @get:FlowObservable
200 - val remoteParticipants: Map<String, RemoteParticipant> 225 + val remoteParticipants: Map<Participant.Identity, RemoteParticipant>
201 get() = mutableRemoteParticipants 226 get() = mutableRemoteParticipants
202 227
  228 + private var sidToIdentity = mutableMapOf<Participant.Sid, Participant.Identity>()
  229 +
203 private var mutableActiveSpeakers by flowDelegate(emptyList<Participant>()) 230 private var mutableActiveSpeakers by flowDelegate(emptyList<Participant>())
204 231
205 @FlowObservable 232 @FlowObservable
@@ -221,6 +248,14 @@ constructor( @@ -221,6 +248,14 @@ constructor(
221 e2eeOptions = e2eeOptions, 248 e2eeOptions = e2eeOptions,
222 ) 249 )
223 250
  251 + /**
  252 + * Connect to a LiveKit Room.
  253 + *
  254 + * @param url
  255 + * @param token
  256 + * @param options
  257 + */
  258 + @Throws(Exception::class)
224 suspend fun connect(url: String, token: String, options: ConnectOptions = ConnectOptions()) { 259 suspend fun connect(url: String, token: String, options: ConnectOptions = ConnectOptions()) {
225 if (this::coroutineScope.isInitialized) { 260 if (this::coroutineScope.isInitialized) {
226 coroutineScope.cancel() 261 coroutineScope.cancel()
@@ -333,7 +368,11 @@ constructor( @@ -333,7 +368,11 @@ constructor(
333 override fun onJoinResponse(response: LivekitRtc.JoinResponse) { 368 override fun onJoinResponse(response: LivekitRtc.JoinResponse) {
334 LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" } 369 LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" }
335 370
  371 + if (response.room.sid != null) {
336 sid = Sid(response.room.sid) 372 sid = Sid(response.room.sid)
  373 + } else {
  374 + sid = null
  375 + }
337 name = response.room.name 376 name = response.room.name
338 metadata = response.room.metadata 377 metadata = response.room.metadata
339 378
@@ -354,16 +393,16 @@ constructor( @@ -354,16 +393,16 @@ constructor(
354 localParticipant.updateFromInfo(response.participant) 393 localParticipant.updateFromInfo(response.participant)
355 394
356 if (response.otherParticipantsList.isNotEmpty()) { 395 if (response.otherParticipantsList.isNotEmpty()) {
357 - response.otherParticipantsList.forEach {  
358 - getOrCreateRemoteParticipant(it.sid, it) 396 + response.otherParticipantsList.forEach { info ->
  397 + getOrCreateRemoteParticipant(Participant.Identity(info.identity), info)
359 } 398 }
360 } 399 }
361 } 400 }
362 401
363 - private fun handleParticipantDisconnect(sid: String) { 402 + private fun handleParticipantDisconnect(identity: Participant.Identity) {
364 val newParticipants = mutableRemoteParticipants.toMutableMap() 403 val newParticipants = mutableRemoteParticipants.toMutableMap()
365 - val removedParticipant = newParticipants.remove(sid) ?: return  
366 - removedParticipant.tracks.values.toList().forEach { publication -> 404 + val removedParticipant = newParticipants.remove(identity) ?: return
  405 + removedParticipant.trackPublications.values.toList().forEach { publication ->
367 removedParticipant.unpublishTrack(publication.sid, true) 406 removedParticipant.unpublishTrack(publication.sid, true)
368 } 407 }
369 408
@@ -372,29 +411,41 @@ constructor( @@ -372,29 +411,41 @@ constructor(
372 eventBus.postEvent(RoomEvent.ParticipantDisconnected(this, removedParticipant), coroutineScope) 411 eventBus.postEvent(RoomEvent.ParticipantDisconnected(this, removedParticipant), coroutineScope)
373 } 412 }
374 413
375 - fun getParticipant(sid: String): Participant? { 414 + fun getParticipantBySid(sid: String): Participant? {
  415 + return getParticipantBySid(Participant.Sid(sid))
  416 + }
  417 +
  418 + fun getParticipantBySid(sid: Participant.Sid): Participant? {
376 if (sid == localParticipant.sid) { 419 if (sid == localParticipant.sid) {
377 return localParticipant 420 return localParticipant
378 } else { 421 } else {
379 - return remoteParticipants[sid] 422 + return remoteParticipants[sidToIdentity[sid]]
  423 + }
  424 + }
  425 +
  426 + fun getParticipantByIdentity(identity: String): Participant? {
  427 + return getParticipantByIdentity(Participant.Identity(identity))
  428 + }
  429 +
  430 + fun getParticipantByIdentity(identity: Participant.Identity): Participant? {
  431 + if (identity == localParticipant.identity) {
  432 + return localParticipant
  433 + } else {
  434 + return remoteParticipants[identity]
380 } 435 }
381 } 436 }
382 437
383 @Synchronized 438 @Synchronized
384 private fun getOrCreateRemoteParticipant( 439 private fun getOrCreateRemoteParticipant(
385 - sid: String,  
386 - info: LivekitModels.ParticipantInfo? = null, 440 + identity: Participant.Identity,
  441 + info: LivekitModels.ParticipantInfo,
387 ): RemoteParticipant { 442 ): RemoteParticipant {
388 - var participant = remoteParticipants[sid] 443 + var participant = remoteParticipants[identity]
389 if (participant != null) { 444 if (participant != null) {
390 return participant 445 return participant
391 } 446 }
392 447
393 - participant = if (info != null) {  
394 - RemoteParticipant(info, engine.client, ioDispatcher, defaultDispatcher)  
395 - } else {  
396 - RemoteParticipant(sid, null, engine.client, ioDispatcher, defaultDispatcher)  
397 - } 448 + participant = RemoteParticipant(info, engine.client, ioDispatcher, defaultDispatcher)
398 participant.internalListener = this 449 participant.internalListener = this
399 450
400 coroutineScope.launch { 451 coroutineScope.launch {
@@ -466,26 +517,25 @@ constructor( @@ -466,26 +517,25 @@ constructor(
466 } 517 }
467 } 518 }
468 519
469 - if (info != null) {  
470 participant.updateFromInfo(info) 520 participant.updateFromInfo(info)
471 - }  
472 521
473 val newRemoteParticipants = mutableRemoteParticipants.toMutableMap() 522 val newRemoteParticipants = mutableRemoteParticipants.toMutableMap()
474 - newRemoteParticipants[sid] = participant 523 + newRemoteParticipants[identity] = participant
475 mutableRemoteParticipants = newRemoteParticipants 524 mutableRemoteParticipants = newRemoteParticipants
  525 + sidToIdentity[participant.sid] = identity
476 526
477 return participant 527 return participant
478 } 528 }
479 529
480 private fun handleActiveSpeakersUpdate(speakerInfos: List<LivekitModels.SpeakerInfo>) { 530 private fun handleActiveSpeakersUpdate(speakerInfos: List<LivekitModels.SpeakerInfo>) {
481 val speakers = mutableListOf<Participant>() 531 val speakers = mutableListOf<Participant>()
482 - val seenSids = mutableSetOf<String>() 532 + val seenSids = mutableSetOf<Participant.Sid>()
483 val localParticipant = localParticipant 533 val localParticipant = localParticipant
484 speakerInfos.forEach { speakerInfo -> 534 speakerInfos.forEach { speakerInfo ->
485 - val speakerSid = speakerInfo.sid!! 535 + val speakerSid = Participant.Sid(speakerInfo.sid)
486 seenSids.add(speakerSid) 536 seenSids.add(speakerSid)
487 537
488 - val participant = getParticipant(speakerSid) ?: return@forEach 538 + val participant = getParticipantBySid(speakerSid) ?: return@forEach
489 participant.audioLevel = speakerInfo.level 539 participant.audioLevel = speakerInfo.level
490 participant.isSpeaking = true 540 participant.isSpeaking = true
491 speakers.add(participant) 541 speakers.add(participant)
@@ -508,21 +558,22 @@ constructor( @@ -508,21 +558,22 @@ constructor(
508 } 558 }
509 559
510 private fun handleSpeakersChanged(speakerInfos: List<LivekitModels.SpeakerInfo>) { 560 private fun handleSpeakersChanged(speakerInfos: List<LivekitModels.SpeakerInfo>) {
511 - val updatedSpeakers = mutableMapOf<String, Participant>()  
512 - activeSpeakers.forEach {  
513 - updatedSpeakers[it.sid] = it 561 + val updatedSpeakers = mutableMapOf<Participant.Sid, Participant>()
  562 + activeSpeakers.forEach { participant ->
  563 + updatedSpeakers[participant.sid] = participant
514 } 564 }
515 565
516 speakerInfos.forEach { speaker -> 566 speakerInfos.forEach { speaker ->
517 - val participant = getParticipant(speaker.sid) ?: return@forEach 567 + val speakerSid = Participant.Sid(speaker.sid)
  568 + val participant = getParticipantBySid(speakerSid) ?: return@forEach
518 569
519 participant.audioLevel = speaker.level 570 participant.audioLevel = speaker.level
520 participant.isSpeaking = speaker.active 571 participant.isSpeaking = speaker.active
521 572
522 if (speaker.active) { 573 if (speaker.active) {
523 - updatedSpeakers[speaker.sid] = participant 574 + updatedSpeakers[speakerSid] = participant
524 } else { 575 } else {
525 - updatedSpeakers.remove(speaker.sid) 576 + updatedSpeakers.remove(speakerSid)
526 } 577 }
527 } 578 }
528 579
@@ -555,6 +606,7 @@ constructor( @@ -555,6 +606,7 @@ constructor(
555 metadata = null 606 metadata = null
556 name = null 607 name = null
557 isRecording = false 608 isRecording = false
  609 + sidToIdentity.clear()
558 } 610 }
559 611
560 private fun handleDisconnect(reason: DisconnectReason) { 612 private fun handleDisconnect(reason: DisconnectReason) {
@@ -590,8 +642,8 @@ constructor( @@ -590,8 +642,8 @@ constructor(
590 val participantTracksList = mutableListOf<LivekitModels.ParticipantTracks>() 642 val participantTracksList = mutableListOf<LivekitModels.ParticipantTracks>()
591 for (participant in remoteParticipants.values) { 643 for (participant in remoteParticipants.values) {
592 val builder = LivekitModels.ParticipantTracks.newBuilder() 644 val builder = LivekitModels.ParticipantTracks.newBuilder()
593 - builder.participantSid = participant.sid  
594 - for (trackPub in participant.tracks.values) { 645 + builder.participantSid = participant.sid.value
  646 + for (trackPub in participant.trackPublications.values) {
595 val remoteTrackPub = (trackPub as? RemoteTrackPublication) ?: continue 647 val remoteTrackPub = (trackPub as? RemoteTrackPublication) ?: continue
596 if (remoteTrackPub.subscribed != sendUnsub) { 648 if (remoteTrackPub.subscribed != sendUnsub) {
597 builder.addTrackSids(remoteTrackPub.sid) 649 builder.addTrackSids(remoteTrackPub.sid)
@@ -712,11 +764,19 @@ constructor( @@ -712,11 +764,19 @@ constructor(
712 return 764 return
713 } 765 }
714 766
715 - var (participantSid, trackSid) = unpackStreamId(streams.first().id)  
716 - if (trackSid == null) {  
717 - trackSid = track.id() 767 + var (participantSid, streamId) = unpackStreamId(streams.first().id)
  768 + var trackSid = track.id()
  769 +
  770 + if (streamId != null && streamId.startsWith("TR")) {
  771 + trackSid = streamId
  772 + }
  773 + val participant = getParticipantBySid(participantSid) as? RemoteParticipant
  774 +
  775 + if (participant == null) {
  776 + LKLog.e { "Tried to add a track for a participant that is not present. sid: $participantSid" }
  777 + return
718 } 778 }
719 - val participant = getOrCreateRemoteParticipant(participantSid) 779 +
720 val statsGetter = engine.createStatsGetter(receiver) 780 val statsGetter = engine.createStatsGetter(receiver)
721 participant.addSubscribedMediaTrack( 781 participant.addSubscribedMediaTrack(
722 track, 782 track,
@@ -732,24 +792,37 @@ constructor( @@ -732,24 +792,37 @@ constructor(
732 */ 792 */
733 override fun onUpdateParticipants(updates: List<LivekitModels.ParticipantInfo>) { 793 override fun onUpdateParticipants(updates: List<LivekitModels.ParticipantInfo>) {
734 for (info in updates) { 794 for (info in updates) {
735 - val participantSid = info.sid 795 + val participantSid = Participant.Sid(info.sid)
  796 + // LiveKit server doesn't send identity info prior to version 1.5.2 in disconnect updates
  797 + // so we try to map an empty identity to an already known sID manually
  798 +
  799 + @Suppress("NAME_SHADOWING") var info = info
  800 + if (info.identity.isNullOrBlank()) {
  801 + info = with(info.toBuilder()) {
  802 + identity = sidToIdentity[participantSid]?.value ?: ""
  803 + build()
  804 + }
  805 + }
  806 +
  807 + val participantIdentity = Participant.Identity(info.identity)
736 808
737 - if (localParticipant.sid == participantSid) { 809 + if (localParticipant.identity == participantIdentity) {
738 localParticipant.updateFromInfo(info) 810 localParticipant.updateFromInfo(info)
739 continue 811 continue
740 } 812 }
741 813
742 - val isNewParticipant = !remoteParticipants.contains(participantSid) 814 + val isNewParticipant = !remoteParticipants.contains(participantIdentity)
743 815
744 if (info.state == LivekitModels.ParticipantInfo.State.DISCONNECTED) { 816 if (info.state == LivekitModels.ParticipantInfo.State.DISCONNECTED) {
745 - handleParticipantDisconnect(participantSid) 817 + handleParticipantDisconnect(participantIdentity)
746 } else { 818 } else {
747 - val participant = getOrCreateRemoteParticipant(participantSid, info) 819 + val participant = getOrCreateRemoteParticipant(participantIdentity, info)
748 if (isNewParticipant) { 820 if (isNewParticipant) {
749 listener?.onParticipantConnected(this, participant) 821 listener?.onParticipantConnected(this, participant)
750 eventBus.postEvent(RoomEvent.ParticipantConnected(this, participant), coroutineScope) 822 eventBus.postEvent(RoomEvent.ParticipantConnected(this, participant), coroutineScope)
751 } else { 823 } else {
752 participant.updateFromInfo(info) 824 participant.updateFromInfo(info)
  825 + sidToIdentity[participantSid] = participantIdentity
753 } 826 }
754 } 827 }
755 } 828 }
@@ -773,6 +846,9 @@ constructor( @@ -773,6 +846,9 @@ constructor(
773 * @suppress 846 * @suppress
774 */ 847 */
775 override fun onRoomUpdate(update: LivekitModels.Room) { 848 override fun onRoomUpdate(update: LivekitModels.Room) {
  849 + if (update.sid != null) {
  850 + sid = Sid(update.sid)
  851 + }
776 val oldMetadata = metadata 852 val oldMetadata = metadata
777 metadata = update.metadata 853 metadata = update.metadata
778 854
@@ -794,7 +870,7 @@ constructor( @@ -794,7 +870,7 @@ constructor(
794 override fun onConnectionQuality(updates: List<LivekitRtc.ConnectionQualityInfo>) { 870 override fun onConnectionQuality(updates: List<LivekitRtc.ConnectionQualityInfo>) {
795 updates.forEach { info -> 871 updates.forEach { info ->
796 val quality = ConnectionQuality.fromProto(info.quality) 872 val quality = ConnectionQuality.fromProto(info.quality)
797 - val participant = getParticipant(info.participantSid) ?: return 873 + val participant = getParticipantBySid(info.participantSid) ?: return
798 participant.connectionQuality = quality 874 participant.connectionQuality = quality
799 listener?.onConnectionQualityChanged(participant, quality) 875 listener?.onConnectionQualityChanged(participant, quality)
800 eventBus.postEvent(RoomEvent.ConnectionQualityChanged(this, participant, quality), coroutineScope) 876 eventBus.postEvent(RoomEvent.ConnectionQualityChanged(this, participant, quality), coroutineScope)
@@ -812,7 +888,7 @@ constructor( @@ -812,7 +888,7 @@ constructor(
812 * @suppress 888 * @suppress
813 */ 889 */
814 override fun onUserPacket(packet: LivekitModels.UserPacket, kind: LivekitModels.DataPacket.Kind) { 890 override fun onUserPacket(packet: LivekitModels.UserPacket, kind: LivekitModels.DataPacket.Kind) {
815 - val participant = remoteParticipants[packet.participantSid] 891 + val participant = getParticipantBySid(packet.participantSid) as? RemoteParticipant
816 val data = packet.payload.toByteArray() 892 val data = packet.payload.toByteArray()
817 val topic = if (packet.hasTopic()) { 893 val topic = if (packet.hasTopic()) {
818 packet.topic 894 packet.topic
@@ -830,8 +906,8 @@ constructor( @@ -830,8 +906,8 @@ constructor(
830 */ 906 */
831 override fun onStreamStateUpdate(streamStates: List<LivekitRtc.StreamStateInfo>) { 907 override fun onStreamStateUpdate(streamStates: List<LivekitRtc.StreamStateInfo>) {
832 for (streamState in streamStates) { 908 for (streamState in streamStates) {
833 - val participant = getParticipant(streamState.participantSid) ?: continue  
834 - val track = participant.tracks[streamState.trackSid] ?: continue 909 + val participant = getParticipantBySid(streamState.participantSid) ?: continue
  910 + val track = participant.trackPublications[streamState.trackSid] ?: continue
835 911
836 track.track?.streamState = Track.StreamState.fromProto(streamState.state) 912 track.track?.streamState = Track.StreamState.fromProto(streamState.state)
837 } 913 }
@@ -848,7 +924,7 @@ constructor( @@ -848,7 +924,7 @@ constructor(
848 * @suppress 924 * @suppress
849 */ 925 */
850 override fun onSubscriptionPermissionUpdate(subscriptionPermissionUpdate: LivekitRtc.SubscriptionPermissionUpdate) { 926 override fun onSubscriptionPermissionUpdate(subscriptionPermissionUpdate: LivekitRtc.SubscriptionPermissionUpdate) {
851 - val participant = getParticipant(subscriptionPermissionUpdate.participantSid) as? RemoteParticipant ?: return 927 + val participant = getParticipantBySid(subscriptionPermissionUpdate.participantSid) as? RemoteParticipant ?: return
852 participant.onSubscriptionPermissionUpdate(subscriptionPermissionUpdate) 928 participant.onSubscriptionPermissionUpdate(subscriptionPermissionUpdate)
853 } 929 }
854 930
@@ -885,7 +961,7 @@ constructor( @@ -885,7 +961,7 @@ constructor(
885 override fun onFullReconnecting() { 961 override fun onFullReconnecting() {
886 localParticipant.prepareForFullReconnect() 962 localParticipant.prepareForFullReconnect()
887 remoteParticipants.keys.toMutableSet() // copy keys to avoid concurrent modifications. 963 remoteParticipants.keys.toMutableSet() // copy keys to avoid concurrent modifications.
888 - .forEach { sid -> handleParticipantDisconnect(sid) } 964 + .forEach { identity -> handleParticipantDisconnect(identity) }
889 } 965 }
890 966
891 /** 967 /**
@@ -897,7 +973,7 @@ constructor( @@ -897,7 +973,7 @@ constructor(
897 } else { 973 } else {
898 val remoteParticipants = remoteParticipants.values.toList() 974 val remoteParticipants = remoteParticipants.values.toList()
899 for (participant in remoteParticipants) { 975 for (participant in remoteParticipants) {
900 - val pubs = participant.tracks.values.toList() 976 + val pubs = participant.trackPublications.values.toList()
901 for (pub in pubs) { 977 for (pub in pubs) {
902 val remotePub = pub as? RemoteTrackPublication ?: continue 978 val remotePub = pub as? RemoteTrackPublication ?: continue
903 if (remotePub.subscribed) { 979 if (remotePub.subscribed) {
@@ -1091,8 +1167,6 @@ interface RoomListener { @@ -1091,8 +1167,6 @@ interface RoomListener {
1091 * Could not connect to the room 1167 * Could not connect to the room
1092 */ 1168 */
1093 fun onFailedToConnect(room: Room, error: Throwable) {} 1169 fun onFailedToConnect(room: Room, error: Throwable) {}
1094 -// fun onReconnecting(room: Room, error: Exception) {}  
1095 -// fun onReconnect(room: Room) {}  
1096 1170
1097 /** 1171 /**
1098 * Active speakers changed. List of speakers are ordered by their audio level. loudest 1172 * Active speakers changed. List of speakers are ordered by their audio level. loudest
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -37,12 +37,12 @@ import livekit.LivekitModels @@ -37,12 +37,12 @@ import livekit.LivekitModels
37 import livekit.LivekitRtc 37 import livekit.LivekitRtc
38 import livekit.LivekitRtc.JoinResponse 38 import livekit.LivekitRtc.JoinResponse
39 import livekit.LivekitRtc.ReconnectResponse 39 import livekit.LivekitRtc.ReconnectResponse
  40 +import livekit.org.webrtc.IceCandidate
  41 +import livekit.org.webrtc.PeerConnection
  42 +import livekit.org.webrtc.SessionDescription
40 import okhttp3.* 43 import okhttp3.*
41 import okio.ByteString 44 import okio.ByteString
42 import okio.ByteString.Companion.toByteString 45 import okio.ByteString.Companion.toByteString
43 -import org.webrtc.IceCandidate  
44 -import org.webrtc.PeerConnection  
45 -import org.webrtc.SessionDescription  
46 import java.util.* 46 import java.util.*
47 import javax.inject.Inject 47 import javax.inject.Inject
48 import javax.inject.Named 48 import javax.inject.Named
@@ -116,7 +116,7 @@ constructor( @@ -116,7 +116,7 @@ constructor(
116 /** 116 /**
117 * @throws Exception if fails to connect. 117 * @throws Exception if fails to connect.
118 */ 118 */
119 - suspend fun reconnect(url: String, token: String, participantSid: String?): Either<ReconnectResponse, Unit> { 119 + internal suspend fun reconnect(url: String, token: String, participantSid: String?): Either<ReconnectResponse, Unit> {
120 val reconnectResponse = connect( 120 val reconnectResponse = connect(
121 url, 121 url,
122 token, 122 token,
@@ -385,14 +385,21 @@ constructor( @@ -385,14 +385,21 @@ constructor(
385 cid: String, 385 cid: String,
386 name: String, 386 name: String,
387 type: LivekitModels.TrackType, 387 type: LivekitModels.TrackType,
  388 + stream: String?,
388 builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(), 389 builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(),
389 ) { 390 ) {
390 val encryptionType = lastRoomOptions?.e2eeOptions?.encryptionType ?: LivekitModels.Encryption.Type.NONE 391 val encryptionType = lastRoomOptions?.e2eeOptions?.encryptionType ?: LivekitModels.Encryption.Type.NONE
391 - val addTrackRequest = builder  
392 - .setCid(cid)  
393 - .setName(name)  
394 - .setType(type)  
395 - .setEncryption(encryptionType) 392 + val addTrackRequest = builder.apply {
  393 + setCid(cid)
  394 + setName(name)
  395 + setType(type)
  396 + if (stream != null) {
  397 + setStream(stream)
  398 + } else {
  399 + clearStream()
  400 + }
  401 + encryption = encryptionType
  402 + }
396 val request = LivekitRtc.SignalRequest.newBuilder() 403 val request = LivekitRtc.SignalRequest.newBuilder()
397 .setAddTrack(addTrackRequest) 404 .setAddTrack(addTrackRequest)
398 .build() 405 .build()
@@ -834,4 +841,7 @@ enum class ProtocolVersion(val value: Int) { @@ -834,4 +841,7 @@ enum class ProtocolVersion(val value: Int) {
834 v7(7), 841 v7(7),
835 v8(8), 842 v8(8),
836 v9(9), 843 v9(9),
  844 + v10(10),
  845 + v11(11),
  846 + v12(12),
837 } 847 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -19,14 +19,14 @@ package io.livekit.android.room @@ -19,14 +19,14 @@ package io.livekit.android.room
19 import io.livekit.android.util.LKLog 19 import io.livekit.android.util.LKLog
20 import io.livekit.android.webrtc.peerconnection.executeOnRTCThread 20 import io.livekit.android.webrtc.peerconnection.executeOnRTCThread
21 import livekit.LivekitRtc 21 import livekit.LivekitRtc
22 -import org.webrtc.CandidatePairChangeEvent  
23 -import org.webrtc.DataChannel  
24 -import org.webrtc.IceCandidate  
25 -import org.webrtc.MediaStream  
26 -import org.webrtc.MediaStreamTrack  
27 -import org.webrtc.PeerConnection  
28 -import org.webrtc.RtpReceiver  
29 -import org.webrtc.RtpTransceiver 22 +import livekit.org.webrtc.CandidatePairChangeEvent
  23 +import livekit.org.webrtc.DataChannel
  24 +import livekit.org.webrtc.IceCandidate
  25 +import livekit.org.webrtc.MediaStream
  26 +import livekit.org.webrtc.MediaStreamTrack
  27 +import livekit.org.webrtc.PeerConnection
  28 +import livekit.org.webrtc.RtpReceiver
  29 +import livekit.org.webrtc.RtpTransceiver
30 30
31 /** 31 /**
32 * @suppress 32 * @suppress
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -41,8 +41,8 @@ import livekit.LivekitModels @@ -41,8 +41,8 @@ import livekit.LivekitModels
41 import livekit.LivekitRtc 41 import livekit.LivekitRtc
42 import livekit.LivekitRtc.AddTrackRequest 42 import livekit.LivekitRtc.AddTrackRequest
43 import livekit.LivekitRtc.SimulcastCodec 43 import livekit.LivekitRtc.SimulcastCodec
44 -import org.webrtc.*  
45 -import org.webrtc.RtpTransceiver.RtpTransceiverInit 44 +import livekit.org.webrtc.*
  45 +import livekit.org.webrtc.RtpTransceiver.RtpTransceiverInit
46 import javax.inject.Named 46 import javax.inject.Named
47 import kotlin.math.max 47 import kotlin.math.max
48 48
@@ -62,16 +62,16 @@ internal constructor( @@ -62,16 +62,16 @@ internal constructor(
62 coroutineDispatcher: CoroutineDispatcher, 62 coroutineDispatcher: CoroutineDispatcher,
63 @Named(InjectionNames.SENDER) 63 @Named(InjectionNames.SENDER)
64 private val capabilitiesGetter: CapabilitiesGetter, 64 private val capabilitiesGetter: CapabilitiesGetter,
65 -) : Participant("", null, coroutineDispatcher) { 65 +) : Participant(Sid(""), null, coroutineDispatcher) {
66 66
67 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults 67 var audioTrackCaptureDefaults: LocalAudioTrackOptions by defaultsManager::audioTrackCaptureDefaults
68 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults 68 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults
69 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults 69 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults
70 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults 70 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults
71 71
72 - var republishes: List<LocalTrackPublication>? = null 72 + private var republishes: List<LocalTrackPublication>? = null
73 private val localTrackPublications 73 private val localTrackPublications
74 - get() = tracks.values 74 + get() = trackPublications.values
75 .mapNotNull { it as? LocalTrackPublication } 75 .mapNotNull { it as? LocalTrackPublication }
76 .toList() 76 .toList()
77 77
@@ -259,7 +259,7 @@ internal constructor( @@ -259,7 +259,7 @@ internal constructor(
259 requestConfig = { 259 requestConfig = {
260 disableDtx = !options.dtx 260 disableDtx = !options.dtx
261 disableRed = !options.red 261 disableRed = !options.red
262 - source = LivekitModels.TrackSource.MICROPHONE 262 + source = options.source?.toProto() ?: LivekitModels.TrackSource.MICROPHONE
263 }, 263 },
264 encodings = encodings, 264 encodings = encodings,
265 publishListener = publishListener, 265 publishListener = publishListener,
@@ -295,7 +295,7 @@ internal constructor( @@ -295,7 +295,7 @@ internal constructor(
295 requestConfig = { 295 requestConfig = {
296 width = track.dimensions.width 296 width = track.dimensions.width
297 height = track.dimensions.height 297 height = track.dimensions.height
298 - source = if (track.options.isScreencast) { 298 + source = options.source?.toProto() ?: if (track.options.isScreencast) {
299 LivekitModels.TrackSource.SCREEN_SHARE 299 LivekitModels.TrackSource.SCREEN_SHARE
300 } else { 300 } else {
301 LivekitModels.TrackSource.CAMERA 301 LivekitModels.TrackSource.CAMERA
@@ -350,8 +350,9 @@ internal constructor( @@ -350,8 +350,9 @@ internal constructor(
350 } 350 }
351 val trackInfo = engine.addTrack( 351 val trackInfo = engine.addTrack(
352 cid = cid, 352 cid = cid,
353 - name = track.name, 353 + name = options.name ?: track.name,
354 kind = track.kind.toProto(), 354 kind = track.kind.toProto(),
  355 + stream = options.stream,
355 builder = builder, 356 builder = builder,
356 ) 357 )
357 358
@@ -374,7 +375,7 @@ internal constructor( @@ -374,7 +375,7 @@ internal constructor(
374 375
375 val transInit = RtpTransceiverInit( 376 val transInit = RtpTransceiverInit(
376 RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, 377 RtpTransceiver.RtpTransceiverDirection.SEND_ONLY,
377 - listOf(this.sid), 378 + listOf(this.sid.value),
378 encodings, 379 encodings,
379 ) 380 )
380 val transceiver = engine.createSenderTransceiver(track.rtcTrack, transInit) 381 val transceiver = engine.createSenderTransceiver(track.rtcTrack, transInit)
@@ -552,7 +553,7 @@ internal constructor( @@ -552,7 +553,7 @@ internal constructor(
552 } 553 }
553 554
554 val sid = publication.sid 555 val sid = publication.sid
555 - tracks = tracks.toMutableMap().apply { remove(sid) } 556 + trackPublications = trackPublications.toMutableMap().apply { remove(sid) }
556 557
557 if (engine.connectionState == ConnectionState.CONNECTED) { 558 if (engine.connectionState == ConnectionState.CONNECTED) {
558 engine.removeTrack(track.rtcTrack) 559 engine.removeTrack(track.rtcTrack)
@@ -570,15 +571,15 @@ internal constructor( @@ -570,15 +571,15 @@ internal constructor(
570 * 571 *
571 * @param data payload to send 572 * @param data payload to send
572 * @param reliability for delivery guarantee, use RELIABLE. for fastest delivery without guarantee, use LOSSY 573 * @param reliability for delivery guarantee, use RELIABLE. for fastest delivery without guarantee, use LOSSY
573 - * @param destination list of participant SIDs to deliver the payload, null to deliver to everyone  
574 * @param topic the topic under which the message was published 574 * @param topic the topic under which the message was published
  575 + * @param identities list of participant identities to deliver the payload, null to deliver to everyone
575 */ 576 */
576 @Suppress("unused") 577 @Suppress("unused")
577 suspend fun publishData( 578 suspend fun publishData(
578 data: ByteArray, 579 data: ByteArray,
579 reliability: DataPublishReliability = DataPublishReliability.RELIABLE, 580 reliability: DataPublishReliability = DataPublishReliability.RELIABLE,
580 - destination: List<String>? = null,  
581 topic: String? = null, 581 topic: String? = null,
  582 + identities: List<Identity>? = null,
582 ) { 583 ) {
583 if (data.size > RTCEngine.MAX_DATA_PACKET_SIZE) { 584 if (data.size > RTCEngine.MAX_DATA_PACKET_SIZE) {
584 throw IllegalArgumentException("cannot publish data larger than " + RTCEngine.MAX_DATA_PACKET_SIZE) 585 throw IllegalArgumentException("cannot publish data larger than " + RTCEngine.MAX_DATA_PACKET_SIZE)
@@ -590,12 +591,12 @@ internal constructor( @@ -590,12 +591,12 @@ internal constructor(
590 } 591 }
591 val packetBuilder = LivekitModels.UserPacket.newBuilder().apply { 592 val packetBuilder = LivekitModels.UserPacket.newBuilder().apply {
592 payload = ByteString.copyFrom(data) 593 payload = ByteString.copyFrom(data)
593 - participantSid = sid 594 + participantSid = sid.value
594 if (topic != null) { 595 if (topic != null) {
595 setTopic(topic) 596 setTopic(topic)
596 } 597 }
597 - if (destination != null) {  
598 - addAllDestinationSids(destination) 598 + if (identities != null) {
  599 + addAllDestinationIdentities(identities.map { it.value })
599 } 600 }
600 } 601 }
601 val dataPacket = LivekitModels.DataPacket.newBuilder() 602 val dataPacket = LivekitModels.DataPacket.newBuilder()
@@ -611,10 +612,10 @@ internal constructor( @@ -611,10 +612,10 @@ internal constructor(
611 612
612 // detect tracks that have mute status mismatched on server 613 // detect tracks that have mute status mismatched on server
613 for (ti in info.tracksList) { 614 for (ti in info.tracksList) {
614 - val publication = this.tracks[ti.sid] as? LocalTrackPublication ?: continue 615 + val publication = this.trackPublications[ti.sid] as? LocalTrackPublication ?: continue
615 val localMuted = publication.muted 616 val localMuted = publication.muted
616 if (ti.muted != localMuted) { 617 if (ti.muted != localMuted) {
617 - engine.updateMuteStatus(sid, localMuted) 618 + engine.updateMuteStatus(sid.value, localMuted)
618 } 619 }
619 } 620 }
620 } 621 }
@@ -640,7 +641,7 @@ internal constructor( @@ -640,7 +641,7 @@ internal constructor(
640 } 641 }
641 642
642 internal fun onRemoteMuteChanged(trackSid: String, muted: Boolean) { 643 internal fun onRemoteMuteChanged(trackSid: String, muted: Boolean) {
643 - val pub = tracks[trackSid] 644 + val pub = trackPublications[trackSid]
644 pub?.muted = muted 645 pub?.muted = muted
645 } 646 }
646 647
@@ -652,7 +653,7 @@ internal constructor( @@ -652,7 +653,7 @@ internal constructor(
652 val trackSid = subscribedQualityUpdate.trackSid 653 val trackSid = subscribedQualityUpdate.trackSid
653 val subscribedCodecs = subscribedQualityUpdate.subscribedCodecsList 654 val subscribedCodecs = subscribedQualityUpdate.subscribedCodecsList
654 val qualities = subscribedQualityUpdate.subscribedQualitiesList 655 val qualities = subscribedQualityUpdate.subscribedQualitiesList
655 - val pub = tracks[trackSid] as? LocalTrackPublication ?: return 656 + val pub = trackPublications[trackSid] as? LocalTrackPublication ?: return
656 val track = pub.track as? LocalVideoTrack ?: return 657 val track = pub.track as? LocalVideoTrack ?: return
657 val options = pub.options as? VideoTrackPublishOptions ?: return 658 val options = pub.options as? VideoTrackPublishOptions ?: return
658 659
@@ -671,7 +672,7 @@ internal constructor( @@ -671,7 +672,7 @@ internal constructor(
671 } 672 }
672 673
673 private fun publishAdditionalCodecForTrack(track: LocalVideoTrack, codec: VideoCodec, options: VideoTrackPublishOptions) { 674 private fun publishAdditionalCodecForTrack(track: LocalVideoTrack, codec: VideoCodec, options: VideoTrackPublishOptions) {
674 - val existingPublication = tracks[track.sid] ?: run { 675 + val existingPublication = trackPublications[track.sid] ?: run {
675 LKLog.w { "attempting to publish additional codec for non-published track?!" } 676 LKLog.w { "attempting to publish additional codec for non-published track?!" }
676 return 677 return
677 } 678 }
@@ -685,7 +686,7 @@ internal constructor( @@ -685,7 +686,7 @@ internal constructor(
685 686
686 val transceiverInit = RtpTransceiverInit( 687 val transceiverInit = RtpTransceiverInit(
687 RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, 688 RtpTransceiver.RtpTransceiverDirection.SEND_ONLY,
688 - listOf(this.sid), 689 + listOf(this.sid.value),
689 newEncodings, 690 newEncodings,
690 ) 691 )
691 692
@@ -725,6 +726,7 @@ internal constructor( @@ -725,6 +726,7 @@ internal constructor(
725 cid = simulcastTrack.rtcTrack.id(), 726 cid = simulcastTrack.rtcTrack.id(),
726 name = existingPublication.name, 727 name = existingPublication.name,
727 kind = existingPublication.kind.toProto(), 728 kind = existingPublication.kind.toProto(),
  729 + stream = options.stream,
728 builder = trackRequest, 730 builder = trackRequest,
729 ) 731 )
730 732
@@ -735,7 +737,7 @@ internal constructor( @@ -735,7 +737,7 @@ internal constructor(
735 } 737 }
736 738
737 internal fun handleLocalTrackUnpublished(unpublishedResponse: LivekitRtc.TrackUnpublishedResponse) { 739 internal fun handleLocalTrackUnpublished(unpublishedResponse: LivekitRtc.TrackUnpublishedResponse) {
738 - val pub = tracks[unpublishedResponse.trackSid] 740 + val pub = trackPublications[unpublishedResponse.trackSid]
739 val track = pub?.track 741 val track = pub?.track
740 if (track == null) { 742 if (track == null) {
741 LKLog.w { "Received unpublished track response for unknown or non-published track: ${unpublishedResponse.trackSid}" } 743 LKLog.w { "Received unpublished track response for unknown or non-published track: ${unpublishedResponse.trackSid}" }
@@ -753,7 +755,7 @@ internal constructor( @@ -753,7 +755,7 @@ internal constructor(
753 republishes = pubs 755 republishes = pubs
754 } 756 }
755 757
756 - tracks = tracks.toMutableMap().apply { clear() } 758 + trackPublications = trackPublications.toMutableMap().apply { clear() }
757 759
758 for (publication in pubs) { 760 for (publication in pubs) {
759 internalListener?.onTrackUnpublished(publication, this) 761 internalListener?.onTrackUnpublished(publication, this)
@@ -780,7 +782,7 @@ internal constructor( @@ -780,7 +782,7 @@ internal constructor(
780 } 782 }
781 783
782 fun cleanup() { 784 fun cleanup() {
783 - for (pub in tracks.values) { 785 + for (pub in trackPublications.values) {
784 val track = pub.track 786 val track = pub.track
785 787
786 if (track != null) { 788 if (track != null) {
@@ -810,7 +812,7 @@ internal constructor( @@ -810,7 +812,7 @@ internal constructor(
810 } 812 }
811 813
812 internal fun LocalParticipant.publishTracksInfo(): List<LivekitRtc.TrackPublishedResponse> { 814 internal fun LocalParticipant.publishTracksInfo(): List<LivekitRtc.TrackPublishedResponse> {
813 - return tracks.values.mapNotNull { trackPub -> 815 + return trackPublications.values.mapNotNull { trackPub ->
814 val track = trackPub.track ?: return@mapNotNull null 816 val track = trackPub.track ?: return@mapNotNull null
815 817
816 LivekitRtc.TrackPublishedResponse.newBuilder() 818 LivekitRtc.TrackPublishedResponse.newBuilder()
@@ -821,7 +823,23 @@ internal fun LocalParticipant.publishTracksInfo(): List<LivekitRtc.TrackPublishe @@ -821,7 +823,23 @@ internal fun LocalParticipant.publishTracksInfo(): List<LivekitRtc.TrackPublishe
821 } 823 }
822 824
823 interface TrackPublishOptions { 825 interface TrackPublishOptions {
  826 + /**
  827 + * The name of the track.
  828 + */
824 val name: String? 829 val name: String?
  830 +
  831 + /**
  832 + * The source of a track, camera, microphone or screen.
  833 + */
  834 + val source: Track.Source?
  835 +
  836 + /**
  837 + * The stream name for the track. Audio and video tracks with the same stream
  838 + * name will be placed in the same `MediaStream` and offer better synchronization.
  839 + *
  840 + * By default, camera and microphone will be placed in the same stream.
  841 + */
  842 + val stream: String?
825 } 843 }
826 844
827 abstract class BaseVideoTrackPublishOptions { 845 abstract class BaseVideoTrackPublishOptions {
@@ -868,17 +886,23 @@ data class VideoTrackPublishOptions( @@ -868,17 +886,23 @@ data class VideoTrackPublishOptions(
868 override val videoCodec: String = VideoCodec.VP8.codecName, 886 override val videoCodec: String = VideoCodec.VP8.codecName,
869 override val scalabilityMode: String? = null, 887 override val scalabilityMode: String? = null,
870 override val backupCodec: BackupVideoCodec? = null, 888 override val backupCodec: BackupVideoCodec? = null,
  889 + override val source: Track.Source? = null,
  890 + override val stream: String? = null,
871 ) : BaseVideoTrackPublishOptions(), TrackPublishOptions { 891 ) : BaseVideoTrackPublishOptions(), TrackPublishOptions {
872 constructor( 892 constructor(
873 name: String? = null, 893 name: String? = null,
874 base: BaseVideoTrackPublishOptions, 894 base: BaseVideoTrackPublishOptions,
  895 + source: Track.Source? = null,
  896 + stream: String? = null,
875 ) : this( 897 ) : this(
876 - name,  
877 - base.videoEncoding,  
878 - base.simulcast,  
879 - base.videoCodec,  
880 - base.scalabilityMode,  
881 - base.backupCodec, 898 + name = name,
  899 + videoEncoding = base.videoEncoding,
  900 + simulcast = base.simulcast,
  901 + videoCodec = base.videoCodec,
  902 + scalabilityMode = base.scalabilityMode,
  903 + backupCodec = base.backupCodec,
  904 + source = source,
  905 + stream = stream,
882 ) 906 )
883 907
884 fun createBackupOptions(): VideoTrackPublishOptions? { 908 fun createBackupOptions(): VideoTrackPublishOptions? {
@@ -913,25 +937,38 @@ abstract class BaseAudioTrackPublishOptions { @@ -913,25 +937,38 @@ abstract class BaseAudioTrackPublishOptions {
913 abstract val red: Boolean 937 abstract val red: Boolean
914 } 938 }
915 939
  940 +/**
  941 + * Default options for publishing an audio track.
  942 + */
916 data class AudioTrackPublishDefaults( 943 data class AudioTrackPublishDefaults(
917 override val audioBitrate: Int? = 20_000, 944 override val audioBitrate: Int? = 20_000,
918 override val dtx: Boolean = true, 945 override val dtx: Boolean = true,
919 override val red: Boolean = true, 946 override val red: Boolean = true,
920 ) : BaseAudioTrackPublishOptions() 947 ) : BaseAudioTrackPublishOptions()
921 948
  949 +/**
  950 + * Options for publishing an audio track.
  951 + */
922 data class AudioTrackPublishOptions( 952 data class AudioTrackPublishOptions(
923 override val name: String? = null, 953 override val name: String? = null,
924 override val audioBitrate: Int? = null, 954 override val audioBitrate: Int? = null,
925 override val dtx: Boolean = true, 955 override val dtx: Boolean = true,
926 override val red: Boolean = true, 956 override val red: Boolean = true,
  957 + override val source: Track.Source? = null,
  958 + override val stream: String? = null,
927 ) : BaseAudioTrackPublishOptions(), TrackPublishOptions { 959 ) : BaseAudioTrackPublishOptions(), TrackPublishOptions {
928 constructor( 960 constructor(
929 name: String? = null, 961 name: String? = null,
930 base: BaseAudioTrackPublishOptions, 962 base: BaseAudioTrackPublishOptions,
  963 + source: Track.Source? = null,
  964 + stream: String? = null,
931 ) : this( 965 ) : this(
932 - name,  
933 - base.audioBitrate,  
934 - base.dtx, 966 + name = name,
  967 + audioBitrate = base.audioBitrate,
  968 + dtx = base.dtx,
  969 + red = base.red,
  970 + source = source,
  971 + stream = stream,
935 ) 972 )
936 } 973 }
937 974
@@ -962,7 +999,7 @@ data class ParticipantTrackPermission( @@ -962,7 +999,7 @@ data class ParticipantTrackPermission(
962 } 999 }
963 } 1000 }
964 1001
965 - fun toProto(): LivekitRtc.TrackPermission { 1002 + internal fun toProto(): LivekitRtc.TrackPermission {
966 return LivekitRtc.TrackPermission.newBuilder() 1003 return LivekitRtc.TrackPermission.newBuilder()
967 .setParticipantIdentity(participantIdentity) 1004 .setParticipantIdentity(participantIdentity)
968 .setParticipantSid(participantSid) 1005 .setParticipantSid(participantSid)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -29,17 +29,26 @@ import io.livekit.android.util.flow @@ -29,17 +29,26 @@ import io.livekit.android.util.flow
29 import io.livekit.android.util.flowDelegate 29 import io.livekit.android.util.flowDelegate
30 import kotlinx.coroutines.* 30 import kotlinx.coroutines.*
31 import kotlinx.coroutines.flow.* 31 import kotlinx.coroutines.flow.*
  32 +import kotlinx.serialization.Serializable
32 import livekit.LivekitModels 33 import livekit.LivekitModels
33 import java.util.Date 34 import java.util.Date
34 import javax.inject.Named 35 import javax.inject.Named
35 36
36 open class Participant( 37 open class Participant(
37 - var sid: String,  
38 - identity: String? = null, 38 + var sid: Sid,
  39 + identity: Identity? = null,
39 @Named(InjectionNames.DISPATCHER_DEFAULT) 40 @Named(InjectionNames.DISPATCHER_DEFAULT)
40 private val coroutineDispatcher: CoroutineDispatcher, 41 private val coroutineDispatcher: CoroutineDispatcher,
41 ) { 42 ) {
42 43
  44 + @Serializable
  45 + @JvmInline
  46 + value class Identity(val value: String)
  47 +
  48 + @Serializable
  49 + @JvmInline
  50 + value class Sid(val value: String)
  51 +
43 /** 52 /**
44 * To only be used for flow delegate scoping, and should not be cancelled. 53 * To only be used for flow delegate scoping, and should not be cancelled.
45 **/ 54 **/
@@ -65,7 +74,7 @@ open class Participant( @@ -65,7 +74,7 @@ open class Participant(
65 */ 74 */
66 @FlowObservable 75 @FlowObservable
67 @get:FlowObservable 76 @get:FlowObservable
68 - var identity: String? by flowDelegate(identity) 77 + var identity: Identity? by flowDelegate(identity)
69 internal set 78 internal set
70 79
71 /** 80 /**
@@ -179,7 +188,7 @@ open class Participant( @@ -179,7 +188,7 @@ open class Participant(
179 */ 188 */
180 @FlowObservable 189 @FlowObservable
181 @get:FlowObservable 190 @get:FlowObservable
182 - var tracks by flowDelegate(emptyMap<String, TrackPublication>()) 191 + var trackPublications by flowDelegate(emptyMap<String, TrackPublication>())
183 protected set 192 protected set
184 193
185 private fun Flow<Map<String, TrackPublication>>.trackUpdateFlow(): Flow<List<Pair<TrackPublication, Track?>>> { 194 private fun Flow<Map<String, TrackPublication>>.trackUpdateFlow(): Flow<List<Pair<TrackPublication, Track?>>> {
@@ -206,8 +215,8 @@ open class Participant( @@ -206,8 +215,8 @@ open class Participant(
206 */ 215 */
207 @FlowObservable 216 @FlowObservable
208 @get:FlowObservable 217 @get:FlowObservable
209 - val audioTracks by flowDelegate(  
210 - stateFlow = ::tracks.flow 218 + val audioTrackPublications by flowDelegate(
  219 + stateFlow = ::trackPublications.flow
211 .map { it.filterValues { publication -> publication.kind == Track.Kind.AUDIO } } 220 .map { it.filterValues { publication -> publication.kind == Track.Kind.AUDIO } }
212 .trackUpdateFlow() 221 .trackUpdateFlow()
213 .stateIn(delegateScope, SharingStarted.Eagerly, emptyList()), 222 .stateIn(delegateScope, SharingStarted.Eagerly, emptyList()),
@@ -218,8 +227,8 @@ open class Participant( @@ -218,8 +227,8 @@ open class Participant(
218 */ 227 */
219 @FlowObservable 228 @FlowObservable
220 @get:FlowObservable 229 @get:FlowObservable
221 - val videoTracks by flowDelegate(  
222 - stateFlow = ::tracks.flow 230 + val videoTrackPublications by flowDelegate(
  231 + stateFlow = ::trackPublications.flow
223 .map { it.filterValues { publication -> publication.kind == Track.Kind.VIDEO } } 232 .map { it.filterValues { publication -> publication.kind == Track.Kind.VIDEO } }
224 .trackUpdateFlow() 233 .trackUpdateFlow()
225 .stateIn(delegateScope, SharingStarted.Eagerly, emptyList()), 234 .stateIn(delegateScope, SharingStarted.Eagerly, emptyList()),
@@ -231,7 +240,7 @@ open class Participant( @@ -231,7 +240,7 @@ open class Participant(
231 fun addTrackPublication(publication: TrackPublication) { 240 fun addTrackPublication(publication: TrackPublication) {
232 val track = publication.track 241 val track = publication.track
233 track?.sid = publication.sid 242 track?.sid = publication.sid
234 - tracks = tracks.toMutableMap().apply { 243 + trackPublications = trackPublications.toMutableMap().apply {
235 this[publication.sid] = publication 244 this[publication.sid] = publication
236 } 245 }
237 } 246 }
@@ -244,7 +253,7 @@ open class Participant( @@ -244,7 +253,7 @@ open class Participant(
244 return null 253 return null
245 } 254 }
246 255
247 - for ((_, pub) in tracks) { 256 + for ((_, pub) in trackPublications) {
248 if (pub.source == source) { 257 if (pub.source == source) {
249 return pub 258 return pub
250 } 259 }
@@ -269,7 +278,7 @@ open class Participant( @@ -269,7 +278,7 @@ open class Participant(
269 * Retrieves the first track that matches [name], or null 278 * Retrieves the first track that matches [name], or null
270 */ 279 */
271 open fun getTrackPublicationByName(name: String): TrackPublication? { 280 open fun getTrackPublicationByName(name: String): TrackPublication? {
272 - for ((_, pub) in tracks) { 281 + for ((_, pub) in trackPublications) {
273 if (pub.name == name) { 282 if (pub.name == name) {
274 return pub 283 return pub
275 } 284 }
@@ -300,8 +309,8 @@ open class Participant( @@ -300,8 +309,8 @@ open class Participant(
300 * @suppress 309 * @suppress
301 */ 310 */
302 internal open fun updateFromInfo(info: LivekitModels.ParticipantInfo) { 311 internal open fun updateFromInfo(info: LivekitModels.ParticipantInfo) {
303 - sid = info.sid  
304 - identity = info.identity 312 + sid = Sid(info.sid)
  313 + identity = Identity(info.identity)
305 participantInfo = info 314 participantInfo = info
306 metadata = info.metadata 315 metadata = info.metadata
307 name = info.name 316 name = info.name
@@ -339,7 +348,7 @@ open class Participant( @@ -339,7 +348,7 @@ open class Participant(
339 } 348 }
340 349
341 internal fun onTrackStreamStateChanged(trackEvent: TrackEvent.StreamStateChanged) { 350 internal fun onTrackStreamStateChanged(trackEvent: TrackEvent.StreamStateChanged) {
342 - val trackPublication = tracks[trackEvent.track.sid] ?: return 351 + val trackPublication = trackPublications[trackEvent.track.sid] ?: return
343 eventBus.postEvent( 352 eventBus.postEvent(
344 ParticipantEvent.TrackStreamStateChanged(this, trackPublication, trackEvent.streamState), 353 ParticipantEvent.TrackStreamStateChanged(this, trackPublication, trackEvent.streamState),
345 scope, 354 scope,
@@ -355,7 +364,7 @@ open class Participant( @@ -355,7 +364,7 @@ open class Participant(
355 internal open fun dispose() { 364 internal open fun dispose() {
356 scope.cancel() 365 scope.cancel()
357 366
358 - sid = "" 367 + sid = Sid("")
359 name = null 368 name = null
360 identity = null 369 identity = null
361 metadata = null 370 metadata = null
@@ -455,6 +464,7 @@ enum class ConnectionQuality { @@ -455,6 +464,7 @@ enum class ConnectionQuality {
455 GOOD, 464 GOOD,
456 POOR, 465 POOR,
457 UNKNOWN, 466 UNKNOWN,
  467 + LOST,
458 ; 468 ;
459 469
460 companion object { 470 companion object {
@@ -464,6 +474,7 @@ enum class ConnectionQuality { @@ -464,6 +474,7 @@ enum class ConnectionQuality {
464 LivekitModels.ConnectionQuality.GOOD -> GOOD 474 LivekitModels.ConnectionQuality.GOOD -> GOOD
465 LivekitModels.ConnectionQuality.POOR -> POOR 475 LivekitModels.ConnectionQuality.POOR -> POOR
466 LivekitModels.ConnectionQuality.UNRECOGNIZED -> UNKNOWN 476 LivekitModels.ConnectionQuality.UNRECOGNIZED -> UNKNOWN
  477 + LivekitModels.ConnectionQuality.LOST -> LOST
467 } 478 }
468 } 479 }
469 } 480 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.room.participant 17 package io.livekit.android.room.participant
18 18
19 -fun String.mimeTypeToVideoCodec(): String? { 19 +internal fun String.mimeTypeToVideoCodec(): String? {
20 return split("/") 20 return split("/")
21 .takeIf { length > 1 } 21 .takeIf { length > 1 }
22 ?.get(1) 22 ?.get(1)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -32,14 +32,14 @@ import kotlinx.coroutines.delay @@ -32,14 +32,14 @@ import kotlinx.coroutines.delay
32 import kotlinx.coroutines.launch 32 import kotlinx.coroutines.launch
33 import livekit.LivekitModels 33 import livekit.LivekitModels
34 import livekit.LivekitRtc 34 import livekit.LivekitRtc
35 -import org.webrtc.AudioTrack  
36 -import org.webrtc.MediaStreamTrack  
37 -import org.webrtc.RtpReceiver  
38 -import org.webrtc.VideoTrack 35 +import livekit.org.webrtc.AudioTrack
  36 +import livekit.org.webrtc.MediaStreamTrack
  37 +import livekit.org.webrtc.RtpReceiver
  38 +import livekit.org.webrtc.VideoTrack
39 39
40 class RemoteParticipant( 40 class RemoteParticipant(
41 - sid: String,  
42 - identity: String? = null, 41 + sid: Sid,
  42 + identity: Identity? = null,
43 val signalClient: SignalClient, 43 val signalClient: SignalClient,
44 private val ioDispatcher: CoroutineDispatcher, 44 private val ioDispatcher: CoroutineDispatcher,
45 defaultDispatcher: CoroutineDispatcher, 45 defaultDispatcher: CoroutineDispatcher,
@@ -57,8 +57,8 @@ class RemoteParticipant( @@ -57,8 +57,8 @@ class RemoteParticipant(
57 ioDispatcher: CoroutineDispatcher, 57 ioDispatcher: CoroutineDispatcher,
58 defaultDispatcher: CoroutineDispatcher, 58 defaultDispatcher: CoroutineDispatcher,
59 ) : this( 59 ) : this(
60 - info.sid,  
61 - info.identity, 60 + Sid(info.sid),
  61 + Identity(info.identity),
62 signalClient, 62 signalClient,
63 ioDispatcher, 63 ioDispatcher,
64 defaultDispatcher, 64 defaultDispatcher,
@@ -68,7 +68,7 @@ class RemoteParticipant( @@ -68,7 +68,7 @@ class RemoteParticipant(
68 68
69 private val coroutineScope = CloseableCoroutineScope(defaultDispatcher + SupervisorJob()) 69 private val coroutineScope = CloseableCoroutineScope(defaultDispatcher + SupervisorJob())
70 70
71 - fun getTrackPublication(sid: String): RemoteTrackPublication? = tracks[sid] as? RemoteTrackPublication 71 + fun getTrackPublication(sid: String): RemoteTrackPublication? = trackPublications[sid] as? RemoteTrackPublication
72 72
73 /** 73 /**
74 * @suppress 74 * @suppress
@@ -105,9 +105,9 @@ class RemoteParticipant( @@ -105,9 +105,9 @@ class RemoteParticipant(
105 eventBus.postEvent(ParticipantEvent.TrackPublished(this, publication), scope) 105 eventBus.postEvent(ParticipantEvent.TrackPublished(this, publication), scope)
106 } 106 }
107 107
108 - val invalidKeys = tracks.keys - validTrackPublication.keys 108 + val invalidKeys = trackPublications.keys - validTrackPublication.keys
109 for (invalidKey in invalidKeys) { 109 for (invalidKey in invalidKeys) {
110 - val publication = tracks[invalidKey] ?: continue 110 + val publication = trackPublications[invalidKey] ?: continue
111 unpublishTrack(publication.sid, true) 111 unpublishTrack(publication.sid, true)
112 } 112 }
113 } 113 }
@@ -175,8 +175,8 @@ class RemoteParticipant( @@ -175,8 +175,8 @@ class RemoteParticipant(
175 } 175 }
176 176
177 fun unpublishTrack(trackSid: String, sendUnpublish: Boolean = false) { 177 fun unpublishTrack(trackSid: String, sendUnpublish: Boolean = false) {
178 - val publication = tracks[trackSid] as? RemoteTrackPublication ?: return  
179 - tracks = tracks.toMutableMap().apply { remove(trackSid) } 178 + val publication = trackPublications[trackSid] as? RemoteTrackPublication ?: return
  179 + trackPublications = trackPublications.toMutableMap().apply { remove(trackSid) }
180 180
181 val track = publication.track 181 val track = publication.track
182 if (track != null) { 182 if (track != null) {
@@ -198,7 +198,7 @@ class RemoteParticipant( @@ -198,7 +198,7 @@ class RemoteParticipant(
198 } 198 }
199 199
200 internal fun onSubscriptionPermissionUpdate(subscriptionPermissionUpdate: LivekitRtc.SubscriptionPermissionUpdate) { 200 internal fun onSubscriptionPermissionUpdate(subscriptionPermissionUpdate: LivekitRtc.SubscriptionPermissionUpdate) {
201 - val pub = tracks[subscriptionPermissionUpdate.trackSid] as? RemoteTrackPublication ?: return 201 + val pub = trackPublications[subscriptionPermissionUpdate.trackSid] as? RemoteTrackPublication ?: return
202 202
203 if (pub.subscriptionAllowed != subscriptionPermissionUpdate.allowed) { 203 if (pub.subscriptionAllowed != subscriptionPermissionUpdate.allowed) {
204 pub.subscriptionAllowed = subscriptionPermissionUpdate.allowed 204 pub.subscriptionAllowed = subscriptionPermissionUpdate.allowed
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,16 @@ @@ -16,7 +16,16 @@
16 16
17 package io.livekit.android.room.track 17 package io.livekit.android.room.track
18 18
19 -import org.webrtc.AudioTrack 19 +import livekit.org.webrtc.AudioTrack
20 20
21 -abstract class AudioTrack(name: String, override val rtcTrack: AudioTrack) : 21 +/**
  22 + * A class representing an audio track.
  23 + */
  24 +abstract class AudioTrack(
  25 + name: String,
  26 + /**
  27 + * The underlying WebRTC audio track.
  28 + */
  29 + override val rtcTrack: AudioTrack
  30 +) :
22 Track(name, Kind.AUDIO, rtcTrack) 31 Track(name, Kind.AUDIO, rtcTrack)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,10 +21,10 @@ import android.content.Context @@ -21,10 +21,10 @@ import android.content.Context
21 import android.content.pm.PackageManager 21 import android.content.pm.PackageManager
22 import androidx.core.content.ContextCompat 22 import androidx.core.content.ContextCompat
23 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread 23 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread
24 -import org.webrtc.MediaConstraints  
25 -import org.webrtc.PeerConnectionFactory  
26 -import org.webrtc.RtpSender  
27 -import org.webrtc.RtpTransceiver 24 +import livekit.org.webrtc.MediaConstraints
  25 +import livekit.org.webrtc.PeerConnectionFactory
  26 +import livekit.org.webrtc.RtpSender
  27 +import livekit.org.webrtc.RtpTransceiver
28 import java.util.* 28 import java.util.*
29 29
30 /** 30 /**
@@ -34,7 +34,7 @@ import java.util.* @@ -34,7 +34,7 @@ import java.util.*
34 */ 34 */
35 class LocalAudioTrack( 35 class LocalAudioTrack(
36 name: String, 36 name: String,
37 - mediaTrack: org.webrtc.AudioTrack 37 + mediaTrack: livekit.org.webrtc.AudioTrack
38 ) : AudioTrack(name, mediaTrack) { 38 ) : AudioTrack(name, mediaTrack) {
39 var enabled: Boolean 39 var enabled: Boolean
40 get() = executeBlockingOnRTCThread { rtcTrack.enabled() } 40 get() = executeBlockingOnRTCThread { rtcTrack.enabled() }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import dagger.assisted.AssistedInject @@ -28,7 +28,7 @@ import dagger.assisted.AssistedInject
28 import io.livekit.android.room.DefaultsManager 28 import io.livekit.android.room.DefaultsManager
29 import io.livekit.android.room.track.screencapture.ScreenCaptureConnection 29 import io.livekit.android.room.track.screencapture.ScreenCaptureConnection
30 import io.livekit.android.room.track.screencapture.ScreenCaptureService 30 import io.livekit.android.room.track.screencapture.ScreenCaptureService
31 -import org.webrtc.* 31 +import livekit.org.webrtc.*
32 import java.util.* 32 import java.util.*
33 33
34 class LocalScreencastVideoTrack 34 class LocalScreencastVideoTrack
@@ -38,7 +38,7 @@ constructor( @@ -38,7 +38,7 @@ constructor(
38 @Assisted source: VideoSource, 38 @Assisted source: VideoSource,
39 @Assisted name: String, 39 @Assisted name: String,
40 @Assisted options: LocalVideoTrackOptions, 40 @Assisted options: LocalVideoTrackOptions,
41 - @Assisted rtcTrack: org.webrtc.VideoTrack, 41 + @Assisted rtcTrack: livekit.org.webrtc.VideoTrack,
42 @Assisted mediaProjectionCallback: MediaProjectionCallback, 42 @Assisted mediaProjectionCallback: MediaProjectionCallback,
43 peerConnectionFactory: PeerConnectionFactory, 43 peerConnectionFactory: PeerConnectionFactory,
44 context: Context, 44 context: Context,
@@ -104,7 +104,7 @@ constructor( @@ -104,7 +104,7 @@ constructor(
104 source: VideoSource, 104 source: VideoSource,
105 name: String, 105 name: String,
106 options: LocalVideoTrackOptions, 106 options: LocalVideoTrackOptions,
107 - rtcTrack: org.webrtc.VideoTrack, 107 + rtcTrack: livekit.org.webrtc.VideoTrack,
108 mediaProjectionCallback: MediaProjectionCallback, 108 mediaProjectionCallback: MediaProjectionCallback,
109 ): LocalScreencastVideoTrack 109 ): LocalScreencastVideoTrack
110 } 110 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -37,22 +37,22 @@ import io.livekit.android.util.FlowObservable @@ -37,22 +37,22 @@ import io.livekit.android.util.FlowObservable
37 import io.livekit.android.util.LKLog 37 import io.livekit.android.util.LKLog
38 import io.livekit.android.util.flowDelegate 38 import io.livekit.android.util.flowDelegate
39 import livekit.LivekitModels 39 import livekit.LivekitModels
40 -import livekit.LivekitModels.VideoQuality  
41 import livekit.LivekitRtc 40 import livekit.LivekitRtc
42 import livekit.LivekitRtc.SubscribedCodec 41 import livekit.LivekitRtc.SubscribedCodec
43 -import org.webrtc.CameraVideoCapturer  
44 -import org.webrtc.CameraVideoCapturer.CameraEventsHandler  
45 -import org.webrtc.EglBase  
46 -import org.webrtc.MediaStreamTrack  
47 -import org.webrtc.PeerConnectionFactory  
48 -import org.webrtc.RtpParameters  
49 -import org.webrtc.RtpSender  
50 -import org.webrtc.RtpTransceiver  
51 -import org.webrtc.SurfaceTextureHelper  
52 -import org.webrtc.VideoCapturer  
53 -import org.webrtc.VideoProcessor  
54 -import org.webrtc.VideoSource 42 +import livekit.org.webrtc.CameraVideoCapturer
  43 +import livekit.org.webrtc.CameraVideoCapturer.CameraEventsHandler
  44 +import livekit.org.webrtc.EglBase
  45 +import livekit.org.webrtc.MediaStreamTrack
  46 +import livekit.org.webrtc.PeerConnectionFactory
  47 +import livekit.org.webrtc.RtpParameters
  48 +import livekit.org.webrtc.RtpSender
  49 +import livekit.org.webrtc.RtpTransceiver
  50 +import livekit.org.webrtc.SurfaceTextureHelper
  51 +import livekit.org.webrtc.VideoCapturer
  52 +import livekit.org.webrtc.VideoProcessor
  53 +import livekit.org.webrtc.VideoSource
55 import java.util.UUID 54 import java.util.UUID
  55 +import livekit.LivekitModels.VideoQuality as ProtoVideoQuality
56 56
57 /** 57 /**
58 * A representation of a local video track (generally input coming from camera or screen). 58 * A representation of a local video track (generally input coming from camera or screen).
@@ -66,7 +66,7 @@ constructor( @@ -66,7 +66,7 @@ constructor(
66 @Assisted private var source: VideoSource, 66 @Assisted private var source: VideoSource,
67 @Assisted name: String, 67 @Assisted name: String,
68 @Assisted options: LocalVideoTrackOptions, 68 @Assisted options: LocalVideoTrackOptions,
69 - @Assisted rtcTrack: org.webrtc.VideoTrack, 69 + @Assisted rtcTrack: livekit.org.webrtc.VideoTrack,
70 private val peerConnectionFactory: PeerConnectionFactory, 70 private val peerConnectionFactory: PeerConnectionFactory,
71 private val context: Context, 71 private val context: Context,
72 private val eglBase: EglBase, 72 private val eglBase: EglBase,
@@ -74,7 +74,7 @@ constructor( @@ -74,7 +74,7 @@ constructor(
74 private val trackFactory: Factory, 74 private val trackFactory: Factory,
75 ) : VideoTrack(name, rtcTrack) { 75 ) : VideoTrack(name, rtcTrack) {
76 76
77 - override var rtcTrack: org.webrtc.VideoTrack = rtcTrack 77 + override var rtcTrack: livekit.org.webrtc.VideoTrack = rtcTrack
78 internal set 78 internal set
79 79
80 internal var codec: String? = null 80 internal var codec: String? = null
@@ -274,14 +274,14 @@ constructor( @@ -274,14 +274,14 @@ constructor(
274 274
275 if (encodings.firstOrNull()?.scalabilityMode != null) { 275 if (encodings.firstOrNull()?.scalabilityMode != null) {
276 val encoding = encodings.first() 276 val encoding = encodings.first()
277 - var maxQuality = VideoQuality.OFF 277 + var maxQuality = ProtoVideoQuality.OFF
278 for (quality in qualities) { 278 for (quality in qualities) {
279 - if (quality.enabled && (maxQuality == VideoQuality.OFF || quality.quality.number > maxQuality.number)) { 279 + if (quality.enabled && (maxQuality == ProtoVideoQuality.OFF || quality.quality.number > maxQuality.number)) {
280 maxQuality = quality.quality 280 maxQuality = quality.quality
281 } 281 }
282 } 282 }
283 283
284 - if (maxQuality == VideoQuality.OFF) { 284 + if (maxQuality == ProtoVideoQuality.OFF) {
285 if (encoding.active) { 285 if (encoding.active) {
286 LKLog.v { "setting svc track to disabled" } 286 LKLog.v { "setting svc track to disabled" }
287 encoding.active = false 287 encoding.active = false
@@ -379,7 +379,7 @@ constructor( @@ -379,7 +379,7 @@ constructor(
379 source: VideoSource, 379 source: VideoSource,
380 name: String, 380 name: String,
381 options: LocalVideoTrackOptions, 381 options: LocalVideoTrackOptions,
382 - rtcTrack: org.webrtc.VideoTrack, 382 + rtcTrack: livekit.org.webrtc.VideoTrack,
383 ): LocalVideoTrack 383 ): LocalVideoTrack
384 } 384 }
385 385
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.room.track 17 package io.livekit.android.room.track
18 18
19 -import org.webrtc.RtpParameters 19 +import livekit.org.webrtc.RtpParameters
20 20
21 data class LocalVideoTrackOptions( 21 data class LocalVideoTrackOptions(
22 val isScreencast: Boolean = false, 22 val isScreencast: Boolean = false,
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,9 +17,9 @@ @@ -17,9 +17,9 @@
17 package io.livekit.android.room.track 17 package io.livekit.android.room.track
18 18
19 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread 19 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread
20 -import org.webrtc.AudioTrack  
21 -import org.webrtc.AudioTrackSink  
22 -import org.webrtc.RtpReceiver 20 +import livekit.org.webrtc.AudioTrack
  21 +import livekit.org.webrtc.AudioTrackSink
  22 +import livekit.org.webrtc.RtpReceiver
23 23
24 class RemoteAudioTrack( 24 class RemoteAudioTrack(
25 name: String, 25 name: String,
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ class RemoteTrackPublication( @@ -34,7 +34,6 @@ class RemoteTrackPublication(
34 private val ioDispatcher: CoroutineDispatcher, 34 private val ioDispatcher: CoroutineDispatcher,
35 ) : TrackPublication(info, track, participant) { 35 ) : TrackPublication(info, track, participant) {
36 36
37 - @OptIn(FlowPreview::class)  
38 override var track: Track? 37 override var track: Track?
39 get() = super.track 38 get() = super.track
40 set(value) { 39 set(value) {
@@ -67,7 +66,7 @@ class RemoteTrackPublication( @@ -67,7 +66,7 @@ class RemoteTrackPublication(
67 66
68 private var unsubscribed: Boolean = false 67 private var unsubscribed: Boolean = false
69 private var disabled: Boolean = false 68 private var disabled: Boolean = false
70 - private var videoQuality: LivekitModels.VideoQuality? = LivekitModels.VideoQuality.HIGH 69 + private var videoQuality: VideoQuality? = VideoQuality.HIGH
71 private var videoDimensions: Track.Dimensions? = null 70 private var videoDimensions: Track.Dimensions? = null
72 private var fps: Int? = null 71 private var fps: Int? = null
73 72
@@ -123,7 +122,7 @@ class RemoteTrackPublication( @@ -123,7 +122,7 @@ class RemoteTrackPublication(
123 unsubscribed = !subscribed 122 unsubscribed = !subscribed
124 val participant = this.participant.get() as? RemoteParticipant ?: return 123 val participant = this.participant.get() as? RemoteParticipant ?: return
125 val participantTracks = with(LivekitModels.ParticipantTracks.newBuilder()) { 124 val participantTracks = with(LivekitModels.ParticipantTracks.newBuilder()) {
126 - participantSid = participant.sid 125 + participantSid = participant.sid.value
127 addTrackSids(sid) 126 addTrackSids(sid)
128 build() 127 build()
129 } 128 }
@@ -152,7 +151,7 @@ class RemoteTrackPublication( @@ -152,7 +151,7 @@ class RemoteTrackPublication(
152 * 151 *
153 * Will override previous calls to [setVideoDimensions]. 152 * Will override previous calls to [setVideoDimensions].
154 */ 153 */
155 - fun setVideoQuality(quality: LivekitModels.VideoQuality) { 154 + fun setVideoQuality(quality: VideoQuality) {
156 if (isAutoManaged || 155 if (isAutoManaged ||
157 !subscribed || 156 !subscribed ||
158 quality == videoQuality || 157 quality == videoQuality ||
@@ -223,7 +222,7 @@ class RemoteTrackPublication( @@ -223,7 +222,7 @@ class RemoteTrackPublication(
223 val participant = this.participant.get() as? RemoteParticipant ?: return 222 val participant = this.participant.get() as? RemoteParticipant ?: return
224 223
225 val rtcTrack = track?.rtcTrack 224 val rtcTrack = track?.rtcTrack
226 - if (rtcTrack is org.webrtc.VideoTrack) { 225 + if (rtcTrack is livekit.org.webrtc.VideoTrack) {
227 rtcTrack.setShouldReceive(!disabled) 226 rtcTrack.setShouldReceive(!disabled)
228 } 227 }
229 228
@@ -231,7 +230,7 @@ class RemoteTrackPublication( @@ -231,7 +230,7 @@ class RemoteTrackPublication(
231 sid, 230 sid,
232 disabled, 231 disabled,
233 videoDimensions, 232 videoDimensions,
234 - videoQuality, 233 + videoQuality?.toProto(),
235 fps, 234 fps,
236 ) 235 )
237 } 236 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -23,14 +23,14 @@ import io.livekit.android.room.track.video.VideoSinkVisibility @@ -23,14 +23,14 @@ import io.livekit.android.room.track.video.VideoSinkVisibility
23 import io.livekit.android.room.track.video.ViewVisibility 23 import io.livekit.android.room.track.video.ViewVisibility
24 import io.livekit.android.util.LKLog 24 import io.livekit.android.util.LKLog
25 import kotlinx.coroutines.* 25 import kotlinx.coroutines.*
26 -import org.webrtc.RtpReceiver  
27 -import org.webrtc.VideoSink 26 +import livekit.org.webrtc.RtpReceiver
  27 +import livekit.org.webrtc.VideoSink
28 import javax.inject.Named 28 import javax.inject.Named
29 import kotlin.math.max 29 import kotlin.math.max
30 30
31 class RemoteVideoTrack( 31 class RemoteVideoTrack(
32 name: String, 32 name: String,
33 - rtcTrack: org.webrtc.VideoTrack, 33 + rtcTrack: livekit.org.webrtc.VideoTrack,
34 val autoManageVideo: Boolean = false, 34 val autoManageVideo: Boolean = false,
35 @Named(InjectionNames.DISPATCHER_DEFAULT) 35 @Named(InjectionNames.DISPATCHER_DEFAULT)
36 private val dispatcher: CoroutineDispatcher, 36 private val dispatcher: CoroutineDispatcher,
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -24,9 +24,9 @@ import io.livekit.android.webrtc.getStats @@ -24,9 +24,9 @@ import io.livekit.android.webrtc.getStats
24 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread 24 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread
25 import livekit.LivekitModels 25 import livekit.LivekitModels
26 import livekit.LivekitRtc 26 import livekit.LivekitRtc
27 -import org.webrtc.MediaStreamTrack  
28 -import org.webrtc.RTCStatsCollectorCallback  
29 -import org.webrtc.RTCStatsReport 27 +import livekit.org.webrtc.MediaStreamTrack
  28 +import livekit.org.webrtc.RTCStatsCollectorCallback
  29 +import livekit.org.webrtc.RTCStatsReport
30 30
31 abstract class Track( 31 abstract class Track(
32 name: String, 32 name: String,
  1 +/*
  2 + * Copyright 2024 LiveKit, Inc.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package io.livekit.android.room.track
  18 +
  19 +import livekit.LivekitModels
  20 +
  21 +enum class VideoQuality {
  22 + LOW,
  23 + MEDIUM,
  24 + HIGH,
  25 + ;
  26 +
  27 + fun toProto(): LivekitModels.VideoQuality {
  28 + return when (this) {
  29 + LOW -> LivekitModels.VideoQuality.LOW
  30 + MEDIUM -> LivekitModels.VideoQuality.MEDIUM
  31 + HIGH -> LivekitModels.VideoQuality.HIGH
  32 + }
  33 + }
  34 +
  35 + companion object {
  36 + fun fromProto(quality: LivekitModels.VideoQuality): VideoQuality? {
  37 + return when (quality) {
  38 + LivekitModels.VideoQuality.LOW -> LOW
  39 + LivekitModels.VideoQuality.MEDIUM -> MEDIUM
  40 + LivekitModels.VideoQuality.HIGH -> HIGH
  41 + LivekitModels.VideoQuality.OFF -> null
  42 + LivekitModels.VideoQuality.UNRECOGNIZED -> null
  43 + }
  44 + }
  45 + }
  46 +}
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@ @@ -17,8 +17,8 @@
17 package io.livekit.android.room.track 17 package io.livekit.android.room.track
18 18
19 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread 19 import io.livekit.android.webrtc.peerconnection.executeBlockingOnRTCThread
20 -import org.webrtc.VideoSink  
21 -import org.webrtc.VideoTrack 20 +import livekit.org.webrtc.VideoSink
  21 +import livekit.org.webrtc.VideoTrack
22 22
23 abstract class VideoTrack(name: String, override val rtcTrack: VideoTrack) : 23 abstract class VideoTrack(name: String, override val rtcTrack: VideoTrack) :
24 Track(name, Kind.VIDEO, rtcTrack) { 24 Track(name, Kind.VIDEO, rtcTrack) {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -33,10 +33,10 @@ import androidx.core.app.NotificationCompat @@ -33,10 +33,10 @@ import androidx.core.app.NotificationCompat
33 * This a simple default foreground service to display a notification while screen 33 * This a simple default foreground service to display a notification while screen
34 * capturing. 34 * capturing.
35 */ 35 */
36 -  
37 open class ScreenCaptureService : Service() { 36 open class ScreenCaptureService : Service() {
38 private var binder: IBinder = ScreenCaptureBinder() 37 private var binder: IBinder = ScreenCaptureBinder()
39 private var bindCount = 0 38 private var bindCount = 0
  39 +
40 override fun onBind(intent: Intent?): IBinder { 40 override fun onBind(intent: Intent?): IBinder {
41 bindCount++ 41 bindCount++
42 return binder 42 return binder
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@ import android.graphics.Matrix @@ -22,9 +22,9 @@ import android.graphics.Matrix
22 import android.graphics.Paint 22 import android.graphics.Paint
23 import android.os.Build 23 import android.os.Build
24 import android.view.Surface 24 import android.view.Surface
25 -import org.webrtc.CapturerObserver  
26 -import org.webrtc.SurfaceTextureHelper  
27 -import org.webrtc.VideoCapturer 25 +import livekit.org.webrtc.CapturerObserver
  26 +import livekit.org.webrtc.SurfaceTextureHelper
  27 +import livekit.org.webrtc.VideoCapturer
28 28
29 /** 29 /**
30 * A [VideoCapturer] that can be manually driven by passing in [Bitmap]. 30 * A [VideoCapturer] that can be manually driven by passing in [Bitmap].
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -23,14 +23,17 @@ import android.hardware.camera2.CameraManager @@ -23,14 +23,17 @@ import android.hardware.camera2.CameraManager
23 import io.livekit.android.room.track.CameraPosition 23 import io.livekit.android.room.track.CameraPosition
24 import io.livekit.android.room.track.LocalVideoTrackOptions 24 import io.livekit.android.room.track.LocalVideoTrackOptions
25 import io.livekit.android.util.LKLog 25 import io.livekit.android.util.LKLog
26 -import org.webrtc.Camera1Capturer  
27 -import org.webrtc.Camera1Enumerator  
28 -import org.webrtc.Camera1Helper  
29 -import org.webrtc.Camera2Capturer  
30 -import org.webrtc.Camera2Enumerator  
31 -import org.webrtc.CameraEnumerator  
32 -import org.webrtc.VideoCapturer  
33 - 26 +import livekit.org.webrtc.Camera1Capturer
  27 +import livekit.org.webrtc.Camera1Enumerator
  28 +import livekit.org.webrtc.Camera1Helper
  29 +import livekit.org.webrtc.Camera2Capturer
  30 +import livekit.org.webrtc.Camera2Enumerator
  31 +import livekit.org.webrtc.CameraEnumerator
  32 +import livekit.org.webrtc.VideoCapturer
  33 +
  34 +/**
  35 + * Various utils for handling camera capturers.
  36 + */
34 object CameraCapturerUtils { 37 object CameraCapturerUtils {
35 38
36 /** 39 /**
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.room.track.video 17 package io.livekit.android.room.track.video
18 18
19 -import org.webrtc.CameraVideoCapturer.CameraEventsHandler 19 +import livekit.org.webrtc.CameraVideoCapturer.CameraEventsHandler
20 20
21 /** 21 /**
22 * Dispatches CameraEventsHandler callbacks to registered handlers. 22 * Dispatches CameraEventsHandler callbacks to registered handlers.
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -44,8 +44,16 @@ class ComposeVisibility : VideoSinkVisibility() { @@ -44,8 +44,16 @@ class ComposeVisibility : VideoSinkVisibility() {
44 return Track.Dimensions(width, height) 44 return Track.Dimensions(width, height)
45 } 45 }
46 46
47 - // Note, LayoutCoordinates are mutable and may be reused. 47 + /**
  48 + * To be called from a compose view, using `Modifier.onGloballyPositioned`.
  49 + *
  50 + * Example:
  51 + * ```
  52 + * modifier = Modifier.onGloballyPositioned { videoSinkVisibility.onGloballyPositioned(it) }
  53 + * ```
  54 + */
48 fun onGloballyPositioned(layoutCoordinates: LayoutCoordinates) { 55 fun onGloballyPositioned(layoutCoordinates: LayoutCoordinates) {
  56 + // Note, LayoutCoordinates are mutable and may be reused.
49 coordinates = layoutCoordinates 57 coordinates = layoutCoordinates
50 val visible = isVisible() 58 val visible = isVisible()
51 val size = size() 59 val size = size()
@@ -58,6 +66,18 @@ class ComposeVisibility : VideoSinkVisibility() { @@ -58,6 +66,18 @@ class ComposeVisibility : VideoSinkVisibility() {
58 lastSize = size 66 lastSize = size
59 } 67 }
60 68
  69 + /**
  70 + * To be called when the associated compose view no longer exists.
  71 + *
  72 + * Example:
  73 + * ```
  74 + * DisposableEffect(room, videoTrack) {
  75 + * onDispose {
  76 + * videoSinkVisibility.onDispose()
  77 + * }
  78 + * }
  79 + * ```
  80 + */
61 fun onDispose() { 81 fun onDispose() {
62 if (coordinates == null) { 82 if (coordinates == null) {
63 return 83 return
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 package io.livekit.android.room.track.video 17 package io.livekit.android.room.track.video
18 18
19 import android.hardware.camera2.CameraManager 19 import android.hardware.camera2.CameraManager
20 -import org.webrtc.* 20 +import livekit.org.webrtc.*
21 21
22 /** 22 /**
23 * @suppress 23 * @suppress
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -32,7 +32,14 @@ import java.util.Observable @@ -32,7 +32,14 @@ import java.util.Observable
32 * is used. 32 * is used.
33 */ 33 */
34 abstract class VideoSinkVisibility : Observable() { 34 abstract class VideoSinkVisibility : Observable() {
  35 + /**
  36 + * @return whether this VideoSink is visible or not.
  37 + */
35 abstract fun isVisible(): Boolean 38 abstract fun isVisible(): Boolean
  39 +
  40 + /**
  41 + * @return the dimensions of this VideoSink.
  42 + */
36 abstract fun size(): Track.Dimensions 43 abstract fun size(): Track.Dimensions
37 44
38 /** 45 /**
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,15 +21,15 @@ import kotlinx.coroutines.runBlocking @@ -21,15 +21,15 @@ import kotlinx.coroutines.runBlocking
21 import kotlinx.coroutines.suspendCancellableCoroutine 21 import kotlinx.coroutines.suspendCancellableCoroutine
22 import kotlinx.coroutines.sync.Mutex 22 import kotlinx.coroutines.sync.Mutex
23 import kotlinx.coroutines.sync.withLock 23 import kotlinx.coroutines.sync.withLock
24 -import org.webrtc.MediaConstraints  
25 -import org.webrtc.PeerConnection  
26 -import org.webrtc.SdpObserver  
27 -import org.webrtc.SessionDescription 24 +import livekit.org.webrtc.MediaConstraints
  25 +import livekit.org.webrtc.PeerConnection
  26 +import livekit.org.webrtc.SdpObserver
  27 +import livekit.org.webrtc.SessionDescription
28 import kotlin.coroutines.Continuation 28 import kotlin.coroutines.Continuation
29 import kotlin.coroutines.resume 29 import kotlin.coroutines.resume
30 import kotlin.coroutines.suspendCoroutine 30 import kotlin.coroutines.suspendCoroutine
31 31
32 -open class CoroutineSdpObserver : SdpObserver { 32 +internal open class CoroutineSdpObserver : SdpObserver {
33 33
34 private val stateLock = Mutex() 34 private val stateLock = Mutex()
35 private var createOutcome: Either<SessionDescription, String?>? = null 35 private var createOutcome: Either<SessionDescription, String?>? = null
@@ -136,25 +136,25 @@ open class CoroutineSdpObserver : SdpObserver { @@ -136,25 +136,25 @@ open class CoroutineSdpObserver : SdpObserver {
136 } 136 }
137 } 137 }
138 138
139 -suspend fun PeerConnection.createOffer(constraints: MediaConstraints): Either<SessionDescription, String?> { 139 +internal suspend fun PeerConnection.createOffer(constraints: MediaConstraints): Either<SessionDescription, String?> {
140 val observer = CoroutineSdpObserver() 140 val observer = CoroutineSdpObserver()
141 this.createOffer(observer, constraints) 141 this.createOffer(observer, constraints)
142 return observer.awaitCreate() 142 return observer.awaitCreate()
143 } 143 }
144 144
145 -suspend fun PeerConnection.createAnswer(constraints: MediaConstraints): Either<SessionDescription, String?> { 145 +internal suspend fun PeerConnection.createAnswer(constraints: MediaConstraints): Either<SessionDescription, String?> {
146 val observer = CoroutineSdpObserver() 146 val observer = CoroutineSdpObserver()
147 this.createAnswer(observer, constraints) 147 this.createAnswer(observer, constraints)
148 return observer.awaitCreate() 148 return observer.awaitCreate()
149 } 149 }
150 150
151 -suspend fun PeerConnection.setRemoteDescription(description: SessionDescription): Either<Unit, String?> { 151 +internal suspend fun PeerConnection.setRemoteDescription(description: SessionDescription): Either<Unit, String?> {
152 val observer = CoroutineSdpObserver() 152 val observer = CoroutineSdpObserver()
153 this.setRemoteDescription(observer, description) 153 this.setRemoteDescription(observer, description)
154 return observer.awaitSet() 154 return observer.awaitSet()
155 } 155 }
156 156
157 -suspend fun PeerConnection.setLocalDescription(description: SessionDescription): Either<Unit, String?> { 157 +internal suspend fun PeerConnection.setLocalDescription(description: SessionDescription): Either<Unit, String?> {
158 val observer = CoroutineSdpObserver() 158 val observer = CoroutineSdpObserver()
159 this.setLocalDescription(observer, description) 159 this.setLocalDescription(observer, description)
160 return observer.awaitSet() 160 return observer.awaitSet()
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import io.livekit.android.room.track.VideoPreset169 @@ -22,7 +22,7 @@ import io.livekit.android.room.track.VideoPreset169
22 import io.livekit.android.room.track.VideoPreset43 22 import io.livekit.android.room.track.VideoPreset43
23 import io.livekit.android.room.track.video.ScalabilityMode 23 import io.livekit.android.room.track.video.ScalabilityMode
24 import livekit.LivekitModels 24 import livekit.LivekitModels
25 -import org.webrtc.RtpParameters 25 +import livekit.org.webrtc.RtpParameters
26 import kotlin.math.abs 26 import kotlin.math.abs
27 import kotlin.math.ceil 27 import kotlin.math.ceil
28 import kotlin.math.max 28 import kotlin.math.max
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.room.util 17 package io.livekit.android.room.util
18 18
19 -import org.webrtc.MediaConstraints 19 +import livekit.org.webrtc.MediaConstraints
20 20
21 object MediaConstraintKeys { 21 object MediaConstraintKeys {
22 const val OFFER_TO_RECV_AUDIO = "OfferToReceiveAudio" 22 const val OFFER_TO_RECV_AUDIO = "OfferToReceiveAudio"
1 -/*  
2 - * Copyright 2023 LiveKit, Inc.  
3 - *  
4 - * Licensed under the Apache License, Version 2.0 (the "License");  
5 - * you may not use this file except in compliance with the License.  
6 - * You may obtain a copy of the License at  
7 - *  
8 - * http://www.apache.org/licenses/LICENSE-2.0  
9 - *  
10 - * Unless required by applicable law or agreed to in writing, software  
11 - * distributed under the License is distributed on an "AS IS" BASIS,  
12 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
13 - * See the License for the specific language governing permissions and  
14 - * limitations under the License.  
15 - */  
16 -  
17 -package io.livekit.android.room.util  
18 -  
19 -import org.webrtc.DataChannel  
20 -  
21 -fun DataChannel.unpackedTrackLabel(): Triple<String, String, String> {  
22 - val parts = label().split("|")  
23 - val participantSid: String  
24 - val trackSid: String  
25 - val name: String  
26 -  
27 - if (parts.count() == 3) {  
28 - participantSid = parts[0]  
29 - trackSid = parts[1]  
30 - name = parts[2]  
31 - } else {  
32 - participantSid = ""  
33 - trackSid = ""  
34 - name = ""  
35 - }  
36 -  
37 - return Triple(participantSid, trackSid, name)  
38 -}  
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ interface NetworkInfo { @@ -25,7 +25,7 @@ interface NetworkInfo {
25 fun getNetworkType(): NetworkType 25 fun getNetworkType(): NetworkType
26 } 26 }
27 27
28 -class AndroidNetworkInfo(private val context: Context) : NetworkInfo { 28 +internal class AndroidNetworkInfo(private val context: Context) : NetworkInfo {
29 override fun getNetworkType(): NetworkType { 29 override fun getNetworkType(): NetworkType {
30 val connectivityManager = 30 val connectivityManager =
31 context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager ?: return NetworkType.UNKNOWN 31 context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager ?: return NetworkType.UNKNOWN
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@ package io.livekit.android.util @@ -18,7 +18,7 @@ package io.livekit.android.util
18 18
19 import kotlinx.coroutines.* 19 import kotlinx.coroutines.*
20 20
21 -fun <T, R> debounce( 21 +internal fun <T, R> debounce(
22 waitMs: Long = 300L, 22 waitMs: Long = 300L,
23 coroutineScope: CoroutineScope, 23 coroutineScope: CoroutineScope,
24 destinationFunction: suspend (T) -> R, 24 destinationFunction: suspend (T) -> R,
@@ -33,6 +33,6 @@ fun <T, R> debounce( @@ -33,6 +33,6 @@ fun <T, R> debounce(
33 } 33 }
34 } 34 }
35 35
36 -fun <R> ((Unit) -> R).invoke() { 36 +internal fun <R> ((Unit) -> R).invoke() {
37 this.invoke(Unit) 37 this.invoke(Unit)
38 } 38 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,11 +16,11 @@ @@ -16,11 +16,11 @@
16 16
17 package io.livekit.android.util 17 package io.livekit.android.util
18 18
19 -sealed class Either<out A, out B> { 19 +internal sealed class Either<out A, out B> {
20 class Left<out A>(val value: A) : Either<A, Nothing>() 20 class Left<out A>(val value: A) : Either<A, Nothing>()
21 class Right<out B>(val value: B) : Either<Nothing, B>() 21 class Right<out B>(val value: B) : Either<Nothing, B>()
22 } 22 }
23 23
24 -fun <A> Either<A, String?>?.nullSafe(): Either<A, String?> { 24 +internal fun <A> Either<A, String?>?.nullSafe(): Either<A, String?> {
25 return this ?: Either.Right("null") 25 return this ?: Either.Right("null")
26 } 26 }
@@ -57,6 +57,10 @@ internal val <T> KProperty0<T>.delegate: Any? @@ -57,6 +57,10 @@ internal val <T> KProperty0<T>.delegate: Any?
57 } 57 }
58 } 58 }
59 59
  60 +/**
  61 + * @return the flow associated with a [FlowObservable] property,
  62 + * which can be collected upon to observe changes in the value.
  63 + */
60 @Suppress("UNCHECKED_CAST") 64 @Suppress("UNCHECKED_CAST")
61 val <T> KProperty0<T>.flow: StateFlow<T> 65 val <T> KProperty0<T>.flow: StateFlow<T>
62 get() = delegate as StateFlow<T> 66 get() = delegate as StateFlow<T>
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import com.google.protobuf.MessageLite @@ -20,7 +20,7 @@ import com.google.protobuf.MessageLite
20 import okio.ByteString 20 import okio.ByteString
21 import okio.ByteString.Companion.toByteString 21 import okio.ByteString.Companion.toByteString
22 22
23 -fun MessageLite.toOkioByteString(): ByteString { 23 +internal fun MessageLite.toOkioByteString(): ByteString {
24 val byteArray = toByteArray() 24 val byteArray = toByteArray()
25 return byteArray.toByteString(0, byteArray.size) 25 return byteArray.toByteString(0, byteArray.size)
26 } 26 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,12 +16,12 @@ @@ -16,12 +16,12 @@
16 16
17 package io.livekit.android.webrtc 17 package io.livekit.android.webrtc
18 18
19 -import org.webrtc.EglBase  
20 -import org.webrtc.SoftwareVideoDecoderFactory  
21 -import org.webrtc.VideoCodecInfo  
22 -import org.webrtc.VideoDecoder  
23 -import org.webrtc.VideoDecoderFactory  
24 -import org.webrtc.WrappedVideoDecoderFactory 19 +import livekit.org.webrtc.EglBase
  20 +import livekit.org.webrtc.SoftwareVideoDecoderFactory
  21 +import livekit.org.webrtc.VideoCodecInfo
  22 +import livekit.org.webrtc.VideoDecoder
  23 +import livekit.org.webrtc.VideoDecoderFactory
  24 +import livekit.org.webrtc.WrappedVideoDecoderFactory
25 25
26 open class CustomVideoDecoderFactory( 26 open class CustomVideoDecoderFactory(
27 sharedContext: EglBase.Context?, 27 sharedContext: EglBase.Context?,
@@ -31,10 +31,16 @@ open class CustomVideoDecoderFactory( @@ -31,10 +31,16 @@ open class CustomVideoDecoderFactory(
31 private val softwareVideoDecoderFactory = SoftwareVideoDecoderFactory() 31 private val softwareVideoDecoderFactory = SoftwareVideoDecoderFactory()
32 private val wrappedVideoDecoderFactory = WrappedVideoDecoderFactory(sharedContext) 32 private val wrappedVideoDecoderFactory = WrappedVideoDecoderFactory(sharedContext)
33 33
  34 + /**
  35 + * Set to true to force software codecs.
  36 + */
34 fun setForceSWCodec(forceSWCodec: Boolean) { 37 fun setForceSWCodec(forceSWCodec: Boolean) {
35 this.forceSWCodec = forceSWCodec 38 this.forceSWCodec = forceSWCodec
36 } 39 }
37 40
  41 + /**
  42 + * Set a list of codecs for which to use software codecs.
  43 + */
38 fun setForceSWCodecList(forceSWCodecs: List<String>) { 44 fun setForceSWCodecList(forceSWCodecs: List<String>) {
39 this.forceSWCodecs = forceSWCodecs 45 this.forceSWCodecs = forceSWCodecs
40 } 46 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,11 +16,11 @@ @@ -16,11 +16,11 @@
16 16
17 package io.livekit.android.webrtc 17 package io.livekit.android.webrtc
18 18
19 -import org.webrtc.EglBase  
20 -import org.webrtc.SoftwareVideoEncoderFactory  
21 -import org.webrtc.VideoCodecInfo  
22 -import org.webrtc.VideoEncoder  
23 -import org.webrtc.VideoEncoderFactory 19 +import livekit.org.webrtc.EglBase
  20 +import livekit.org.webrtc.SoftwareVideoEncoderFactory
  21 +import livekit.org.webrtc.VideoCodecInfo
  22 +import livekit.org.webrtc.VideoEncoder
  23 +import livekit.org.webrtc.VideoEncoderFactory
24 24
25 open class CustomVideoEncoderFactory( 25 open class CustomVideoEncoderFactory(
26 sharedContext: EglBase.Context?, 26 sharedContext: EglBase.Context?,
@@ -37,10 +37,16 @@ open class CustomVideoEncoderFactory( @@ -37,10 +37,16 @@ open class CustomVideoEncoderFactory(
37 SimulcastVideoEncoderFactoryWrapper(sharedContext, enableIntelVp8Encoder, enableH264HighProfile) 37 SimulcastVideoEncoderFactoryWrapper(sharedContext, enableIntelVp8Encoder, enableH264HighProfile)
38 } 38 }
39 39
  40 + /**
  41 + * Set to true to force software codecs.
  42 + */
40 fun setForceSWCodec(forceSWCodec: Boolean) { 43 fun setForceSWCodec(forceSWCodec: Boolean) {
41 this.forceSWCodec = forceSWCodec 44 this.forceSWCodec = forceSWCodec
42 } 45 }
43 46
  47 + /**
  48 + * Set a list of codecs for which to use software codecs.
  49 + */
44 fun setForceSWCodecList(forceSWCodecs: List<String>) { 50 fun setForceSWCodecList(forceSWCodecs: List<String>) {
45 this.forceSWCodecs = forceSWCodecs 51 this.forceSWCodecs = forceSWCodecs
46 } 52 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@ import android.gov.nist.javax.sdp.fields.AttributeField @@ -20,9 +20,9 @@ import android.gov.nist.javax.sdp.fields.AttributeField
20 import android.javax.sdp.MediaDescription 20 import android.javax.sdp.MediaDescription
21 import io.livekit.android.util.LKLog 21 import io.livekit.android.util.LKLog
22 22
23 -data class SdpRtp(val payload: Long, val codec: String, val rate: Long?, val encoding: String?) 23 +internal data class SdpRtp(val payload: Long, val codec: String, val rate: Long?, val encoding: String?)
24 24
25 -fun MediaDescription.getRtps(): List<Pair<AttributeField, SdpRtp>> { 25 +internal fun MediaDescription.getRtps(): List<Pair<AttributeField, SdpRtp>> {
26 return getAttributes(true) 26 return getAttributes(true)
27 .filterIsInstance<AttributeField>() 27 .filterIsInstance<AttributeField>()
28 .filter { it.attribute.name == "rtpmap" } 28 .filter { it.attribute.name == "rtpmap" }
@@ -37,23 +37,23 @@ fun MediaDescription.getRtps(): List<Pair<AttributeField, SdpRtp>> { @@ -37,23 +37,23 @@ fun MediaDescription.getRtps(): List<Pair<AttributeField, SdpRtp>> {
37 } 37 }
38 38
39 private val RTP = """(\d*) ([\w\-.]*)(?:\s*/(\d*)(?:\s*/(\S*))?)?""".toRegex() 39 private val RTP = """(\d*) ([\w\-.]*)(?:\s*/(\d*)(?:\s*/(\S*))?)?""".toRegex()
40 -fun tryParseRtp(string: String): SdpRtp? { 40 +internal fun tryParseRtp(string: String): SdpRtp? {
41 val match = RTP.matchEntire(string) ?: return null 41 val match = RTP.matchEntire(string) ?: return null
42 val (payload, codec, rate, encoding) = match.destructured 42 val (payload, codec, rate, encoding) = match.destructured
43 return SdpRtp(payload.toLong(), codec, toOptionalLong(rate), toOptionalString(encoding)) 43 return SdpRtp(payload.toLong(), codec, toOptionalLong(rate), toOptionalString(encoding))
44 } 44 }
45 45
46 -data class SdpMsid( 46 +internal data class SdpMsid(
47 /** holds the msid-id (and msid-appdata if available) */ 47 /** holds the msid-id (and msid-appdata if available) */
48 val value: String, 48 val value: String,
49 ) 49 )
50 50
51 -fun MediaDescription.getMsid(): SdpMsid? { 51 +internal fun MediaDescription.getMsid(): SdpMsid? {
52 val attribute = getAttribute("msid") ?: return null 52 val attribute = getAttribute("msid") ?: return null
53 return SdpMsid(attribute) 53 return SdpMsid(attribute)
54 } 54 }
55 55
56 -data class SdpFmtp(val payload: Long, val config: String) { 56 +internal data class SdpFmtp(val payload: Long, val config: String) {
57 fun toAttributeField(): AttributeField { 57 fun toAttributeField(): AttributeField {
58 return AttributeField().apply { 58 return AttributeField().apply {
59 name = "fmtp" 59 name = "fmtp"
@@ -62,7 +62,7 @@ data class SdpFmtp(val payload: Long, val config: String) { @@ -62,7 +62,7 @@ data class SdpFmtp(val payload: Long, val config: String) {
62 } 62 }
63 } 63 }
64 64
65 -fun MediaDescription.getFmtps(): List<Pair<AttributeField, SdpFmtp>> { 65 +internal fun MediaDescription.getFmtps(): List<Pair<AttributeField, SdpFmtp>> {
66 return getAttributes(true) 66 return getAttributes(true)
67 .filterIsInstance<AttributeField>() 67 .filterIsInstance<AttributeField>()
68 .filter { it.attribute.name == "fmtp" } 68 .filter { it.attribute.name == "fmtp" }
@@ -77,13 +77,13 @@ fun MediaDescription.getFmtps(): List<Pair<AttributeField, SdpFmtp>> { @@ -77,13 +77,13 @@ fun MediaDescription.getFmtps(): List<Pair<AttributeField, SdpFmtp>> {
77 } 77 }
78 78
79 private val FMTP = """(\d*) ([\S| ]*)""".toRegex() 79 private val FMTP = """(\d*) ([\S| ]*)""".toRegex()
80 -fun tryParseFmtp(string: String): SdpFmtp? { 80 +internal fun tryParseFmtp(string: String): SdpFmtp? {
81 val match = FMTP.matchEntire(string) ?: return null 81 val match = FMTP.matchEntire(string) ?: return null
82 val (payload, config) = match.destructured 82 val (payload, config) = match.destructured
83 return SdpFmtp(payload.toLong(), config) 83 return SdpFmtp(payload.toLong(), config)
84 } 84 }
85 85
86 -data class SdpExt(val value: Long, val direction: String?, val encryptUri: String?, val uri: String, val config: String?) { 86 +internal data class SdpExt(val value: Long, val direction: String?, val encryptUri: String?, val uri: String, val config: String?) {
87 fun toAttributeField(): AttributeField { 87 fun toAttributeField(): AttributeField {
88 return AttributeField().apply { 88 return AttributeField().apply {
89 name = "extmap" 89 name = "extmap"
@@ -104,7 +104,7 @@ data class SdpExt(val value: Long, val direction: String?, val encryptUri: Strin @@ -104,7 +104,7 @@ data class SdpExt(val value: Long, val direction: String?, val encryptUri: Strin
104 } 104 }
105 } 105 }
106 106
107 -fun MediaDescription.getExts(): List<Pair<AttributeField, SdpExt>> { 107 +internal fun MediaDescription.getExts(): List<Pair<AttributeField, SdpExt>> {
108 return getAttributes(true) 108 return getAttributes(true)
109 .filterIsInstance<AttributeField>() 109 .filterIsInstance<AttributeField>()
110 .filter { it.attribute.name == "extmap" } 110 .filter { it.attribute.name == "extmap" }
@@ -119,11 +119,11 @@ fun MediaDescription.getExts(): List<Pair<AttributeField, SdpExt>> { @@ -119,11 +119,11 @@ fun MediaDescription.getExts(): List<Pair<AttributeField, SdpExt>> {
119 } 119 }
120 120
121 private val EXT = """(\d+)(?:/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?""".toRegex() 121 private val EXT = """(\d+)(?:/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?""".toRegex()
122 -fun tryParseExt(string: String): SdpExt? { 122 +internal fun tryParseExt(string: String): SdpExt? {
123 val match = EXT.matchEntire(string) ?: return null 123 val match = EXT.matchEntire(string) ?: return null
124 val (value, direction, encryptUri, uri, config) = match.destructured 124 val (value, direction, encryptUri, uri, config) = match.destructured
125 return SdpExt(value.toLong(), toOptionalString(direction), toOptionalString(encryptUri), uri, toOptionalString(config)) 125 return SdpExt(value.toLong(), toOptionalString(direction), toOptionalString(encryptUri), uri, toOptionalString(config))
126 } 126 }
127 127
128 -fun toOptionalLong(str: String): Long? = if (str.isEmpty()) null else str.toLong()  
129 -fun toOptionalString(str: String): String? = str.ifEmpty { null } 128 +internal fun toOptionalLong(str: String): Long? = if (str.isEmpty()) null else str.toLong()
  129 +internal fun toOptionalString(str: String): String? = str.ifEmpty { null }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@ @@ -16,8 +16,8 @@
16 16
17 package io.livekit.android.webrtc 17 package io.livekit.android.webrtc
18 18
19 -import org.webrtc.PeerConnection  
20 -import org.webrtc.PeerConnection.RTCConfiguration 19 +import livekit.org.webrtc.PeerConnection
  20 +import livekit.org.webrtc.PeerConnection.RTCConfiguration
21 21
22 /** 22 /**
23 * Completed state is a valid state for a connected connection, so this should be used 23 * Completed state is a valid state for a connected connection, so this should be used
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@ package io.livekit.android.webrtc @@ -18,10 +18,10 @@ package io.livekit.android.webrtc
18 18
19 import io.livekit.android.util.LKLog 19 import io.livekit.android.util.LKLog
20 import kotlinx.coroutines.suspendCancellableCoroutine 20 import kotlinx.coroutines.suspendCancellableCoroutine
21 -import org.webrtc.MediaStreamTrack  
22 -import org.webrtc.RTCStats  
23 -import org.webrtc.RTCStatsCollectorCallback  
24 -import org.webrtc.RTCStatsReport 21 +import livekit.org.webrtc.MediaStreamTrack
  22 +import livekit.org.webrtc.RTCStats
  23 +import livekit.org.webrtc.RTCStatsCollectorCallback
  24 +import livekit.org.webrtc.RTCStatsReport
25 import kotlin.coroutines.resume 25 import kotlin.coroutines.resume
26 26
27 /** 27 /**
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@ package io.livekit.android.webrtc @@ -18,9 +18,9 @@ package io.livekit.android.webrtc
18 18
19 import io.livekit.android.dagger.CapabilitiesGetter 19 import io.livekit.android.dagger.CapabilitiesGetter
20 import io.livekit.android.util.LKLog 20 import io.livekit.android.util.LKLog
21 -import org.webrtc.MediaStreamTrack  
22 -import org.webrtc.RtpCapabilities  
23 -import org.webrtc.RtpTransceiver 21 +import livekit.org.webrtc.MediaStreamTrack
  22 +import livekit.org.webrtc.RtpCapabilities
  23 +import livekit.org.webrtc.RtpTransceiver
24 24
25 internal fun RtpTransceiver.sortVideoCodecPreferences(targetCodec: String, capabilitiesGetter: CapabilitiesGetter) { 25 internal fun RtpTransceiver.sortVideoCodecPreferences(targetCodec: String, capabilitiesGetter: CapabilitiesGetter) {
26 val capabilities = capabilitiesGetter(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO) 26 val capabilities = capabilitiesGetter(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,9 +17,9 @@ @@ -17,9 +17,9 @@
17 package io.livekit.android.webrtc 17 package io.livekit.android.webrtc
18 18
19 import livekit.LivekitRtc 19 import livekit.LivekitRtc
20 -import org.webrtc.SessionDescription 20 +import livekit.org.webrtc.SessionDescription
21 21
22 -fun SessionDescription.toProtoSessionDescription(): LivekitRtc.SessionDescription { 22 +internal fun SessionDescription.toProtoSessionDescription(): LivekitRtc.SessionDescription {
23 val sdBuilder = LivekitRtc.SessionDescription.newBuilder() 23 val sdBuilder = LivekitRtc.SessionDescription.newBuilder()
24 sdBuilder.sdp = description 24 sdBuilder.sdp = description
25 sdBuilder.type = type.canonicalForm() 25 sdBuilder.type = type.canonicalForm()
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 package io.livekit.android.webrtc 17 package io.livekit.android.webrtc
18 18
19 import io.livekit.android.util.LKLog 19 import io.livekit.android.util.LKLog
20 -import org.webrtc.* 20 +import livekit.org.webrtc.*
21 import java.util.concurrent.Callable 21 import java.util.concurrent.Callable
22 import java.util.concurrent.ExecutorService 22 import java.util.concurrent.ExecutorService
23 import java.util.concurrent.Executors 23 import java.util.concurrent.Executors
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,10 +16,10 @@ @@ -16,10 +16,10 @@
16 16
17 package io.livekit.android.webrtc.peerconnection 17 package io.livekit.android.webrtc.peerconnection
18 18
19 -import org.webrtc.PeerConnection  
20 -import org.webrtc.RtpReceiver  
21 -import org.webrtc.RtpSender  
22 -import org.webrtc.RtpTransceiver 19 +import livekit.org.webrtc.PeerConnection
  20 +import livekit.org.webrtc.RtpReceiver
  21 +import livekit.org.webrtc.RtpSender
  22 +import livekit.org.webrtc.RtpTransceiver
23 23
24 /** 24 /**
25 * Objects obtained through [PeerConnection] are transient, 25 * Objects obtained through [PeerConnection] are transient,
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.webrtc 17 +package livekit.org.webrtc
18 18
19 /** 19 /**
20 * A helper to access package-protected methods used in [Camera2Session] 20 * A helper to access package-protected methods used in [Camera2Session]
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -package org.webrtc 17 +package livekit.org.webrtc
18 18
19 import android.hardware.camera2.CameraManager 19 import android.hardware.camera2.CameraManager
20 20
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import io.livekit.android.util.toOkioByteString @@ -30,6 +30,7 @@ import io.livekit.android.util.toOkioByteString
30 import kotlinx.coroutines.ExperimentalCoroutinesApi 30 import kotlinx.coroutines.ExperimentalCoroutinesApi
31 import kotlinx.coroutines.launch 31 import kotlinx.coroutines.launch
32 import livekit.LivekitRtc 32 import livekit.LivekitRtc
  33 +import livekit.org.webrtc.PeerConnection
33 import okhttp3.Protocol 34 import okhttp3.Protocol
34 import okhttp3.Request 35 import okhttp3.Request
35 import okhttp3.Response 36 import okhttp3.Response
@@ -37,7 +38,6 @@ import okio.ByteString @@ -37,7 +38,6 @@ import okio.ByteString
37 import org.junit.Before 38 import org.junit.Before
38 import org.junit.runner.RunWith 39 import org.junit.runner.RunWith
39 import org.robolectric.RobolectricTestRunner 40 import org.robolectric.RobolectricTestRunner
40 -import org.webrtc.PeerConnection  
41 41
42 @ExperimentalCoroutinesApi 42 @ExperimentalCoroutinesApi
43 @RunWith(RobolectricTestRunner::class) 43 @RunWith(RobolectricTestRunner::class)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.AudioTrack 19 +import livekit.org.webrtc.AudioTrack
20 20
21 class MockAudioStreamTrack( 21 class MockAudioStreamTrack(
22 val id: String = "id", 22 val id: String = "id",
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.DataChannel 19 +import livekit.org.webrtc.DataChannel
20 20
21 class MockDataChannel(private val label: String?) : DataChannel(1L) { 21 class MockDataChannel(private val label: String?) : DataChannel(1L) {
22 22
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@ package io.livekit.android.mock @@ -18,7 +18,7 @@ package io.livekit.android.mock
18 18
19 import android.graphics.SurfaceTexture 19 import android.graphics.SurfaceTexture
20 import android.view.Surface 20 import android.view.Surface
21 -import org.webrtc.EglBase 21 +import livekit.org.webrtc.EglBase
22 22
23 class MockEglBase( 23 class MockEglBase(
24 private val eglContext: EglBase.Context = EglBase.Context { 0 }, 24 private val eglContext: EglBase.Context = EglBase.Context { 0 },
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@ @@ -16,9 +16,9 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.AudioTrack  
20 -import org.webrtc.MediaStream  
21 -import org.webrtc.VideoTrack 19 +import livekit.org.webrtc.AudioTrack
  20 +import livekit.org.webrtc.MediaStream
  21 +import livekit.org.webrtc.VideoTrack
22 22
23 fun createMediaStreamId(participantSid: String, trackSid: String) = 23 fun createMediaStreamId(participantSid: String, trackSid: String) =
24 "$participantSid|$trackSid" 24 "$participantSid|$trackSid"
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.MediaStreamTrack 19 +import livekit.org.webrtc.MediaStreamTrack
20 20
21 class MockMediaStreamTrack( 21 class MockMediaStreamTrack(
22 val id: String = "id", 22 val id: String = "id",
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,23 +16,23 @@ @@ -16,23 +16,23 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.DataChannel  
20 -import org.webrtc.IceCandidate  
21 -import org.webrtc.MediaConstraints  
22 -import org.webrtc.MediaStream  
23 -import org.webrtc.MediaStreamTrack  
24 -import org.webrtc.MockRtpTransceiver  
25 -import org.webrtc.NativePeerConnectionFactory  
26 -import org.webrtc.PeerConnection  
27 -import org.webrtc.RTCStatsCollectorCallback  
28 -import org.webrtc.RTCStatsReport  
29 -import org.webrtc.RtcCertificatePem  
30 -import org.webrtc.RtpReceiver  
31 -import org.webrtc.RtpSender  
32 -import org.webrtc.RtpTransceiver  
33 -import org.webrtc.SdpObserver  
34 -import org.webrtc.SessionDescription  
35 -import org.webrtc.StatsObserver 19 +import livekit.org.webrtc.DataChannel
  20 +import livekit.org.webrtc.IceCandidate
  21 +import livekit.org.webrtc.MediaConstraints
  22 +import livekit.org.webrtc.MediaStream
  23 +import livekit.org.webrtc.MediaStreamTrack
  24 +import livekit.org.webrtc.MockRtpTransceiver
  25 +import livekit.org.webrtc.NativePeerConnectionFactory
  26 +import livekit.org.webrtc.PeerConnection
  27 +import livekit.org.webrtc.RTCStatsCollectorCallback
  28 +import livekit.org.webrtc.RTCStatsReport
  29 +import livekit.org.webrtc.RtcCertificatePem
  30 +import livekit.org.webrtc.RtpReceiver
  31 +import livekit.org.webrtc.RtpSender
  32 +import livekit.org.webrtc.RtpTransceiver
  33 +import livekit.org.webrtc.SdpObserver
  34 +import livekit.org.webrtc.SessionDescription
  35 +import livekit.org.webrtc.StatsObserver
36 36
37 private class MockNativePeerConnectionFactory : NativePeerConnectionFactory { 37 private class MockNativePeerConnectionFactory : NativePeerConnectionFactory {
38 override fun createNativePeerConnection(): Long = 0L 38 override fun createNativePeerConnection(): Long = 0L
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@ @@ -16,8 +16,8 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
  19 +import livekit.org.webrtc.RtpReceiver
19 import org.mockito.Mockito 20 import org.mockito.Mockito
20 -import org.webrtc.RtpReceiver  
21 21
22 object MockRtpReceiver { 22 object MockRtpReceiver {
23 fun create(): RtpReceiver { 23 fun create(): RtpReceiver {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@ @@ -16,8 +16,8 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
  19 +import livekit.org.webrtc.RtpSender
19 import org.mockito.Mockito 20 import org.mockito.Mockito
20 -import org.webrtc.RtpSender  
21 21
22 object MockRtpSender { 22 object MockRtpSender {
23 fun create(): RtpSender { 23 fun create(): RtpSender {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -17,9 +17,9 @@ @@ -17,9 +17,9 @@
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 import android.content.Context 19 import android.content.Context
20 -import org.webrtc.CapturerObserver  
21 -import org.webrtc.SurfaceTextureHelper  
22 -import org.webrtc.VideoCapturer 20 +import livekit.org.webrtc.CapturerObserver
  21 +import livekit.org.webrtc.SurfaceTextureHelper
  22 +import livekit.org.webrtc.VideoCapturer
23 23
24 class MockVideoCapturer : VideoCapturer { 24 class MockVideoCapturer : VideoCapturer {
25 override fun initialize(p0: SurfaceTextureHelper?, p1: Context?, p2: CapturerObserver?) { 25 override fun initialize(p0: SurfaceTextureHelper?, p1: Context?, p2: CapturerObserver?) {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,6 +16,6 @@ @@ -16,6 +16,6 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.VideoSource 19 +import livekit.org.webrtc.VideoSource
20 20
21 class MockVideoSource(nativeSource: Long = 100) : VideoSource(nativeSource) 21 class MockVideoSource(nativeSource: Long = 100) : VideoSource(nativeSource)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@ @@ -16,8 +16,8 @@
16 16
17 package io.livekit.android.mock 17 package io.livekit.android.mock
18 18
19 -import org.webrtc.VideoSink  
20 -import org.webrtc.VideoTrack 19 +import livekit.org.webrtc.VideoSink
  20 +import livekit.org.webrtc.VideoTrack
21 import java.util.UUID 21 import java.util.UUID
22 22
23 class MockVideoStreamTrack( 23 class MockVideoStreamTrack(
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -21,24 +21,24 @@ import livekit.LivekitModels @@ -21,24 +21,24 @@ import livekit.LivekitModels
21 object TestData { 21 object TestData {
22 22
23 val LOCAL_AUDIO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) { 23 val LOCAL_AUDIO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) {
24 - sid = "local_audio_track_sid" 24 + sid = "TR_local_audio_track_sid"
25 type = LivekitModels.TrackType.AUDIO 25 type = LivekitModels.TrackType.AUDIO
26 build() 26 build()
27 } 27 }
28 val LOCAL_VIDEO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) { 28 val LOCAL_VIDEO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) {
29 - sid = "local_video_track_sid" 29 + sid = "TR_local_video_track_sid"
30 type = LivekitModels.TrackType.VIDEO 30 type = LivekitModels.TrackType.VIDEO
31 build() 31 build()
32 } 32 }
33 33
34 val REMOTE_AUDIO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) { 34 val REMOTE_AUDIO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) {
35 - sid = "remote_audio_track_sid" 35 + sid = "TR_remote_audio_track_sid"
36 type = LivekitModels.TrackType.AUDIO 36 type = LivekitModels.TrackType.AUDIO
37 build() 37 build()
38 } 38 }
39 39
40 val REMOTE_VIDEO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) { 40 val REMOTE_VIDEO_TRACK = with(LivekitModels.TrackInfo.newBuilder()) {
41 - sid = "remote_video_track_sid" 41 + sid = "TR_remote_video_track_sid"
42 type = LivekitModels.TrackType.VIDEO 42 type = LivekitModels.TrackType.VIDEO
43 build() 43 build()
44 } 44 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import dagger.Provides @@ -23,7 +23,7 @@ import dagger.Provides
23 import io.livekit.android.dagger.CapabilitiesGetter 23 import io.livekit.android.dagger.CapabilitiesGetter
24 import io.livekit.android.dagger.InjectionNames 24 import io.livekit.android.dagger.InjectionNames
25 import io.livekit.android.mock.MockEglBase 25 import io.livekit.android.mock.MockEglBase
26 -import org.webrtc.* 26 +import livekit.org.webrtc.*
27 import javax.inject.Named 27 import javax.inject.Named
28 import javax.inject.Singleton 28 import javax.inject.Singleton
29 29
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -22,13 +22,13 @@ import io.livekit.android.util.toPBByteString @@ -22,13 +22,13 @@ import io.livekit.android.util.toPBByteString
22 import kotlinx.coroutines.ExperimentalCoroutinesApi 22 import kotlinx.coroutines.ExperimentalCoroutinesApi
23 import livekit.LivekitModels 23 import livekit.LivekitModels
24 import livekit.LivekitRtc 24 import livekit.LivekitRtc
  25 +import livekit.org.webrtc.PeerConnection
25 import org.junit.Assert 26 import org.junit.Assert
26 import org.junit.Assert.assertEquals 27 import org.junit.Assert.assertEquals
27 import org.junit.Before 28 import org.junit.Before
28 import org.junit.Test 29 import org.junit.Test
29 import org.junit.runner.RunWith 30 import org.junit.runner.RunWith
30 import org.robolectric.RobolectricTestRunner 31 import org.robolectric.RobolectricTestRunner
31 -import org.webrtc.PeerConnection  
32 32
33 @ExperimentalCoroutinesApi 33 @ExperimentalCoroutinesApi
34 @RunWith(RobolectricTestRunner::class) 34 @RunWith(RobolectricTestRunner::class)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -26,9 +26,9 @@ import io.livekit.android.mock.MockPeerConnection @@ -26,9 +26,9 @@ import io.livekit.android.mock.MockPeerConnection
26 import kotlinx.coroutines.ExperimentalCoroutinesApi 26 import kotlinx.coroutines.ExperimentalCoroutinesApi
27 import livekit.LivekitModels.DataPacket 27 import livekit.LivekitModels.DataPacket
28 import livekit.LivekitModels.UserPacket 28 import livekit.LivekitModels.UserPacket
  29 +import livekit.org.webrtc.DataChannel
29 import org.junit.Assert.assertEquals 30 import org.junit.Assert.assertEquals
30 import org.junit.Test 31 import org.junit.Test
31 -import org.webrtc.DataChannel  
32 import java.nio.ByteBuffer 32 import java.nio.ByteBuffer
33 33
34 @OptIn(ExperimentalCoroutinesApi::class) 34 @OptIn(ExperimentalCoroutinesApi::class)
@@ -50,7 +50,7 @@ class RoomDataMockE2ETest : MockE2ETest() { @@ -50,7 +50,7 @@ class RoomDataMockE2ETest : MockE2ETest() {
50 } 50 }
51 val dataBuffer = DataChannel.Buffer( 51 val dataBuffer = DataChannel.Buffer(
52 ByteBuffer.wrap(dataPacket.toByteArray()), 52 ByteBuffer.wrap(dataPacket.toByteArray()),
53 - true 53 + true,
54 ) 54 )
55 55
56 subDataChannel.observer?.onMessage(dataBuffer) 56 subDataChannel.observer?.onMessage(dataBuffer)
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -285,7 +285,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -285,7 +285,7 @@ class RoomMockE2ETest : MockE2ETest() {
285 Assert.assertEquals(true, events[0] is RoomEvent.TrackSubscriptionPermissionChanged) 285 Assert.assertEquals(true, events[0] is RoomEvent.TrackSubscriptionPermissionChanged)
286 286
287 val event = events[0] as RoomEvent.TrackSubscriptionPermissionChanged 287 val event = events[0] as RoomEvent.TrackSubscriptionPermissionChanged
288 - Assert.assertEquals(TestData.REMOTE_PARTICIPANT.sid, event.participant.sid) 288 + Assert.assertEquals(TestData.REMOTE_PARTICIPANT.sid, event.participant.sid.value)
289 Assert.assertEquals(TestData.REMOTE_AUDIO_TRACK.sid, event.trackPublication.sid) 289 Assert.assertEquals(TestData.REMOTE_AUDIO_TRACK.sid, event.trackPublication.sid)
290 Assert.assertEquals(false, event.subscriptionAllowed) 290 Assert.assertEquals(false, event.subscriptionAllowed)
291 } 291 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -22,12 +22,12 @@ import io.livekit.android.room.track.LocalAudioTrack @@ -22,12 +22,12 @@ import io.livekit.android.room.track.LocalAudioTrack
22 import io.livekit.android.util.toPBByteString 22 import io.livekit.android.util.toPBByteString
23 import kotlinx.coroutines.ExperimentalCoroutinesApi 23 import kotlinx.coroutines.ExperimentalCoroutinesApi
24 import livekit.LivekitRtc 24 import livekit.LivekitRtc
  25 +import livekit.org.webrtc.PeerConnection
25 import org.junit.Assert 26 import org.junit.Assert
26 import org.junit.Assert.assertEquals 27 import org.junit.Assert.assertEquals
27 import org.junit.Test 28 import org.junit.Test
28 import org.junit.runner.RunWith 29 import org.junit.runner.RunWith
29 import org.robolectric.RobolectricTestRunner 30 import org.robolectric.RobolectricTestRunner
30 -import org.webrtc.PeerConnection  
31 31
32 /** 32 /**
33 * For tests that only target one reconnection type. 33 * For tests that only target one reconnection type.
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -30,9 +30,13 @@ import io.livekit.android.memory.CloseableManager @@ -30,9 +30,13 @@ import io.livekit.android.memory.CloseableManager
30 import io.livekit.android.mock.* 30 import io.livekit.android.mock.*
31 import io.livekit.android.room.participant.LocalParticipant 31 import io.livekit.android.room.participant.LocalParticipant
32 import kotlinx.coroutines.ExperimentalCoroutinesApi 32 import kotlinx.coroutines.ExperimentalCoroutinesApi
  33 +import kotlinx.coroutines.async
33 import kotlinx.coroutines.flow.MutableSharedFlow 34 import kotlinx.coroutines.flow.MutableSharedFlow
34 import kotlinx.coroutines.flow.SharedFlow 35 import kotlinx.coroutines.flow.SharedFlow
  36 +import kotlinx.coroutines.test.advanceUntilIdle
35 import kotlinx.coroutines.test.runTest 37 import kotlinx.coroutines.test.runTest
  38 +import livekit.LivekitRtc.JoinResponse
  39 +import livekit.org.webrtc.EglBase
36 import org.junit.Assert.* 40 import org.junit.Assert.*
37 import org.junit.Before 41 import org.junit.Before
38 import org.junit.Rule 42 import org.junit.Rule
@@ -45,7 +49,6 @@ import org.mockito.kotlin.* @@ -45,7 +49,6 @@ import org.mockito.kotlin.*
45 import org.robolectric.RobolectricTestRunner 49 import org.robolectric.RobolectricTestRunner
46 import org.robolectric.Shadows 50 import org.robolectric.Shadows
47 import org.robolectric.shadows.ShadowConnectivityManager 51 import org.robolectric.shadows.ShadowConnectivityManager
48 -import org.webrtc.EglBase  
49 52
50 @ExperimentalCoroutinesApi 53 @ExperimentalCoroutinesApi
51 @RunWith(RobolectricTestRunner::class) 54 @RunWith(RobolectricTestRunner::class)
@@ -99,12 +102,12 @@ class RoomTest { @@ -99,12 +102,12 @@ class RoomTest {
99 ) 102 )
100 } 103 }
101 104
102 - suspend fun connect() { 105 + suspend fun connect(joinResponse: JoinResponse = SignalClientTest.JOIN.join) {
103 rtcEngine.stub { 106 rtcEngine.stub {
104 onBlocking { rtcEngine.join(any(), any(), anyOrNull(), anyOrNull()) } 107 onBlocking { rtcEngine.join(any(), any(), anyOrNull(), anyOrNull()) }
105 .doSuspendableAnswer { 108 .doSuspendableAnswer {
106 - room.onJoinResponse(SignalClientTest.JOIN.join)  
107 - SignalClientTest.JOIN.join 109 + room.onJoinResponse(joinResponse)
  110 + joinResponse
108 } 111 }
109 } 112 }
110 rtcEngine.stub { 113 rtcEngine.stub {
@@ -138,6 +141,7 @@ class RoomTest { @@ -138,6 +141,7 @@ class RoomTest {
138 room.onRoomUpdate(update) 141 room.onRoomUpdate(update)
139 val events = eventCollector.stopCollecting() 142 val events = eventCollector.stopCollecting()
140 143
  144 + assertEquals(update.sid, room.sid?.sid)
141 assertEquals(update.metadata, room.metadata) 145 assertEquals(update.metadata, room.metadata)
142 assertEquals(update.activeRecording, room.isRecording) 146 assertEquals(update.activeRecording, room.isRecording)
143 147
@@ -209,4 +213,23 @@ class RoomTest { @@ -209,4 +213,23 @@ class RoomTest {
209 assertNull(room.name) 213 assertNull(room.name)
210 assertFalse(room.isRecording) 214 assertFalse(room.isRecording)
211 } 215 }
  216 +
  217 + @Test
  218 + fun getSidSuspendsUntilPopulated() = runTest {
  219 + val job = async {
  220 + room.getSid()
  221 + }
  222 +
  223 + assertFalse(job.isCompleted)
  224 + connect()
  225 + assertFalse(job.isCompleted)
  226 + val update = SignalClientTest.ROOM_UPDATE.roomUpdate.room
  227 + room.onRoomUpdate(update)
  228 +
  229 + advanceUntilIdle()
  230 + assertTrue(job.isCompleted)
  231 + val sid = job.await()
  232 +
  233 + assertEquals(update.sid, sid.sid)
  234 + }
212 } 235 }
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -30,8 +30,15 @@ import livekit.LivekitModels @@ -30,8 +30,15 @@ import livekit.LivekitModels
30 import livekit.LivekitModels.ClientConfiguration 30 import livekit.LivekitModels.ClientConfiguration
31 import livekit.LivekitRtc 31 import livekit.LivekitRtc
32 import livekit.LivekitRtc.ICEServer 32 import livekit.LivekitRtc.ICEServer
33 -import okhttp3.*  
34 -import org.junit.Assert.* 33 +import livekit.org.webrtc.SessionDescription
  34 +import okhttp3.OkHttpClient
  35 +import okhttp3.Protocol
  36 +import okhttp3.Request
  37 +import okhttp3.Response
  38 +import okhttp3.WebSocketListener
  39 +import org.junit.Assert.assertEquals
  40 +import org.junit.Assert.assertFalse
  41 +import org.junit.Assert.assertTrue
35 import org.junit.Before 42 import org.junit.Before
36 import org.junit.Test 43 import org.junit.Test
37 import org.mockito.Mock 44 import org.mockito.Mock
@@ -40,7 +47,6 @@ import org.mockito.kotlin.any @@ -40,7 +47,6 @@ import org.mockito.kotlin.any
40 import org.mockito.kotlin.argThat 47 import org.mockito.kotlin.argThat
41 import org.mockito.kotlin.inOrder 48 import org.mockito.kotlin.inOrder
42 import org.mockito.kotlin.times 49 import org.mockito.kotlin.times
43 -import org.webrtc.SessionDescription  
44 50
45 @ExperimentalCoroutinesApi 51 @ExperimentalCoroutinesApi
46 class SignalClientTest : BaseTest() { 52 class SignalClientTest : BaseTest() {
@@ -330,7 +336,6 @@ class SignalClientTest : BaseTest() { @@ -330,7 +336,6 @@ class SignalClientTest : BaseTest() {
330 join = with(LivekitRtc.JoinResponse.newBuilder()) { 336 join = with(LivekitRtc.JoinResponse.newBuilder()) {
331 room = with(LivekitModels.Room.newBuilder()) { 337 room = with(LivekitModels.Room.newBuilder()) {
332 name = "roomname" 338 name = "roomname"
333 - sid = "room_sid"  
334 build() 339 build()
335 } 340 }
336 participant = TestData.LOCAL_PARTICIPANT 341 participant = TestData.LOCAL_PARTICIPANT
@@ -380,6 +385,7 @@ class SignalClientTest : BaseTest() { @@ -380,6 +385,7 @@ class SignalClientTest : BaseTest() {
380 val ROOM_UPDATE = with(LivekitRtc.SignalResponse.newBuilder()) { 385 val ROOM_UPDATE = with(LivekitRtc.SignalResponse.newBuilder()) {
381 roomUpdate = with(LivekitRtc.RoomUpdate.newBuilder()) { 386 roomUpdate = with(LivekitRtc.RoomUpdate.newBuilder()) {
382 room = with(LivekitModels.Room.newBuilder()) { 387 room = with(LivekitModels.Room.newBuilder()) {
  388 + sid = "room_sid"
383 metadata = "metadata" 389 metadata = "metadata"
384 activeRecording = true 390 activeRecording = true
385 build() 391 build()
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import io.livekit.android.room.SignalClientTest @@ -30,6 +30,7 @@ import io.livekit.android.room.SignalClientTest
30 import io.livekit.android.room.track.LocalAudioTrack 30 import io.livekit.android.room.track.LocalAudioTrack
31 import io.livekit.android.room.track.LocalVideoTrack 31 import io.livekit.android.room.track.LocalVideoTrack
32 import io.livekit.android.room.track.LocalVideoTrackOptions 32 import io.livekit.android.room.track.LocalVideoTrackOptions
  33 +import io.livekit.android.room.track.Track
33 import io.livekit.android.room.track.VideoCaptureParameter 34 import io.livekit.android.room.track.VideoCaptureParameter
34 import io.livekit.android.room.track.VideoCodec 35 import io.livekit.android.room.track.VideoCodec
35 import io.livekit.android.util.toOkioByteString 36 import io.livekit.android.util.toOkioByteString
@@ -39,6 +40,7 @@ import livekit.LivekitModels @@ -39,6 +40,7 @@ import livekit.LivekitModels
39 import livekit.LivekitRtc 40 import livekit.LivekitRtc
40 import livekit.LivekitRtc.SubscribedCodec 41 import livekit.LivekitRtc.SubscribedCodec
41 import livekit.LivekitRtc.SubscribedQuality 42 import livekit.LivekitRtc.SubscribedQuality
  43 +import livekit.org.webrtc.VideoSource
42 import org.junit.Assert.* 44 import org.junit.Assert.*
43 import org.junit.Test 45 import org.junit.Test
44 import org.junit.runner.RunWith 46 import org.junit.runner.RunWith
@@ -46,7 +48,6 @@ import org.mockito.Mockito @@ -46,7 +48,6 @@ import org.mockito.Mockito
46 import org.mockito.Mockito.mock 48 import org.mockito.Mockito.mock
47 import org.mockito.kotlin.argThat 49 import org.mockito.kotlin.argThat
48 import org.robolectric.RobolectricTestRunner 50 import org.robolectric.RobolectricTestRunner
49 -import org.webrtc.VideoSource  
50 51
51 @ExperimentalCoroutinesApi 52 @ExperimentalCoroutinesApi
52 @RunWith(RobolectricTestRunner::class) 53 @RunWith(RobolectricTestRunner::class)
@@ -65,7 +66,7 @@ class LocalParticipantMockE2ETest : MockE2ETest() { @@ -65,7 +66,7 @@ class LocalParticipantMockE2ETest : MockE2ETest() {
65 66
66 room.disconnect() 67 room.disconnect()
67 68
68 - assertEquals("", room.localParticipant.sid) 69 + assertEquals("", room.localParticipant.sid.value)
69 assertNull(room.localParticipant.name) 70 assertNull(room.localParticipant.name)
70 assertNull(room.localParticipant.identity) 71 assertNull(room.localParticipant.identity)
71 assertNull(room.localParticipant.metadata) 72 assertNull(room.localParticipant.metadata)
@@ -74,9 +75,9 @@ class LocalParticipantMockE2ETest : MockE2ETest() { @@ -74,9 +75,9 @@ class LocalParticipantMockE2ETest : MockE2ETest() {
74 assertFalse(room.localParticipant.isSpeaking) 75 assertFalse(room.localParticipant.isSpeaking)
75 assertEquals(ConnectionQuality.UNKNOWN, room.localParticipant.connectionQuality) 76 assertEquals(ConnectionQuality.UNKNOWN, room.localParticipant.connectionQuality)
76 77
77 - assertEquals(0, room.localParticipant.tracks.values.size)  
78 - assertEquals(0, room.localParticipant.audioTracks.size)  
79 - assertEquals(0, room.localParticipant.videoTracks.size) 78 + assertEquals(0, room.localParticipant.trackPublications.values.size)
  79 + assertEquals(0, room.localParticipant.audioTrackPublications.size)
  80 + assertEquals(0, room.localParticipant.videoTrackPublications.size)
80 } 81 }
81 82
82 @Test 83 @Test
@@ -97,6 +98,30 @@ class LocalParticipantMockE2ETest : MockE2ETest() { @@ -97,6 +98,30 @@ class LocalParticipantMockE2ETest : MockE2ETest() {
97 } 98 }
98 99
99 @Test 100 @Test
  101 + fun publishVideoTrackRequest() = runTest {
  102 + connect()
  103 + wsFactory.ws.clearRequests()
  104 + val videoTrack = createLocalTrack()
  105 + val publishOptions = VideoTrackPublishOptions(
  106 + name = "name",
  107 + source = Track.Source.SCREEN_SHARE,
  108 + stream = "stream_id",
  109 + )
  110 + room.localParticipant.publishVideoTrack(videoTrack, publishOptions)
  111 +
  112 + // Verify the add track request gets the proper publish options set.
  113 + val requestString = wsFactory.ws.sentRequests.first().toPBByteString()
  114 + val sentRequest = LivekitRtc.SignalRequest.newBuilder()
  115 + .mergeFrom(requestString)
  116 + .build()
  117 +
  118 + assertTrue(sentRequest.hasAddTrack())
  119 + assertEquals(publishOptions.name, sentRequest.addTrack.name)
  120 + assertEquals(publishOptions.source?.toProto(), sentRequest.addTrack.source)
  121 + assertEquals(publishOptions.stream, sentRequest.addTrack.stream)
  122 + }
  123 +
  124 + @Test
100 fun updateMetadata() = runTest { 125 fun updateMetadata() = runTest {
101 connect() 126 connect()
102 val newMetadata = "new_metadata" 127 val newMetadata = "new_metadata"
@@ -249,7 +274,7 @@ class LocalParticipantMockE2ETest : MockE2ETest() { @@ -249,7 +274,7 @@ class LocalParticipantMockE2ETest : MockE2ETest() {
249 wsFactory.receiveMessage( 274 wsFactory.receiveMessage(
250 with(LivekitRtc.SignalResponse.newBuilder()) { 275 with(LivekitRtc.SignalResponse.newBuilder()) {
251 subscribedQualityUpdate = with(LivekitRtc.SubscribedQualityUpdate.newBuilder()) { 276 subscribedQualityUpdate = with(LivekitRtc.SubscribedQualityUpdate.newBuilder()) {
252 - trackSid = room.localParticipant.videoTracks.first().first.sid 277 + trackSid = room.localParticipant.videoTrackPublications.first().first.sid
253 addAllSubscribedCodecs( 278 addAllSubscribedCodecs(
254 listOf( 279 listOf(
255 with(SubscribedCodec.newBuilder()) { 280 with(SubscribedCodec.newBuilder()) {
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ class ParticipantMockE2ETest : MockE2ETest() { @@ -54,7 +54,7 @@ class ParticipantMockE2ETest : MockE2ETest() {
54 54
55 assertEquals(1, events.size) 55 assertEquals(1, events.size)
56 assertEquals(true, events[0] is RoomEvent.TrackUnpublished) 56 assertEquals(true, events[0] is RoomEvent.TrackUnpublished)
57 - assertEquals(0, room.localParticipant.tracks.size) 57 + assertEquals(0, room.localParticipant.trackPublications.size)
58 } 58 }
59 59
60 @Test 60 @Test