diff --git a/AGENTS.md b/AGENTS.md index 51a50ffed..f4567e201 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,6 +6,8 @@ Supported platforms: Android (minimum API level 21) - Assemble: `./gradlew assemble` - Run tests: `./gradlew test` +- Run detekt (static analysis): `./gradlew detektDebug` +- Run detekt with baseline: `./gradlew detektRelease` - Install example app: `./gradlew sample-app-compose:installDebug` ## Architecture diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 537579a1d..fd99b5135 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -4,6 +4,10 @@ config: warningsAsErrors: true excludes: '' +empty-blocks: + EmptyFunctionBlock: + ignoreOverridden: true + style: active: false @@ -20,4 +24,4 @@ livekit-rules: exceptions: TooGenericExceptionCaught: - active: false \ No newline at end of file + active: false diff --git a/livekit-android-sdk/build.gradle b/livekit-android-sdk/build.gradle index f6ded5177..706ffa27d 100644 --- a/livekit-android-sdk/build.gradle +++ b/livekit-android-sdk/build.gradle @@ -96,7 +96,7 @@ protobuf { } jacoco { - toolVersion = "0.8.10" + toolVersion = "0.8.14" } tasks.withType(Test) { diff --git a/livekit-android-sdk/detekt-baseline-release.xml b/livekit-android-sdk/detekt-baseline-release.xml index ba07c77f6..89e10ca0b 100644 --- a/livekit-android-sdk/detekt-baseline-release.xml +++ b/livekit-android-sdk/detekt-baseline-release.xml @@ -27,32 +27,9 @@ CyclomaticComplexMethod:Room.kt$Room$@Throws(Exception::class) suspend fun connect(url: String, token: String, options: ConnectOptions = ConnectOptions()) CyclomaticComplexMethod:RoomEvent.kt$fun LivekitModels.DisconnectReason?.convert(): DisconnectReason CyclomaticComplexMethod:SignalClient.kt$SignalClient$private fun handleSignalResponseImpl(ws: WebSocket, response: LivekitRtc.SignalResponse) - DoubleMutabilityForCollection:CoroutineSdpObserver.kt$CoroutineSdpObserver$private var pendingCreate = mutableListOf<Continuation<Either<SessionDescription, String?>>>() - DoubleMutabilityForCollection:CoroutineSdpObserver.kt$CoroutineSdpObserver$private var pendingSets = mutableListOf<Continuation<Either<Unit, String?>>>() - DoubleMutabilityForCollection:E2EEManager.kt$E2EEManager$private var frameCryptors = mutableMapOf<Pair<String, Participant.Identity>, FrameCryptor>() - DoubleMutabilityForCollection:PeerConnectionTransport.kt$PeerConnectionTransport$private var trackBitrates = mutableMapOf<TrackBitrateInfoKey, TrackBitrateInfo>() - DoubleMutabilityForCollection:RegionUrlProvider.kt$RegionUrlProvider$private var attemptedRegions = mutableSetOf<RegionInfo>() - DoubleMutabilityForCollection:Room.kt$Room$private var sidToIdentity = mutableMapOf<Participant.Sid, Participant.Identity>() - DoubleMutabilityForCollection:Room.kt$Room$private var transcriptionReceivedTimes = mutableMapOf<String, Long>() - EmptyCatchBlock:EndpointTokenSource.kt$EndpointTokenSource.<no name provided>${ } - EmptyDefaultConstructor:CachingTokenSource.kt$InMemoryTokenStore$() - EmptyDefaultConstructor:LocalScreencastVideoTrack.kt$LocalScreencastVideoTrack.MediaProjectionCallback$() - EmptyFunctionBlock:CommunicationWorkaround.kt$NoopCommunicationWorkaround${ } - EmptyFunctionBlock:LocalVideoTrack.kt$LocalVideoTrack.<no name provided>.<no name provided>${ } - EmptyFunctionBlock:NoAudioHandler.kt$NoAudioHandler${ } - EmptyFunctionBlock:PublisherTransportObserver.kt$PublisherTransportObserver${ } EmptyFunctionBlock:RTCEngine.kt$RTCEngine${ } - EmptyFunctionBlock:Room.kt$Room${ } - EmptyFunctionBlock:SubscriberTransportObserver.kt$SubscriberTransportObserver${ } - EmptyFunctionBlock:TextureViewRenderer.kt$TextureViewRenderer${} - EmptyFunctionBlock:VideoFrameCapturer.kt$VideoFrameCapturer${ } HasPlatformType:DataChannelManager.kt$DataChannelManager$@get:FlowObservable var state by flowDelegate(dataChannel.state()) private set - HasPlatformType:RTCModule.kt$RTCModule$@Provides fun sdpFactory() IgnoredReturnValue:BaseStreamReceiver.kt$BaseStreamReceiver$catch { } - InjectDispatcher:CoroutinesModule.kt$CoroutinesModule$Default - InjectDispatcher:CoroutinesModule.kt$CoroutinesModule$IO - InjectDispatcher:CoroutinesModule.kt$CoroutinesModule$Unconfined - InjectDispatcher:NetworkMonitor.kt$NetworkMonitor$IO InstanceOfCheckForException:LocalParticipant.kt$LocalParticipant$e is RpcError LargeClass:LocalParticipant.kt$LocalParticipant : ParticipantOutgoingDataStreamManagerRpcManager LargeClass:RTCEngine.kt$RTCEngine : Listener @@ -106,14 +83,9 @@ NestedBlockDepth:RTCEngine.kt$RTCEngine$private fun makeRTCConfig( serverResponse: Either<JoinResponse, ReconnectResponse>, connectOptions: ConnectOptions, ): RTCConfiguration NestedBlockDepth:Room.kt$Room$override suspend fun onPostReconnect(isFullReconnect: Boolean) NestedBlockDepth:SignalClient.kt$SignalClient$override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) - SwallowedException:EndpointTokenSource.kt$EndpointTokenSource.<no name provided>$e: Exception SwallowedException:FlowExt.kt$e: CancellationException SwallowedException:LocalVideoTrack.kt$LocalVideoTrack$e: Exception - SwallowedException:NetworkCallbackManager.kt$NetworkCallbackManagerImpl$e: IllegalArgumentException - SwallowedException:RemoteParticipant.kt$RemoteParticipant$e: Exception SwallowedException:TextureViewRenderer.kt$TextureViewRenderer$e: NotFoundException - ThrowingExceptionsWithoutMessageOrCause:LKDebugTree.kt$LKDebugTree$Throwable() - ThrowingExceptionsWithoutMessageOrCause:SignalClient.kt$SignalClient$Exception() TooManyFunctions:CommunicationWorkaround.kt$CommunicationWorkaroundImpl : CommunicationWorkaround TooManyFunctions:E2EEManager.kt$E2EEManager TooManyFunctions:IncomingDataStreamManager.kt$IncomingDataStreamManagerImpl : IncomingDataStreamManager @@ -135,17 +107,12 @@ TooManyFunctions:SimulcastVideoEncoderFactoryWrapper.kt$SimulcastVideoEncoderFactoryWrapper$StreamEncoderWrapper : VideoEncoder TooManyFunctions:SubscriberTransportObserver.kt$SubscriberTransportObserver : ObserverPeerConnectionStateObservable TooManyFunctions:TextureViewRenderer.kt$TextureViewRenderer : TextureViewCallbackSurfaceTextureListenerVideoSinkRendererEventsNotifier - UnnecessaryNotNullOperator:E2EEManager.kt$E2EEManager$room!! - UnnecessaryNotNullOperator:Room.kt$Room$e2eeManager!! - UnnecessarySafeCall:E2EEManager.kt$E2EEManager$(publication.track!! as LocalAudioTrack)?.sender - UnnecessarySafeCall:E2EEManager.kt$E2EEManager$(publication.track!! as LocalVideoTrack)?.sender UnsafeCallOnNullableType:AudioSwitchHandler.kt$AudioSwitchHandler$thread!! UnsafeCallOnNullableType:CustomAudioProcessingFactory.kt$CustomAudioProcessingFactory.AudioProcessingBridge$buffer!! UnsafeCallOnNullableType:DataPacketBuffer.kt$DataPacketBuffer$item!! UnsafeCallOnNullableType:E2EEManager.kt$E2EEManager$participant.identity!! UnsafeCallOnNullableType:E2EEManager.kt$E2EEManager$publication.track!! UnsafeCallOnNullableType:E2EEManager.kt$E2EEManager$rtpReceiver!! - UnsafeCallOnNullableType:E2EEManager.kt$E2EEManager$rtpSender!! UnsafeCallOnNullableType:E2EEManager.kt$E2EEManager$this.room!! UnsafeCallOnNullableType:EncodingUtils.kt$EncodingUtils$encodings.first().scalabilityMode!! UnsafeCallOnNullableType:LocalParticipant.kt$LocalParticipant$options.backupCodec!! diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/CoroutinesModule.kt b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/CoroutinesModule.kt index e35ff539e..9c844c179 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/CoroutinesModule.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/CoroutinesModule.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. @@ -25,6 +25,7 @@ import javax.inject.Named * @suppress */ @Module +@Suppress("InjectDispatcher") internal object CoroutinesModule { @Provides @Named(InjectionNames.DISPATCHER_DEFAULT) 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 1198b13d4..e8d78fa43 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 @@ -413,7 +413,7 @@ internal object RTCModule { fun videoHwAccel() = true @Provides - fun sdpFactory() = SdpFactory.getInstance() + fun sdpFactory(): SdpFactory = SdpFactory.getInstance() } /** diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/e2ee/E2EEManager.kt b/livekit-android-sdk/src/main/java/io/livekit/android/e2ee/E2EEManager.kt index cbbeb86eb..bc3fc77b4 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/e2ee/E2EEManager.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/e2ee/E2EEManager.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. @@ -48,7 +48,7 @@ constructor( dataPacketCryptorManagerFactory: DataPacketCryptorManager.Factory, ) { private var room: Room? = null - private var frameCryptors = mutableMapOf, FrameCryptor>() + private val frameCryptors = mutableMapOf, FrameCryptor>() private var algorithm: FrameCryptorAlgorithm = FrameCryptorAlgorithm.AES_GCM private lateinit var emitEvent: (roomEvent: RoomEvent) -> Unit? @@ -116,7 +116,7 @@ constructor( LKLog.i { "Receiver::onFrameCryptionStateChanged: $trackId, state: $state" } emitEvent( RoomEvent.TrackE2EEStateEvent( - room!!, + room, publication.track!!, publication, participant, @@ -138,15 +138,15 @@ constructor( } fun addPublishedTrack(track: Track, publication: TrackPublication, participant: LocalParticipant, room: Room) { - val rtpSender: RtpSender? = when (publication.track!!) { - is LocalAudioTrack -> (publication.track!! as LocalAudioTrack)?.sender - is LocalVideoTrack -> (publication.track!! as LocalVideoTrack)?.sender + val rtpSender: RtpSender = when (publication.track!!) { + is LocalAudioTrack -> (publication.track!! as LocalAudioTrack).sender + is LocalVideoTrack -> (publication.track!! as LocalVideoTrack).sender else -> { throw IllegalArgumentException("unsupported track type") } } ?: throw IllegalArgumentException("rtpSender is null") - val frameCryptor = addRtpSender(rtpSender!!, participant.identity!!, publication.sid, publication.track!!.kind.name.lowercase()) + val frameCryptor = addRtpSender(rtpSender, participant.identity!!, publication.sid, publication.track!!.kind.name.lowercase()) frameCryptor.setObserver { trackId, state -> LKLog.i { "Sender::onFrameCryptionStateChanged: $trackId, state: $state" } emitEvent( diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt index fb6f5a011..efae279a4 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.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. @@ -93,7 +93,7 @@ constructor( private var renegotiate = false - private var trackBitrates = mutableMapOf() + private val trackBitrates = mutableMapOf() private var isClosed = AtomicBoolean(false) private val latestOfferId = AtomicInteger(0) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/RegionUrlProvider.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/RegionUrlProvider.kt index 27e269238..765d1e0d6 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/RegionUrlProvider.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/RegionUrlProvider.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. @@ -47,7 +47,7 @@ constructor( private var regionSettings: RegionSettings? = null private var lastUpdateAt: Long = 0L private var settingsCacheTimeMs = 30000 - private var attemptedRegions = mutableSetOf() + private val attemptedRegions = mutableSetOf() fun isLKCloud() = serverUrl.isLKCloud() diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt index c6c28399d..cddf5eda4 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt @@ -346,7 +346,7 @@ constructor( val serverInfo: ServerInfo? get() = engine.serverInfo - private var sidToIdentity = mutableMapOf() + private val sidToIdentity = mutableMapOf() private var mutableActiveSpeakers by flowDelegate(emptyList()) @@ -364,7 +364,7 @@ constructor( private var regionUrlProvider: RegionUrlProvider? = null private var regionUrl: String? = null - private var transcriptionReceivedTimes = mutableMapOf() + private val transcriptionReceivedTimes = mutableMapOf() internal var isPrerecording by defaultsManager::isPrerecording @@ -1521,9 +1521,7 @@ constructor( * @suppress */ override fun onTrackUnpublished(publication: LocalTrackPublication, participant: LocalParticipant) { - e2eeManager?.let { e2eeManager -> - e2eeManager!!.removePublishedTrack(publication.track!!, publication, participant, this) - } + e2eeManager?.removePublishedTrack(publication.track!!, publication, participant, this) eventBus.postEvent(RoomEvent.TrackUnpublished(this, publication, participant), coroutineScope) } @@ -1556,9 +1554,7 @@ constructor( publication: RemoteTrackPublication, participant: RemoteParticipant, ) { - e2eeManager?.let { e2eeManager -> - e2eeManager!!.removeSubscribedTrack(track, publication, participant, this) - } + e2eeManager?.removeSubscribedTrack(track, publication, participant, this) eventBus.postEvent(RoomEvent.TrackUnsubscribed(this, track, publication, participant), coroutineScope) } diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/SignalClient.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/SignalClient.kt index 7c8889b0a..3e91af25a 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/SignalClient.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/SignalClient.kt @@ -866,6 +866,7 @@ constructor( * Can be reused afterwards. */ fun close(code: Int = CLOSE_REASON_NORMAL_CLOSURE, reason: String = "Normal Closure", shouldClearQueuedRequests: Boolean = true) { + @Suppress("ThrowingExceptionsWithoutMessageOrCause") LKLog.v(Exception()) { "Closing SignalClient: code = $code, reason = $reason" } isConnected = false isReconnecting = false diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/network/NetworkCallbackManager.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/network/NetworkCallbackManager.kt index 241f907fb..08ef77bd6 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/network/NetworkCallbackManager.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/network/NetworkCallbackManager.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. @@ -88,6 +88,7 @@ class NetworkCallbackManagerImpl( @Synchronized override fun unregisterCallback() { if (!isClosed.get() && isRegistered.compareAndSet(true, false)) { + @Suppress("SwallowedException") try { connectivityManager.unregisterNetworkCallback(networkCallback) } catch (e: IllegalArgumentException) { diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/participant/RemoteParticipant.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/participant/RemoteParticipant.kt index 3824d8acd..c0ac0e6e3 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/participant/RemoteParticipant.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/participant/RemoteParticipant.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. @@ -206,6 +206,7 @@ class RemoteParticipant( val track = publication.track if (track != null) { + @Suppress("SwallowedException") try { track.stop() } catch (e: Exception) { diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/track/LocalScreencastVideoTrack.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/track/LocalScreencastVideoTrack.kt index 9cf3b550e..b5dcaa573 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/track/LocalScreencastVideoTrack.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/track/LocalScreencastVideoTrack.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. @@ -210,7 +210,7 @@ constructor( /** * Needed to deal with circular dependency. */ - class MediaProjectionCallback() : MediaProjection.Callback() { + class MediaProjectionCallback : MediaProjection.Callback() { var track: Track? = null diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/util/CoroutineSdpObserver.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/util/CoroutineSdpObserver.kt index 6f839f2f4..0c56f9778 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/util/CoroutineSdpObserver.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/util/CoroutineSdpObserver.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. @@ -53,7 +53,7 @@ internal open class CoroutineSdpObserver : SdpObserver { } } - private var pendingCreate = mutableListOf>>() + private val pendingCreate = mutableListOf>>() private var setOutcome: Either? = null set(value) { @@ -75,7 +75,7 @@ internal open class CoroutineSdpObserver : SdpObserver { } } } - private var pendingSets = mutableListOf>>() + private val pendingSets = mutableListOf>>() override fun onCreateSuccess(sdp: SessionDescription?) { createOutcome = if (sdp == null) { diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/stats/NetworkMonitor.kt b/livekit-android-sdk/src/main/java/io/livekit/android/stats/NetworkMonitor.kt deleted file mode 100644 index efaf05eea..000000000 --- a/livekit-android-sdk/src/main/java/io/livekit/android/stats/NetworkMonitor.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 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.stats - -import android.content.Context -import android.net.TrafficStats -import io.livekit.android.util.LKLog -import kotlinx.coroutines.* -import kotlin.coroutines.CoroutineContext - -internal class NetworkMonitor(private val context: Context) { - - private lateinit var coroutineContext: CoroutineContext - private lateinit var scope: CoroutineScope - fun start() { - coroutineContext = SupervisorJob() + Dispatchers.IO - scope = CoroutineScope(coroutineContext) - scope.launch { - val uid = context.packageManager.getApplicationInfo(context.packageName, 0).uid - - var prevTxBytes = TrafficStats.getUidTxBytes(uid) - var emaTxBytes = 0L - while (this.isActive) { - val totalTxBytes = TrafficStats.getUidTxBytes(uid) - val intervalTxBytes = totalTxBytes - prevTxBytes - prevTxBytes = totalTxBytes - emaTxBytes = emaTxBytes / 2 + intervalTxBytes / 2 - - LKLog.v { "send rate: ${convertBytesToReadableString(emaTxBytes)}" } - - delay(1000) - } - } - } - - private fun convertBytesToReadableString(bytes: Long): String { - var num = bytes.toFloat() - var level = 0 - while (num >= 1024 && level < 2) { - num /= 1024 - level++ - } - - // MBps should be way more than enough. - val suffix = when (level) { - 0 -> "Bps" - 1 -> "kBps" - 2 -> "MBps" - else -> throw IllegalStateException("this shouldn't happen. level = $level") - } - - return "$num $suffix" - } - - fun stop() { - coroutineContext.cancel() - } -} diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/token/CachingTokenSource.kt b/livekit-android-sdk/src/main/java/io/livekit/android/token/CachingTokenSource.kt index fdedd0e73..32ba37b46 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/token/CachingTokenSource.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/token/CachingTokenSource.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 LiveKit, Inc. + * Copyright 2025-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. @@ -127,7 +127,7 @@ interface TokenStore { ) } -internal class InMemoryTokenStore() : TokenStore { +internal class InMemoryTokenStore : TokenStore { var item: TokenStore.Item? = null override suspend fun retrieve(): TokenStore.Item? = item diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/token/EndpointTokenSource.kt b/livekit-android-sdk/src/main/java/io/livekit/android/token/EndpointTokenSource.kt index b68886c0b..6f3cdd30a 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/token/EndpointTokenSource.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/token/EndpointTokenSource.kt @@ -17,6 +17,7 @@ package io.livekit.android.token import io.livekit.android.dagger.globalOkHttpClient +import io.livekit.android.util.LKLog import io.livekit.android.util.rethrowIfCancellationSignal import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.serialization.ExperimentalSerializationApi @@ -110,6 +111,7 @@ internal interface EndpointTokenSource : ConfigurableTokenSource { try { tokenResponse = snakeCaseJson.decodeFromString(bodyStr) } catch (e: Exception) { + LKLog.d(e) { "Unable to decode token source json with snake_case, trying camelCase." } } if (tokenResponse == null) { 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 index 7dcf1b87d..b5281bddb 100644 --- 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 @@ -41,6 +41,7 @@ open class LKDebugTree { val tag: String? get() = + @Suppress("ThrowingExceptionsWithoutMessageOrCause") Throwable() .stackTrace .first { it.className !in fqcnIgnore }