From 6f2d0dc239350dbda846f172b47ce490b9450582 Mon Sep 17 00:00:00 2001 From: davidliu Date: Sat, 21 Feb 2026 00:55:15 +0900 Subject: [PATCH 1/3] Remove Timber from dependencies and implement logging internally --- .changeset/tricky-scissors-occur.md | 5 + NOTICE | 24 +++ build.gradle | 1 + examples/screenshare-audio/build.gradle | 1 - gradle/libs.versions.toml | 1 - livekit-android-camerax/build.gradle | 1 - livekit-android-sdk/build.gradle | 1 - .../main/java/io/livekit/android/LiveKit.kt | 22 +-- .../io/livekit/android/dagger/RTCModule.kt | 7 +- .../io/livekit/android/util/LKDebugTree.kt | 139 ++++++++++++++++++ .../java/io/livekit/android/util/LKLog.kt | 63 +++++--- .../io/livekit/android/webrtc/JainSdpUtils.kt | 24 +++ livekit-android-test/build.gradle | 1 - .../livekit/android/test/util/LoggingRule.kt | 16 +- .../java/io/livekit/android/util/LKLogTest.kt | 10 +- livekit-android-track-processors/build.gradle | 1 - sample-app-common/build.gradle | 1 - .../livekit/android/sample/CallViewModel.kt | 21 ++- sample-app-compose/build.gradle | 1 - sample-app/build.gradle | 1 - video-encode-decode-test/build.gradle | 1 - 21 files changed, 276 insertions(+), 66 deletions(-) create mode 100644 .changeset/tricky-scissors-occur.md create mode 100644 livekit-android-sdk/src/main/java/io/livekit/android/util/LKDebugTree.kt diff --git a/.changeset/tricky-scissors-occur.md b/.changeset/tricky-scissors-occur.md new file mode 100644 index 000000000..543e94eda --- /dev/null +++ b/.changeset/tricky-scissors-occur.md @@ -0,0 +1,5 @@ +--- +"client-sdk-android": patch +--- + +Remove Timber from dependencies diff --git a/NOTICE b/NOTICE index b9dd92010..478d95875 100644 --- a/NOTICE +++ b/NOTICE @@ -39,6 +39,8 @@ limitations under the License. The following modifications follow MIT License from https://github.com/ggarber/sdpparser +https://github.com/livekit/client-sdk-android/commit/60ebdd5da1e81db2b1f7ad543105c9cdc058d471 + MIT License Copyright (c) 2023 Gustavo Garcia @@ -96,3 +98,25 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +################################################################################### + +Parts of this source code come from JakeWharton/timber, following Apache License 2.0. + +https://github.com/JakeWharton/timber + +Apache License 2.0 + +Copyright 2013 Jake Wharton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/build.gradle b/build.gradle index 24b2b5662..e304f47dd 100644 --- a/build.gradle +++ b/build.gradle @@ -64,6 +64,7 @@ subprojects { "src/*/java/**/ReentrantMutex.kt", // Different license "src/*/java/**/TextureViewRenderer.kt", // Different license "src/*/java/**/FlowDelegate.kt", // Different license + "src/*/java/**/JainSdpUtils.kt", // Different license ) ktlint("0.50.0") .setEditorConfigPath("$rootDir/.editorconfig") diff --git a/examples/screenshare-audio/build.gradle b/examples/screenshare-audio/build.gradle index 55dcacb18..15191df6c 100644 --- a/examples/screenshare-audio/build.gradle +++ b/examples/screenshare-audio/build.gradle @@ -60,7 +60,6 @@ dependencies { implementation libs.androidx.ui.graphics implementation libs.androidx.ui.tooling.preview implementation libs.androidx.material3 - implementation libs.timber testImplementation libs.junit androidTestImplementation libs.androidx.test.junit androidTestImplementation libs.espresso diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3501a8d7f..189e5a790 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,6 @@ auto-service-annotations = { module = "com.google.auto.service:auto-service-anno coroutines-lib = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } compose-bom = "androidx.compose:compose-bom:2023.08.00" -timber = { module = "com.github.ajalt:timberkt", version = "1.5.1" } # Lint lint-lib = { module = "com.android.tools.lint:lint", version.ref = "lint" } diff --git a/livekit-android-camerax/build.gradle b/livekit-android-camerax/build.gradle index ef850a830..687132d1b 100644 --- a/livekit-android-camerax/build.gradle +++ b/livekit-android-camerax/build.gradle @@ -72,7 +72,6 @@ dokkaHtml { dependencies { api(project(":livekit-android-sdk")) - implementation libs.timber implementation libs.coroutines.lib implementation libs.androidx.annotation diff --git a/livekit-android-sdk/build.gradle b/livekit-android-sdk/build.gradle index 45a3f6981..f6ded5177 100644 --- a/livekit-android-sdk/build.gradle +++ b/livekit-android-sdk/build.gradle @@ -159,7 +159,6 @@ dependencies { implementation libs.dagger.lib kapt libs.dagger.compiler - implementation libs.timber api libs.semver4j lintChecks project(':livekit-lint') diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt index 28c73083a..a94162439 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt @@ -18,13 +18,13 @@ package io.livekit.android import android.app.Application import android.content.Context +import io.livekit.android.LiveKit.loggingLevel import io.livekit.android.dagger.DaggerLiveKitComponent import io.livekit.android.dagger.RTCModule import io.livekit.android.dagger.create import io.livekit.android.room.Room import io.livekit.android.util.LKLog import io.livekit.android.util.LoggingLevel -import timber.log.Timber /** * The main entry point into using LiveKit. @@ -42,16 +42,18 @@ object LiveKit { get() = LKLog.loggingLevel set(value) { LKLog.loggingLevel = value + } - // Plant debug tree if needed. - if (value != LoggingLevel.OFF) { - val forest = Timber.forest() - val needsPlanting = forest.none { it is Timber.DebugTree } - - if (needsPlanting) { - Timber.plant(Timber.DebugTree()) - } - } + /** + * The [LKLog.Logger] to use for Livekit logs. + * + * Default implementation prints to logcat. + */ + @JvmStatic + var logger: LKLog.Logger? + get() = LKLog.logger + set(value) { + LKLog.logger = value } /** diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt index 9f6da9221..5ec4e0b7b 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +58,6 @@ import livekit.org.webrtc.VideoDecoderFactory import livekit.org.webrtc.VideoEncoderFactory import livekit.org.webrtc.audio.AudioDeviceModule import livekit.org.webrtc.audio.JavaAudioDeviceModule -import timber.log.Timber import javax.inject.Named import javax.inject.Singleton @@ -123,9 +122,7 @@ internal object RTCModule { else -> LoggingLevel.OFF } - LKLog.log(loggingLevel) { - Timber.log(loggingLevel.toAndroidLogPriority(), "$s2: $s") - } + LKLog.log(loggingLevel, null) { "$s2: $s" } }, Logging.Severity.LS_VERBOSE, ) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/util/LKDebugTree.kt b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKDebugTree.kt new file mode 100644 index 000000000..7dcf1b87d --- /dev/null +++ b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKDebugTree.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2026 LiveKit, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.livekit.android.util + +import android.os.Build +import android.util.Log +import java.io.PrintWriter +import java.io.StringWriter +import java.util.regex.Pattern + +/** + * This is a modified version of DebugTree from JakeWharton/timber for LiveKit. + * https://github.com/JakeWharton/timber + */ + +/** + * A tree for debug builds. Automatically infers the tag from the calling class. + * @suppress + * */ +open class LKDebugTree { + + private val fqcnIgnore = + listOf( + LKDebugTree::class.java.name, + LKLog.defaultLogger::class.java.name, + ) + + val tag: String? + get() = + Throwable() + .stackTrace + .first { it.className !in fqcnIgnore } + .let(::createStackElementTag) + + fun prepareLog(priority: Int, t: Throwable?, message: String?) { + // Consume tag even when message is not loggable so that next message is correctly tagged. + val tag = tag + + var message = message + if (message.isNullOrEmpty()) { + if (t == null) { + return // Swallow message if it's null and there's no throwable. + } + message = getStackTraceString(t) + } else { + if (t != null) { + message += "\n" + getStackTraceString(t) + } + } + + log(priority, tag, message, t) + } + + private fun getStackTraceString(t: Throwable): String { + // Don't replace this with Log.getStackTraceString() - it hides + // UnknownHostException, which is not what we want. + val sw = StringWriter(256) + val pw = PrintWriter(sw, false) + t.printStackTrace(pw) + pw.flush() + return sw.toString() + } + + /** + * Extract the tag which should be used for the message from the `element`. By default this will + * use the class name without any anonymous class suffixes (e.g., `Foo$1` becomes `Foo`). + * + * Note: This will not be called if a [manual tag][.tag] was specified. + */ + private fun createStackElementTag(element: StackTraceElement): String? { + var tag = element.className.substringAfterLast('.') + val m = ANONYMOUS_CLASS.matcher(tag) + if (m.find()) { + tag = m.replaceAll("") + } + // Tag length limit was removed in API 26. + return if (tag.length <= MAX_TAG_LENGTH || Build.VERSION.SDK_INT >= 26) { + tag + } else { + tag.take(MAX_TAG_LENGTH) + } + } + + /** + * Break up `message` into maximum-length chunks (if needed) and send to either + * [Log.println()][Log.println] or [Log.wtf()][Log.wtf] for logging. + * + * {@inheritDoc} + */ + open fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + if (message.length < MAX_LOG_LENGTH) { + if (priority == Log.ASSERT) { + Log.wtf(tag, message) + } else { + Log.println(priority, tag, message) + } + return + } + + // Split by line, then ensure each line can fit into Log's maximum length. + var i = 0 + val length = message.length + while (i < length) { + var newline = message.indexOf('\n', i) + newline = if (newline != -1) newline else length + do { + val end = newline.coerceAtMost(i + MAX_LOG_LENGTH) + val part = message.substring(i, end) + if (priority == Log.ASSERT) { + Log.wtf(tag, part) + } else { + Log.println(priority, tag, part) + } + i = end + } while (i < newline) + i++ + } + } + + companion object { + private const val MAX_LOG_LENGTH = 4000 + private const val MAX_TAG_LENGTH = 23 + private val ANONYMOUS_CLASS = Pattern.compile("(\\$\\d+)+$") + } +} diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt index e9a476d44..a5516f684 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,13 @@ package io.livekit.android.util -import io.livekit.android.util.LoggingLevel.* -import timber.log.Timber +import io.livekit.android.util.LoggingLevel.DEBUG +import io.livekit.android.util.LoggingLevel.ERROR +import io.livekit.android.util.LoggingLevel.INFO +import io.livekit.android.util.LoggingLevel.OFF +import io.livekit.android.util.LoggingLevel.VERBOSE +import io.livekit.android.util.LoggingLevel.WARN +import io.livekit.android.util.LoggingLevel.WTF /* Copyright 2017-2018 AJ Alt @@ -36,66 +41,78 @@ limitations under the License. Original repo can be found at: https://github.com/ajalt/LKLogkt */ + +private val DEBUG_TREE = LKDebugTree() + /** + * Internal logger for LiveKit + * * @suppress */ @Suppress("NOTHING_TO_INLINE", "unused") class LKLog { + interface Logger { + fun log(priority: LoggingLevel, t: Throwable?, message: String) + } companion object { + val defaultLogger: Logger = object : Logger { + override fun log(priority: LoggingLevel, t: Throwable?, message: String) { + DEBUG_TREE.prepareLog(priority.toAndroidLogPriority(), t, message) + } + } + + var logger: Logger? = defaultLogger + var loggingLevel = OFF /** Log a verbose exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun v(t: Throwable? = null, message: () -> String) = - log(VERBOSE) { Timber.v(t, message()) } + inline fun v(t: Throwable? = null, crossinline message: () -> String) = log(VERBOSE, t, message) @JvmStatic - inline fun v(t: Throwable?) = log(VERBOSE) { Timber.v(t) } + inline fun v(t: Throwable?) = log(VERBOSE, t) { "" } /** Log a debug exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun d(t: Throwable? = null, message: () -> String) = - log(DEBUG) { Timber.d(t, message()) } + inline fun d(t: Throwable? = null, crossinline message: () -> String) = log(DEBUG, t, message) @JvmStatic - inline fun d(t: Throwable?) = log(DEBUG) { Timber.d(t) } + inline fun d(t: Throwable?) = log(DEBUG, t) { "" } /** Log an info exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun i(t: Throwable? = null, message: () -> String) = - log(INFO) { Timber.i(t, message()) } + inline fun i(t: Throwable? = null, crossinline message: () -> String) = log(INFO, t, message) @JvmStatic - inline fun i(t: Throwable?) = log(INFO) { Timber.i(t) } + inline fun i(t: Throwable?) = log(INFO, t) { "" } /** Log a warning exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun w(t: Throwable? = null, message: () -> String) = - log(WARN) { Timber.w(t, message()) } + inline fun w(t: Throwable? = null, crossinline message: () -> String) = log(WARN, t, message) @JvmStatic - inline fun w(t: Throwable?) = log(WARN) { Timber.w(t) } + inline fun w(t: Throwable?) = log(WARN, t) { "" } /** Log an error exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun e(t: Throwable? = null, message: () -> String) = - log(ERROR) { Timber.e(t, message()) } + inline fun e(t: Throwable? = null, crossinline message: () -> String) = log(ERROR, t, message) @JvmStatic - inline fun e(t: Throwable?) = log(ERROR) { Timber.e(t) } + inline fun e(t: Throwable?) = log(ERROR, t) { "" } /** Log an assert exception and a message that will be evaluated lazily when the message is printed */ @JvmStatic - inline fun wtf(t: Throwable? = null, message: () -> String) = - log(WTF) { Timber.wtf(t, message()) } + inline fun wtf(t: Throwable? = null, crossinline message: () -> String) = log(WTF, t, message) @JvmStatic - inline fun wtf(t: Throwable?) = log(WTF) { Timber.wtf(t) } + inline fun wtf(t: Throwable?) = log(WTF, t) { "" } /** @suppress */ - inline fun log(loggingLevel: LoggingLevel, block: () -> Unit) { - if (loggingLevel >= LKLog.loggingLevel && Timber.treeCount() > 0) block() + inline fun log(loggingLevel: LoggingLevel, t: Throwable? = null, crossinline message: (() -> String)) { + if (loggingLevel >= LKLog.loggingLevel) { + logger?.log(loggingLevel, t, message()) + } } } } diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/JainSdpUtils.kt b/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/JainSdpUtils.kt index c6e91c164..897d46d38 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/JainSdpUtils.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/JainSdpUtils.kt @@ -12,6 +12,30 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Parts of this source code comes from https://github.com/ggarber/sdpparser + * + * MIT License + * + * Copyright (c) 2023 Gustavo Garcia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package io.livekit.android.webrtc diff --git a/livekit-android-test/build.gradle b/livekit-android-test/build.gradle index 30d84c287..855e2258a 100644 --- a/livekit-android-test/build.gradle +++ b/livekit-android-test/build.gradle @@ -75,7 +75,6 @@ dokkaHtml { dependencies { implementation(project(":livekit-android-sdk")) - implementation libs.timber implementation libs.coroutines.lib implementation libs.kotlinx.serialization.json api libs.okhttp.lib diff --git a/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt b/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt index 9591f8d61..b6c920497 100644 --- a/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt +++ b/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt @@ -18,11 +18,12 @@ package io.livekit.android.test.util import android.util.Log import io.livekit.android.LiveKit +import io.livekit.android.util.LKDebugTree +import io.livekit.android.util.LKLog import io.livekit.android.util.LoggingLevel import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement -import timber.log.Timber /** * Add this rule to a test class to turn on logs. @@ -31,7 +32,13 @@ class LoggingRule : TestRule { companion object { - val logTree = object : Timber.DebugTree() { + val logger = object : LKLog.Logger { + override fun log(priority: LoggingLevel, t: Throwable?, message: String) { + printlnTree.prepareLog(priority.toAndroidLogPriority(), t, message) + } + + } + val printlnTree = object : LKDebugTree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { val priorityChar = when (priority) { Log.VERBOSE -> "v" @@ -54,11 +61,12 @@ class LoggingRule : TestRule { override fun apply(base: Statement, description: Description?) = object : Statement() { override fun evaluate() { val oldLoggingLevel = LiveKit.loggingLevel - Timber.plant(logTree) + val oldLogger = LiveKit.logger LiveKit.loggingLevel = LoggingLevel.VERBOSE + LiveKit.logger = logger base.evaluate() - Timber.uproot(logTree) LiveKit.loggingLevel = oldLoggingLevel + LiveKit.logger = oldLogger } } } diff --git a/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt b/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt index 79e95cfd4..78788ba4a 100644 --- a/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt +++ b/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt @@ -27,7 +27,10 @@ class LKLogTest { fun log() { var called = false LiveKit.loggingLevel = LoggingLevel.INFO - LKLog.log(LoggingLevel.ERROR) { called = true } + LKLog.log(LoggingLevel.ERROR) { + called = true + "" + } assertTrue(called) } @@ -35,7 +38,10 @@ class LKLogTest { fun noLog() { var called = false LiveKit.loggingLevel = LoggingLevel.OFF - LKLog.log(LoggingLevel.VERBOSE) { called = true } + LKLog.log(LoggingLevel.VERBOSE) { + called = true + "" + } assertFalse(called) } } diff --git a/livekit-android-track-processors/build.gradle b/livekit-android-track-processors/build.gradle index b554edd53..a4726e460 100644 --- a/livekit-android-track-processors/build.gradle +++ b/livekit-android-track-processors/build.gradle @@ -73,7 +73,6 @@ dependencies { implementation(project(":livekit-android-sdk")) implementation(project(":livekit-android-camerax")) - implementation libs.timber implementation libs.coroutines.lib implementation libs.androidx.annotation diff --git a/sample-app-common/build.gradle b/sample-app-common/build.gradle index a699bba76..851579647 100644 --- a/sample-app-common/build.gradle +++ b/sample-app-common/build.gradle @@ -64,7 +64,6 @@ dependencies { api libs.appcompat api libs.material api libs.coroutines.lib - api libs.timber api libs.androidx.lifecycle.runtime.ktx api libs.androidx.lifecycle.viewmodel.ktx api libs.androidx.lifecycle.common.java8 diff --git a/sample-app-common/src/main/java/io/livekit/android/sample/CallViewModel.kt b/sample-app-common/src/main/java/io/livekit/android/sample/CallViewModel.kt index 9f87c3de4..6d0da948f 100644 --- a/sample-app-common/src/main/java/io/livekit/android/sample/CallViewModel.kt +++ b/sample-app-common/src/main/java/io/livekit/android/sample/CallViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.viewModelScope -import com.github.ajalt.timberkt.Timber import io.livekit.android.AudioOptions import io.livekit.android.LiveKit import io.livekit.android.LiveKitOverrides @@ -57,7 +56,6 @@ import io.livekit.android.util.flow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -169,7 +167,7 @@ class CallViewModel( viewModelScope.launch(Dispatchers.Default) { // Collect any errors. launch { - error.collect { Timber.e(it) } + error.collect { LKLog.e(it) } } // Handle any changes in speakers. @@ -197,7 +195,7 @@ class CallViewModel( } else -> { - Timber.e { "Room event: $it" } + LKLog.e { "Room event: $it" } } } } @@ -225,10 +223,10 @@ class CallViewModel( delay(10000) if (pub.subscribed) { val statsReport = pub.track?.getRTCStats() ?: continue - Timber.e { "stats for ${pub.sid}:" } + LKLog.e { "stats for ${pub.sid}:" } for (entry in statsReport.statsMap) { - Timber.e { "${entry.key} = ${entry.value}" } + LKLog.e { "${entry.key} = ${entry.value}" } } } } @@ -409,7 +407,7 @@ class CallViewModel( } fun reconnect() { - Timber.e { "Reconnecting." } + LKLog.e { "Reconnecting." } mutablePrimarySpeaker.value = null room.disconnect() viewModelScope.launch(Dispatchers.IO) { @@ -426,12 +424,12 @@ class CallViewModel( } while (isActive) { - Timber.d { "Stress test -> connect to first room" } + LKLog.d { "Stress test -> connect to first room" } launch(Dispatchers.IO) { quickConnectToRoom(firstToken) } delay(200) room.disconnect() delay(50) - Timber.d { "Stress test -> connect to second room" } + LKLog.d { "Stress test -> connect to second room" } launch(Dispatchers.IO) { quickConnectToRoom(secondToken) } delay(200) room.disconnect() @@ -446,7 +444,7 @@ class CallViewModel( token = token, ) } catch (e: Throwable) { - Timber.e(e) { "Failed to connect to room" } + LKLog.e(e) { "Failed to connect to room" } } } @@ -467,4 +465,3 @@ class CallViewModel( private fun LiveData.hide(): LiveData = this private fun MutableStateFlow.hide(): StateFlow = this -private fun Flow.hide(): Flow = this diff --git a/sample-app-compose/build.gradle b/sample-app-compose/build.gradle index 05cfe1099..e5040b77e 100644 --- a/sample-app-compose/build.gradle +++ b/sample-app-compose/build.gradle @@ -73,7 +73,6 @@ dependencies { implementation libs.androidx.activity.compose implementation 'com.google.accompanist:accompanist-pager:0.19.0' implementation 'com.google.accompanist:accompanist-pager-indicators:0.19.0' - implementation libs.timber testImplementation 'junit:junit:4.+' androidTestImplementation libs.androidx.test.junit androidTestImplementation libs.espresso diff --git a/sample-app/build.gradle b/sample-app/build.gradle index 74d05abf6..cfc536113 100644 --- a/sample-app/build.gradle +++ b/sample-app/build.gradle @@ -61,7 +61,6 @@ dependencies { implementation libs.androidx.lifecycle.common.java8 implementation libs.groupie implementation libs.groupie.viewbinding - implementation libs.timber testImplementation libs.junit androidTestImplementation libs.androidx.test.junit androidTestImplementation libs.espresso diff --git a/video-encode-decode-test/build.gradle b/video-encode-decode-test/build.gradle index 3e3167f9a..33cf850ac 100644 --- a/video-encode-decode-test/build.gradle +++ b/video-encode-decode-test/build.gradle @@ -92,7 +92,6 @@ dependencies { implementation 'androidx.activity:activity-compose:1.3.1' implementation 'com.google.accompanist:accompanist-pager:0.19.0' implementation 'com.google.accompanist:accompanist-pager-indicators:0.19.0' - implementation libs.timber implementation project(":sample-app-common") implementation project(":livekit-android-sdk") testImplementation 'junit:junit:4.+' From 577787f7c448dd0bb856c06eb8c5e670f6207b42 Mon Sep 17 00:00:00 2001 From: davidliu Date: Sat, 21 Feb 2026 01:32:21 +0900 Subject: [PATCH 2/3] spotless --- .../src/main/java/io/livekit/android/LiveKit.kt | 2 +- .../src/main/java/io/livekit/android/util/LKLog.kt | 1 - .../src/main/java/io/livekit/android/test/util/LoggingRule.kt | 3 +-- .../src/test/java/io/livekit/android/util/LKLogTest.kt | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt index a94162439..c281b5aa8 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt index a5516f684..9fa634f93 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/util/LKLog.kt @@ -41,7 +41,6 @@ limitations under the License. Original repo can be found at: https://github.com/ajalt/LKLogkt */ - private val DEBUG_TREE = LKDebugTree() /** diff --git a/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt b/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt index b6c920497..291498c9b 100644 --- a/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt +++ b/livekit-android-test/src/main/java/io/livekit/android/test/util/LoggingRule.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,6 @@ class LoggingRule : TestRule { override fun log(priority: LoggingLevel, t: Throwable?, message: String) { printlnTree.prepareLog(priority.toAndroidLogPriority(), t, message) } - } val printlnTree = object : LKDebugTree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { diff --git a/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt b/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt index 78788ba4a..ca328cd88 100644 --- a/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt +++ b/livekit-android-test/src/test/java/io/livekit/android/util/LKLogTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 LiveKit, Inc. + * Copyright 2024-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From d42bfc0f539d2908c02d9fd3c70f6fe5ef85e470 Mon Sep 17 00:00:00 2001 From: davidliu Date: Sat, 21 Feb 2026 18:34:19 +0900 Subject: [PATCH 3/3] more remove timber --- .../livekit/android/renderer/SurfaceViewRenderer.kt | 4 +--- .../livekit/android/renderer/TextureViewRenderer.kt | 2 -- .../io/livekit/android/sample/ParticipantItem.kt | 6 +++--- .../android/videoencodedecode/CallViewModel.kt | 13 +++++++++---- .../WhitelistDefaultVideoEncoderFactory.kt | 8 ++++---- .../WhitelistSimulcastVideoEncoderFactory.kt | 8 ++++---- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/renderer/SurfaceViewRenderer.kt b/livekit-android-sdk/src/main/java/io/livekit/android/renderer/SurfaceViewRenderer.kt index 1510a9d6e..5f90ccffc 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/renderer/SurfaceViewRenderer.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/renderer/SurfaceViewRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package io.livekit.android.renderer -import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import android.util.Log @@ -48,7 +47,6 @@ open class SurfaceViewRenderer : SurfaceViewRenderer, ViewVisibility.Notifier { super.release() } - @SuppressLint("LogNotTimber") override fun onFrame(frame: VideoFrame) { if (!initialized) { Log.e("SurfaceViewRenderer", "Received frame when not initialized! You must call Room.initVideoRenderer(view) before using this view!") diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/renderer/TextureViewRenderer.kt b/livekit-android-sdk/src/main/java/io/livekit/android/renderer/TextureViewRenderer.kt index e5b733dc1..b1dfc325d 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/renderer/TextureViewRenderer.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/renderer/TextureViewRenderer.kt @@ -9,7 +9,6 @@ */ package io.livekit.android.renderer -import android.annotation.SuppressLint import android.content.Context import android.content.res.Resources.NotFoundException import android.graphics.Matrix @@ -213,7 +212,6 @@ open class TextureViewRenderer : } // VideoSink interface. - @SuppressLint("LogNotTimber") override fun onFrame(frame: VideoFrame) { if (!initialized) { Log.e("TextureViewRenderer", "Received frame when not initialized! You must call Room.initVideoRenderer(view) before using this view!") diff --git a/sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt b/sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt index ea28327fb..74afbe872 100644 --- a/sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt +++ b/sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 LiveKit, Inc. + * Copyright 2024-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package io.livekit.android.sample import android.view.View -import com.github.ajalt.timberkt.Timber import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.GroupieViewHolder import io.livekit.android.room.Room @@ -30,6 +29,7 @@ import io.livekit.android.room.track.LocalVideoTrack import io.livekit.android.room.track.Track import io.livekit.android.room.track.VideoTrack import io.livekit.android.sample.databinding.ParticipantItemBinding +import io.livekit.android.util.LKLog import io.livekit.android.util.flow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -154,7 +154,7 @@ class ParticipantItem( } boundVideoTrack?.removeRenderer(viewBinding.renderer) boundVideoTrack = videoTrack - Timber.v { "adding renderer to $videoTrack" } + LKLog.v { "adding renderer to $videoTrack" } videoTrack?.addRenderer(viewBinding.renderer) } diff --git a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/CallViewModel.kt b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/CallViewModel.kt index c28a31f16..d00b949c5 100644 --- a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/CallViewModel.kt +++ b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/CallViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 LiveKit, Inc. + * Copyright 2024-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import android.graphics.Color import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope -import com.github.ajalt.timberkt.Timber import io.livekit.android.LiveKit import io.livekit.android.LiveKitOverrides import io.livekit.android.RoomOptions @@ -30,9 +29,15 @@ import io.livekit.android.room.participant.Participant import io.livekit.android.room.participant.VideoTrackPublishDefaults import io.livekit.android.room.track.LocalVideoTrackOptions import io.livekit.android.room.track.VideoCaptureParameter +import io.livekit.android.util.LKLog import io.livekit.android.util.flow import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import livekit.org.webrtc.EglBase @@ -69,7 +74,7 @@ class CallViewModel( viewModelScope.launch { launch { - error.collect { Timber.e(it) } + error.collect { LKLog.e(it) } } try { diff --git a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistDefaultVideoEncoderFactory.kt b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistDefaultVideoEncoderFactory.kt index 0ee2c662f..97cfdb475 100644 --- a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistDefaultVideoEncoderFactory.kt +++ b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistDefaultVideoEncoderFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 LiveKit, Inc. + * Copyright 2024-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.livekit.android.videoencodedecode -import com.github.ajalt.timberkt.Timber +import io.livekit.android.util.LKLog import livekit.org.webrtc.DefaultVideoEncoderFactory import livekit.org.webrtc.EglBase import livekit.org.webrtc.VideoCodecInfo @@ -31,10 +31,10 @@ class WhitelistDefaultVideoEncoderFactory( override fun getSupportedCodecs(): Array { val supportedCodecs = super.getSupportedCodecs() - Timber.v { "actual supported codecs: ${supportedCodecs.map { it.name }}" } + LKLog.v { "actual supported codecs: ${supportedCodecs.map { it.name }}" } val filteredCodecs = supportedCodecs.filter { codecWhitelist?.contains(it.name) ?: true }.toTypedArray() - Timber.v { "filtered supported codecs: ${filteredCodecs.map { it.name }}" } + LKLog.v { "filtered supported codecs: ${filteredCodecs.map { it.name }}" } return filteredCodecs } diff --git a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistSimulcastVideoEncoderFactory.kt b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistSimulcastVideoEncoderFactory.kt index 235d6d9a6..1106d9e7d 100644 --- a/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistSimulcastVideoEncoderFactory.kt +++ b/video-encode-decode-test/src/main/java/io/livekit/android/videoencodedecode/WhitelistSimulcastVideoEncoderFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 LiveKit, Inc. + * Copyright 2024-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.livekit.android.videoencodedecode -import com.github.ajalt.timberkt.Timber +import io.livekit.android.util.LKLog import io.livekit.android.webrtc.SimulcastVideoEncoderFactoryWrapper import livekit.org.webrtc.EglBase import livekit.org.webrtc.VideoCodecInfo @@ -31,10 +31,10 @@ class WhitelistSimulcastVideoEncoderFactory( override fun getSupportedCodecs(): Array { val supportedCodecs = super.getSupportedCodecs() - Timber.v { "actual supported codecs: ${supportedCodecs.map { it.name }}" } + LKLog.v { "actual supported codecs: ${supportedCodecs.map { it.name }}" } val filteredCodecs = supportedCodecs.filter { codecWhitelist?.contains(it.name) ?: true }.toTypedArray() - Timber.v { "filtered supported codecs: ${filteredCodecs.map { it.name }}" } + LKLog.v { "filtered supported codecs: ${filteredCodecs.map { it.name }}" } return filteredCodecs }