Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tricky-scissors-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"client-sdk-android": patch
---

Remove Timber from dependencies
24 changes: 24 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
1 change: 0 additions & 1 deletion examples/screenshare-audio/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
1 change: 0 additions & 1 deletion livekit-android-camerax/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ dokkaHtml {
dependencies {

api(project(":livekit-android-sdk"))
implementation libs.timber
implementation libs.coroutines.lib
implementation libs.androidx.annotation

Expand Down
1 change: 0 additions & 1 deletion livekit-android-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ dependencies {
implementation libs.dagger.lib
kapt libs.dagger.compiler

implementation libs.timber
api libs.semver4j

lintChecks project(':livekit-lint')
Expand Down
24 changes: 13 additions & 11 deletions livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
Expand All @@ -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
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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!")
Expand Down
Original file line number Diff line number Diff line change
@@ -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+)+$")
}
}
Loading