Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0ba709c
feat: add video moderation
rahul-lohra Nov 7, 2025
9157f28
Merge branch 'develop' into featture/rahullohra/video-moderation
rahul-lohra Nov 7, 2025
0eed603
feat: add video moderation
rahul-lohra Nov 7, 2025
ca00cec
feat: add video moderation
rahul-lohra Nov 11, 2025
4ac180e
feat: add video moderation
rahul-lohra Nov 11, 2025
ae13786
Make ModerationWarningUiContainer as public api
rahul-lohra Nov 11, 2025
d7529df
Merge branch 'develop' into featture/rahullohra/video-moderation
rahul-lohra Nov 11, 2025
d97cf30
remove dependency of stream-video-android-filters-video from android-…
rahul-lohra Nov 11, 2025
8680769
remove all public-apis
rahul-lohra Nov 11, 2025
983f1bb
revert BlurIntensity enum
rahul-lohra Nov 11, 2025
71b5332
revert BlurIntensity enum
rahul-lohra Nov 11, 2025
91ef365
revert changes in strings.xml
rahul-lohra Nov 11, 2025
1f55bbc
sdk will render moderation warning ui and will blur the video
rahul-lohra Nov 12, 2025
01a6a6b
sdk will render moderation warning ui and will blur the video
rahul-lohra Nov 12, 2025
fd96aa0
sdk will render moderation warning ui and will blur the video
rahul-lohra Nov 12, 2025
900a783
Add default moderation filter
aleksandar-apostolov Nov 12, 2025
7dcac47
Spotless
aleksandar-apostolov Nov 12, 2025
a1a63d7
update
rahul-lohra Nov 12, 2025
f499d49
Spotless
aleksandar-apostolov Nov 12, 2025
8082c8a
Merge remote-tracking branch 'origin/featture/rahullohra/video-modera…
aleksandar-apostolov Nov 12, 2025
2ff7e77
refactor all moderation related configuration into ModerationConfig
rahul-lohra Nov 12, 2025
d89fa60
Merge remote-tracking branch 'origin/featture/rahullohra/video-modera…
rahul-lohra Nov 12, 2025
11df0ac
refactor all moderation related configuration into ModerationConfig
rahul-lohra Nov 12, 2025
5ce5293
refactor all moderation related configuration into ModerationConfig
rahul-lohra Nov 12, 2025
129d851
refactor
rahul-lohra Nov 12, 2025
c2ad729
add ut and comments
rahul-lohra Nov 12, 2025
da0a2af
add ut and comments
rahul-lohra Nov 12, 2025
fdd6381
minor changes
rahul-lohra Nov 13, 2025
e3262a6
Merge branch 'develop' into featture/rahullohra/video-moderation
rahul-lohra Nov 13, 2025
19ce5e2
Make blurring a part of core-sdk
rahul-lohra Nov 13, 2025
06001c5
rename methods
rahul-lohra Nov 13, 2025
6d3d9a2
add token repository
rahul-lohra Nov 27, 2025
9428b6e
add expiry-time in demo-app
rahul-lohra Nov 27, 2025
8d9b961
spotless and apidump
rahul-lohra Nov 27, 2025
2f532f7
single thread coordinator socket
rahul-lohra Dec 1, 2025
90f15cb
single thread coordinator socket
rahul-lohra Dec 1, 2025
b2c5f5c
single thread coordinator socket
rahul-lohra Dec 1, 2025
3a5df3d
single thread coordinator socket
rahul-lohra Dec 1, 2025
5e13b2b
Merge branch 'develop' into bugfix/rahullohra/coordinator-reconnect-j…
rahul-lohra Dec 8, 2025
150e3a4
refactor api files
rahul-lohra Dec 8, 2025
8b4dfc8
refactor
rahul-lohra Dec 8, 2025
22640f4
1. increase token expiry time
rahul-lohra Dec 8, 2025
ff72ed3
1. increase token expiry time
rahul-lohra Dec 8, 2025
a8bc660
1. Update token provider
rahul-lohra Dec 8, 2025
8935374
chore: remove comments
rahul-lohra Dec 8, 2025
2f08110
chore: improve token provider
rahul-lohra Dec 8, 2025
248c1e8
chore: update FakeTokenManager with PersistingTokenProvider
rahul-lohra Dec 8, 2025
a088749
chore: Improve socket disconnection logging and add TODO
rahul-lohra Dec 8, 2025
d97ae9a
Merge branch 'refs/heads/develop' into bugfix/rahullohra/coordinator-…
rahul-lohra Dec 10, 2025
d591a85
remove comments
rahul-lohra Dec 10, 2025
92f6c38
chore: remove logs and commented out code
rahul-lohra Dec 10, 2025
aa840c6
chore: remove token expiry parameter from auth
rahul-lohra Dec 10, 2025
2ca823d
chore: log network requests to system.out for easier debugging
rahul-lohra Dec 10, 2025
4f88ddc
chore: log network requests to system.out for easier debugging
rahul-lohra Dec 10, 2025
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
3 changes: 3 additions & 0 deletions demo-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ dependencies {

implementation(libs.audioswitch)

// Logging
implementation(libs.okhttp.logging)

// Also Leak Canary added in the previous block

// Instrumentation tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
package io.getstream.video.android.data.services.stream

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import io.getstream.log.streamLog
import io.getstream.video.android.model.User
import io.getstream.video.android.models.UserCredentials
import io.getstream.video.android.models.builtInCredentials
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.create
import retrofit2.http.GET
Expand All @@ -38,10 +41,19 @@ fun interface StreamService {
private const val BASE_URL = "https://pronto.getstream.io/"

private val json = Json { ignoreUnknownKeys = true }

private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(
HttpLoggingInterceptor {
streamLog(tag = "Video:Http") { it }
}.apply {
level = HttpLoggingInterceptor.Level.BODY
},
)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.client(okHttpClient)
.build()

private val serviceInstance = retrofit.create<StreamService>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import io.getstream.video.android.util.config.AppConfig
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.runBlocking

public enum class InitializedState {
NOT_STARTED, RUNNING, FINISHED, FAILED
Expand Down Expand Up @@ -197,7 +198,18 @@ object StreamVideoInitHelper {

chatClient.connectUser(
user = chatUser,
token = token,
tokenProvider = object : io.getstream.chat.android.client.token.TokenProvider {
override fun loadToken(): String {
return runBlocking {
val email = user.custom?.get("email")
val authData = StreamService.instance.getAuthData(
environment = AppConfig.currentEnvironment.value!!.env,
userId = email,
)
authData.token
}
}
},
).enqueue()
}

Expand Down Expand Up @@ -303,10 +315,12 @@ object StreamVideoInitHelper {
),
tokenProvider = object : TokenProvider {
override suspend fun loadToken(): String {
val email = user.custom?.get("email")
val userEmail = user.custom?.get("email")
val userId = user.id
val userIdForTokenRenewal = if (userEmail.isNullOrEmpty()) userId else userEmail
val authData = StreamService.instance.getAuthData(
environment = AppConfig.currentEnvironment.value!!.env,
userId = email,
userId = userIdForTokenRenewal,
)
return authData.token
}
Expand Down
16 changes: 12 additions & 4 deletions stream-video-android-core/api/stream-video-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -13118,9 +13118,17 @@ public abstract interface class io/getstream/video/android/core/socket/common/to
public abstract fun loadToken (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class io/getstream/video/android/core/socket/common/token/TokenRepository {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getToken ()Ljava/lang/String;
public final fun updateToken (Ljava/lang/String;)V
}

public class io/getstream/video/android/core/socket/coordinator/CoordinatorSocketConnection : io/getstream/video/android/core/socket/common/SocketListener, io/getstream/video/android/core/socket/common/SocketActions {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;Lio/getstream/video/android/core/socket/common/token/TokenRepository;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;Lio/getstream/video/android/core/socket/common/token/TokenRepository;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun connect (Lio/getstream/video/android/model/User;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public synthetic fun connect (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun connectionId ()Lkotlinx/coroutines/flow/StateFlow;
Expand Down Expand Up @@ -13327,8 +13335,8 @@ public final class io/getstream/video/android/core/socket/coordinator/state/Vide

public final class io/getstream/video/android/core/socket/sfu/SfuSocketConnection : io/getstream/video/android/core/socket/common/SocketListener, io/getstream/video/android/core/socket/common/SocketActions {
public static final field Companion Lio/getstream/video/android/core/socket/sfu/SfuSocketConnection$Companion;
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;Lio/getstream/video/android/core/socket/common/token/TokenRepository;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/Lifecycle;Lio/getstream/video/android/core/socket/common/token/TokenProvider;Lio/getstream/video/android/core/socket/common/token/TokenRepository;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun connect (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun connect (Lstream/video/sfu/event/JoinRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun connectionId ()Lkotlinx/coroutines/flow/StateFlow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ import io.getstream.video.android.core.permission.android.DefaultStreamPermissio
import io.getstream.video.android.core.permission.android.StreamPermissionCheck
import io.getstream.video.android.core.socket.common.scope.ClientScope
import io.getstream.video.android.core.socket.common.scope.UserScope
import io.getstream.video.android.core.socket.common.token.ConstantTokenProvider
import io.getstream.video.android.core.socket.common.token.RepositoryTokenProvider
import io.getstream.video.android.core.socket.common.token.TokenProvider
import io.getstream.video.android.core.socket.common.token.TokenRepository
import io.getstream.video.android.core.sounds.RingingCallVibrationConfig
import io.getstream.video.android.core.sounds.Sounds
import io.getstream.video.android.core.sounds.defaultResourcesRingingConfig
Expand Down Expand Up @@ -95,6 +96,7 @@ import java.net.ConnectException
* @see ClientState.connection
*
*/

public class StreamVideoBuilder @JvmOverloads constructor(
context: Context,
private val apiKey: ApiKey,
Expand All @@ -106,7 +108,7 @@ public class StreamVideoBuilder @JvmOverloads constructor(
object : TokenProvider {
override suspend fun loadToken(): String = legacy.invoke(null)
}
} ?: ConstantTokenProvider(token),
} ?: RepositoryTokenProvider(tokenRepository),
private val loggingLevel: LoggingLevel = LoggingLevel(),
private val notificationConfig: NotificationConfig = NotificationConfig(),
private val ringNotification: ((call: Call) -> Notification?)? = null,
Expand Down Expand Up @@ -214,7 +216,7 @@ public class StreamVideoBuilder @JvmOverloads constructor(

// Android JSR-310 backport backport
AndroidThreeTen.init(context)

tokenRepository.updateToken(token)
// This connection module class exposes the connections to the various retrofit APIs.
val coordinatorConnectionModule = CoordinatorConnectionModule(
context = context,
Expand All @@ -225,9 +227,9 @@ public class StreamVideoBuilder @JvmOverloads constructor(
loggingLevel = loggingLevel,
user = user,
apiKey = apiKey,
userToken = token,
tokenProvider = tokenProvider,
lifecycle = lifecycle,
tokenRepository = tokenRepository,
)

val deviceTokenStorage = DeviceTokenStorage(context)
Expand Down Expand Up @@ -272,6 +274,7 @@ public class StreamVideoBuilder @JvmOverloads constructor(
vibrationConfig = vibrationConfig,
enableStereoForSubscriber = enableStereoForSubscriber,
telecomConfig = telecomConfig,
tokenRepository = tokenRepository,
)

if (user.type == UserType.Guest) {
Expand Down Expand Up @@ -348,6 +351,11 @@ public class StreamVideoBuilder @JvmOverloads constructor(
}
}

/**
* Refactor Later
*/
internal val tokenRepository = TokenRepository("")

sealed class GEO {
/** Run calls over our global edge network, this is the default and right for most applications */
object GlobalEdgeNetwork : GEO()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ import io.getstream.video.android.core.permission.android.DefaultStreamPermissio
import io.getstream.video.android.core.permission.android.StreamPermissionCheck
import io.getstream.video.android.core.socket.ErrorResponse
import io.getstream.video.android.core.socket.common.scope.ClientScope
import io.getstream.video.android.core.socket.common.token.ConstantTokenProvider
import io.getstream.video.android.core.socket.common.token.RepositoryTokenProvider
import io.getstream.video.android.core.socket.common.token.TokenProvider
import io.getstream.video.android.core.socket.common.token.TokenRepository
import io.getstream.video.android.core.socket.coordinator.state.VideoSocketState
import io.getstream.video.android.core.sounds.CallSoundAndVibrationPlayer
import io.getstream.video.android.core.sounds.RingingCallVibrationConfig
Expand Down Expand Up @@ -161,7 +162,8 @@ internal class StreamVideoClient internal constructor(
internal var token: String,
private val lifecycle: Lifecycle,
internal val coordinatorConnectionModule: CoordinatorConnectionModule,
internal val tokenProvider: TokenProvider = ConstantTokenProvider(token),
internal val tokenRepository: TokenRepository,
internal val tokenProvider: TokenProvider = RepositoryTokenProvider(tokenRepository),
internal val streamNotificationManager: StreamNotificationManager,
internal val enableCallNotificationUpdates: Boolean,
internal val callServiceConfigRegistry: CallServiceConfigRegistry = CallServiceConfigRegistry(),
Expand Down Expand Up @@ -273,6 +275,7 @@ internal class StreamVideoClient internal constructor(
// Retry once with a new token if the token is expired
if (e.isAuthError()) {
val newToken = tokenProvider.loadToken()
tokenRepository.updateToken(newToken)
token = newToken
coordinatorConnectionModule.updateToken(newToken)
apiCall()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import io.getstream.video.android.core.model.VideoTrack
import io.getstream.video.android.core.model.toPeerType
import io.getstream.video.android.core.socket.common.VideoParser
import io.getstream.video.android.core.socket.common.parser2.MoshiVideoParser
import io.getstream.video.android.core.socket.common.token.TokenRepository
import io.getstream.video.android.core.socket.sfu.state.SfuSocketState
import io.getstream.video.android.core.toJson
import io.getstream.video.android.core.trace.PeerConnectionTraceKey
Expand Down Expand Up @@ -236,12 +237,12 @@ public class RtcSession internal constructor(
apiUrl = sfuUrl,
wssUrl = sfuWsUrl,
connectionTimeoutInMs = 2000L,
userToken = sfuToken,
lifecycle = lifecycle,
onSignalingLost = { error ->
call.debug.fastReconnect()
},
tracer = sfuTracer,
tokenRepository = TokenRepository(sfuToken),
)
},
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ internal interface ConnectionModuleDeclaration<Api, SocketConnection, Http : OkH
*/
val loggingLevel: LoggingLevel get() = LoggingLevel()

/**
* The user token.
*/
val userToken: Token

/**
* The lifecycle of the application.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.getstream.video.android.core.internal.module

import io.getstream.video.android.core.socket.common.token.TokenRepository
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
Expand All @@ -25,7 +26,7 @@ import java.io.IOException
*/
internal class CoordinatorAuthInterceptor(
var apiKey: String,
var token: String,
val tokenRepository: TokenRepository,
var authType: String = "jwt",
) : Interceptor {

Expand All @@ -43,7 +44,7 @@ internal class CoordinatorAuthInterceptor(

val updated = original.newBuilder()
.url(updatedUrl)
.addHeader(HEADER_AUTHORIZATION, token)
.addHeader(HEADER_AUTHORIZATION, tokenRepository.getToken())
.header(STREAM_AUTH_TYPE, authType)
.build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ import android.net.ConnectivityManager
import androidx.lifecycle.Lifecycle
import io.getstream.android.video.generated.apis.ProductvideoApi
import io.getstream.android.video.generated.infrastructure.Serializer
import io.getstream.log.streamLog
import io.getstream.video.android.core.header.HeadersUtil
import io.getstream.video.android.core.internal.network.NetworkStateProvider
import io.getstream.video.android.core.logging.LoggingLevel
import io.getstream.video.android.core.socket.common.scope.UserScope
import io.getstream.video.android.core.socket.common.token.TokenProvider
import io.getstream.video.android.core.socket.common.token.TokenRepository
import io.getstream.video.android.core.socket.coordinator.CoordinatorSocketConnection
import io.getstream.video.android.core.trace.Tracer
import io.getstream.video.android.model.ApiKey
import io.getstream.video.android.model.User
import io.getstream.video.android.model.UserToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
Expand All @@ -47,19 +49,19 @@ internal class CoordinatorConnectionModule(
context: Context,
tokenProvider: TokenProvider,
user: User,
val tokenRepository: TokenRepository,
override val scope: CoroutineScope,
// Common API
override val apiUrl: String,
override val wssUrl: String,
override val connectionTimeoutInMs: Long,
override val loggingLevel: LoggingLevel = LoggingLevel(),
override val apiKey: ApiKey,
override val userToken: UserToken,
override val lifecycle: Lifecycle,
override val tracer: Tracer = Tracer("coordinator"),
) : ConnectionModuleDeclaration<ProductvideoApi, CoordinatorSocketConnection, OkHttpClient, UserToken> {
// Internals
private val authInterceptor = CoordinatorAuthInterceptor(apiKey, userToken)
private val authInterceptor = CoordinatorAuthInterceptor(apiKey, tokenRepository)
private val retrofit: Retrofit by lazy {
Retrofit.Builder().baseUrl(apiUrl)
.addConverterFactory(ScalarsConverterFactory.create())
Expand All @@ -73,8 +75,8 @@ internal class CoordinatorConnectionModule(
HeadersInterceptor(HeadersUtil()),
)
.addInterceptor(authInterceptor).addInterceptor(
HttpLoggingInterceptor {
streamLog(tag = "Video:Http") { it }
HttpLoggingInterceptor { message ->
println(message)
}.apply {
level = loggingLevel.httpLoggingLevel.level
},
Expand All @@ -96,17 +98,17 @@ internal class CoordinatorConnectionModule(
apiKey = apiKey,
url = wssUrl,
user = user,
token = userToken,
token = tokenRepository.getToken(),
httpClient = http,
networkStateProvider = networkStateProvider,
scope = scope,
scope = UserScope(context = scope.coroutineContext + Dispatchers.IO.limitedParallelism(1)),
lifecycle = lifecycle,
tokenProvider = tokenProvider,
tokenRepository = tokenRepository,
)

override fun updateToken(token: UserToken) {
socketConnection.updateToken(token)
authInterceptor.token = token
tokenRepository.updateToken(token)
}

override fun updateAuthType(authType: String) {
Expand Down
Loading
Loading