diff --git a/demo-app/src/main/kotlin/io/getstream/video/android/App.kt b/demo-app/src/main/kotlin/io/getstream/video/android/App.kt index 58f5a473f57..2c2659077cc 100644 --- a/demo-app/src/main/kotlin/io/getstream/video/android/App.kt +++ b/demo-app/src/main/kotlin/io/getstream/video/android/App.kt @@ -28,6 +28,7 @@ import io.getstream.video.android.core.moderations.CallModerationConstants import io.getstream.video.android.data.model.PolicyViolationUiData import io.getstream.video.android.datastore.delegate.StreamUserDataStore import io.getstream.video.android.tooling.util.StreamBuildFlavorUtil +import io.getstream.video.android.ui.FailureInjectorImpl import io.getstream.video.android.util.StreamVideoInitHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -80,6 +81,12 @@ class App : Application() { observePolicyViolation() observeCallReadyToJoin() + injectFault() + } + + private fun injectFault() { + val faultInjector = FailureInjectorImpl() + StreamVideo.instanceOrNull()?.state?.failureInjector = faultInjector } private fun observeCallReadyToJoin() { diff --git a/demo-app/src/main/kotlin/io/getstream/video/android/CallActivity.kt b/demo-app/src/main/kotlin/io/getstream/video/android/CallActivity.kt index bf4df4beff9..31358b8d887 100644 --- a/demo-app/src/main/kotlin/io/getstream/video/android/CallActivity.kt +++ b/demo-app/src/main/kotlin/io/getstream/video/android/CallActivity.kt @@ -67,6 +67,7 @@ class CallActivity : ComposeStreamCallActivity() { override val uiDelegate: StreamActivityUiDelegate = StreamDemoUiDelegate() var observeCallReadyToJoinJob: Job? = null var observeRingingJob: Job? = null + var isNavigatingBackToMainScreen = false private val previousRingingStates = ConcurrentHashMap.newKeySet() override val callJoinInterceptor = DemoCallJoinInterceptor(previousRingingStates) @@ -194,6 +195,7 @@ class CallActivity : ComposeStreamCallActivity() { private fun StreamCallActivity.goBackToMainScreen() { if (!isFinishing) { + (this as CallActivity).isNavigatingBackToMainScreen = true val intent = Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } @@ -208,5 +210,13 @@ class CallActivity : ComposeStreamCallActivity() { observeCallReadyToJoinJob?.cancel() observeRingingJob?.cancel() previousRingingStates.clear() + + if (!isNavigatingBackToMainScreen) { + isNavigatingBackToMainScreen = true + val intent = Intent(this, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + } + startActivity(intent) + } } } diff --git a/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorImpl.kt b/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorImpl.kt new file mode 100644 index 00000000000..be360ebd310 --- /dev/null +++ b/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorImpl.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.ui + +import io.getstream.result.Error +import io.getstream.video.android.core.faultinjector.FailureInjector +import io.getstream.video.android.core.faultinjector.FailureKey +import retrofit2.HttpException +import retrofit2.Response + +internal class FailureInjectorImpl : FailureInjector { + private val faultCounts = mutableMapOf() + + override fun enable(key: FailureKey) { + if ((faultCounts[key] ?: 0) == 0) faultCounts[key] = 1 + } + + override fun disable(key: FailureKey) { + faultCounts[key] = 0 + } + + override fun setEnabled(key: FailureKey, enabled: Boolean) { + if (enabled) enable(key) else disable(key) + } + + override fun isEnabled(key: FailureKey): Boolean { + return (faultCounts[key] ?: 0) > 0 + } + + override fun setCount(key: FailureKey, count: Int) { + faultCounts[key] = count + } + + override fun getCount(key: FailureKey): Int { + return faultCounts[key] ?: 0 + } + + override fun clear() { + faultCounts.clear() + } + + override fun throwDebugFault(key: FailureKey) { + val count = faultCounts[key] ?: 0 + if (count > 0) { + faultCounts[key] = count - 1 + throw when (key) { + FailureKey.FAIL_LOCATION -> HttpException( + Response.error( + 100, + okhttp3.ResponseBody.create(null, ""), + ), + ) + else -> RuntimeException("Failure injected: $key") + } + } + } + + override fun sendFailResult(key: FailureKey): io.getstream.result.Result.Failure { + val count = faultCounts[key] ?: 0 + if (count > 0) { + faultCounts[key] = count - 1 + } + val message = when (key) { + FailureKey.FAIL_JOIN_CALL -> "Unable to resolve host" + else -> "Failure injected: $key" + } + return io.getstream.result.Result.Failure( + Error.ThrowableError( + message, + RuntimeException(message), + ), + ) + } +} diff --git a/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt b/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt new file mode 100644 index 00000000000..3d539da7bb1 --- /dev/null +++ b/demo-app/src/main/kotlin/io/getstream/video/android/ui/FailureInjectorUi.kt @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import io.getstream.result.Error +import io.getstream.video.android.compose.theme.VideoTheme +import io.getstream.video.android.core.faultinjector.FailureInjector +import io.getstream.video.android.core.faultinjector.FailureKey +import io.getstream.video.android.core.internal.InternalStreamVideoApi + +private val countOptions = listOf(0, 1, 2, 3, 5, 10) + +@OptIn(InternalStreamVideoApi::class) +@Composable +fun FailureInjectorUi( + modifier: Modifier = Modifier, + failureInjector: FailureInjector, + onClose: () -> Unit, +) { + val countState = remember { + mutableStateMapOf().apply { + FailureKey.entries.forEach { key -> put(key, failureInjector.getCount(key)) } + } + } + + Column( + modifier = Modifier + .fillMaxSize() + .background(VideoTheme.colors.baseSheetPrimary), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .background(VideoTheme.colors.baseSheetSecondary) + .padding(horizontal = 16.dp, vertical = 14.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = "Failure Injection", + style = VideoTheme.typography.subtitleM, + color = VideoTheme.colors.basePrimary, + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = "Clear all", + modifier = Modifier.clickable { + failureInjector.clear() + FailureKey.entries.forEach { key -> countState[key] = 0 } + }, + style = VideoTheme.typography.bodyS, + color = VideoTheme.colors.brandPrimary, + ) + + Box( + modifier = Modifier + .background( + color = VideoTheme.colors.baseSheetTertiary, + shape = RoundedCornerShape(999.dp), + ) + .clickable(onClick = onClose) + .padding(8.dp), + ) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Close", + tint = VideoTheme.colors.basePrimary, + ) + } + } + } + + LazyColumn( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + items(FailureKey.entries) { key -> + val count = countState[key] ?: 0 + var expanded by remember { mutableStateOf(false) } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = key.name, + style = VideoTheme.typography.bodyM, + color = VideoTheme.colors.basePrimary, + modifier = Modifier.weight(1f), + ) + + Box { + Row( + modifier = Modifier + .background( + color = VideoTheme.colors.baseSheetTertiary, + shape = RoundedCornerShape(6.dp), + ) + .clickable { expanded = true } + .padding(horizontal = 12.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = "$count", + style = VideoTheme.typography.bodyM, + color = if (count > 0) VideoTheme.colors.brandPrimary else VideoTheme.colors.baseSecondary, + ) + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + tint = VideoTheme.colors.baseSecondary, + ) + } + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + countOptions.forEach { option -> + DropdownMenuItem( + onClick = { + countState[key] = option + failureInjector.setCount(key, option) + expanded = false + }, + ) { + Text( + text = "$option", + style = VideoTheme.typography.bodyM, + color = if (option > 0) VideoTheme.colors.brandPrimary else VideoTheme.colors.basePrimary, + ) + } + } + } + } + } + } + } + + Box( + modifier = Modifier + .fillMaxWidth() + .background(VideoTheme.colors.baseSheetSecondary) + .padding(horizontal = 16.dp, vertical = 12.dp), + ) { + Button( + onClick = onClose, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = VideoTheme.colors.brandPrimary, + contentColor = VideoTheme.colors.baseSheetPrimary, + ), + ) { + Text( + text = "OK", + style = VideoTheme.typography.labelL, + ) + } + } + } +} + +@Preview +@Composable +fun FaultInjectorUiDemo() { + VideoTheme { + FailureInjectorUi( + Modifier, + object : FailureInjector { + override fun enable(key: FailureKey) {} + + override fun disable(key: FailureKey) {} + + override fun setEnabled(key: FailureKey, enabled: Boolean) {} + + override fun isEnabled(key: FailureKey): Boolean = false + + override fun setCount(key: FailureKey, count: Int) {} + + override fun getCount(key: FailureKey): Int = 0 + + override fun clear() {} + + override fun throwDebugFault(key: FailureKey) {} + + override fun sendFailResult( + key: FailureKey, + ): io.getstream.result.Result.Failure { + return io.getstream.result.Result.Failure( + Error.GenericError("Failure injected: $key"), + ) + } + }, + ) {} + } +} diff --git a/demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt b/demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt index 7c31cf4367e..767b22fcce8 100644 --- a/demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt +++ b/demo-app/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt @@ -50,6 +50,7 @@ import androidx.compose.material.icons.filled.Call import androidx.compose.material.icons.filled.QrCodeScanner import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.VideoCall +import androidx.compose.material.icons.filled.Warning import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -98,11 +99,13 @@ import io.getstream.video.android.compose.ui.components.base.StreamButton import io.getstream.video.android.compose.ui.components.base.StreamDialogPositiveNegative import io.getstream.video.android.compose.ui.components.base.StreamIconToggleButton import io.getstream.video.android.compose.ui.components.base.StreamTextField +import io.getstream.video.android.core.StreamVideo import io.getstream.video.android.defaultCallId import io.getstream.video.android.mock.StreamPreviewDataUtils import io.getstream.video.android.mock.previewUsers import io.getstream.video.android.model.User import io.getstream.video.android.tooling.util.StreamBuildFlavorUtil +import io.getstream.video.android.ui.FailureInjectorUi import io.getstream.video.android.ui.LogFilesScreen import io.getstream.video.android.ui.SingleButtonDialog import io.getstream.video.android.util.config.AppConfig @@ -125,6 +128,8 @@ fun CallJoinScreen( val isNetworkAvailable by callJoinViewModel.isNetworkAvailable.collectAsStateWithLifecycle() var renderLogsFileUi by remember { mutableStateOf(false) } + var renderFaultInjectorUi by remember { mutableStateOf(false) } + var renderNetworkSettingsUi by remember { mutableStateOf(false) } HandleCallJoinUiState( callJoinUiState = uiState, @@ -151,6 +156,9 @@ fun CallJoinScreen( onLogsClick = { renderLogsFileUi = true }, + onFaultInjectionClick = { + renderFaultInjectorUi = true + }, ) CallJoinBody( @@ -195,6 +203,18 @@ fun CallJoinScreen( renderLogsFileUi = false }) } + + if (renderFaultInjectorUi) { + val faultInjector = StreamVideo.instanceOrNull()?.state?.failureInjector + faultInjector?.let { + FailureInjectorUi(failureInjector = it, onClose = { + renderFaultInjectorUi = false + }) + } + } + + if (renderNetworkSettingsUi) { + } } @Composable @@ -224,6 +244,7 @@ private fun CallJoinHeader( onDirectCallClick: () -> Unit, onSignOutClick: () -> Unit, onLogsClick: () -> Unit, + onFaultInjectionClick: () -> Unit, ) { Row( modifier = Modifier @@ -340,6 +361,19 @@ private fun CallJoinHeader( }, ) Spacer(modifier = Modifier.width(5.dp)) + StreamButton( + modifier = Modifier + .fillMaxWidth() + .testTag("Stream_FaultInjectorButton"), + icon = Icons.Filled.Warning, + style = VideoTheme.styles.buttonStyles.tertiaryButtonStyle(), + text = stringResource(id = R.string.failure_injector), + onClick = { + showMenu = false + onFaultInjectionClick() + }, + ) + Spacer(modifier = Modifier.width(5.dp)) StreamButton( modifier = Modifier .fillMaxWidth() @@ -743,6 +777,6 @@ private fun CallJoinScreenLandscapePreview() { private fun CallJoinScreenHeader() { StreamPreviewDataUtils.initializeStreamVideo(LocalContext.current) VideoTheme { - CallJoinHeader(previewUsers[0], false, true, {}, {}, {}, {}) + CallJoinHeader(previewUsers[0], false, true, {}, {}, {}, {}, {}) } } diff --git a/demo-app/src/main/res/values/strings.xml b/demo-app/src/main/res/values/strings.xml index 1e5eedfce88..c500237e120 100644 --- a/demo-app/src/main/res/values/strings.xml +++ b/demo-app/src/main/res/values/strings.xml @@ -30,6 +30,7 @@ Contact us Sign out Share Logs + Fault Injector Start a new call, join a meeting by \nentering the call ID or by scanning \na QR code. Join Call Scan QR meeting code diff --git a/stream-video-android-core/api/stream-video-android-core.api b/stream-video-android-core/api/stream-video-android-core.api index 01016ec7295..b5bfcad33a8 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -48,6 +48,8 @@ public abstract interface class io/getstream/android/video/generated/apis/Produc public static synthetic fun queryCallParticipants$default (Lio/getstream/android/video/generated/apis/ProductvideoApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public abstract fun queryCallSessionParticipantStats (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun queryCallSessionParticipantStats$default (Lio/getstream/android/video/generated/apis/ProductvideoApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public abstract fun queryCallSessionStats (Lio/getstream/android/video/generated/models/QueryCallSessionStatsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun queryCallSessionStats (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun queryCallStats (Lio/getstream/android/video/generated/models/QueryCallStatsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun queryCallStats (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun queryCalls (Ljava/lang/String;Lio/getstream/android/video/generated/models/QueryCallsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -56,7 +58,9 @@ public abstract interface class io/getstream/android/video/generated/apis/Produc public static synthetic fun queryCalls$default (Lio/getstream/android/video/generated/apis/ProductvideoApi;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public abstract fun rejectCall (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/RejectCallRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun rejectCall (Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun reportClientCallEvent (Lio/getstream/android/video/generated/models/ReportClientEventRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun requestPermission (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/RequestPermissionRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun resolveSipAuth (Lio/getstream/android/video/generated/models/ResolveSipAuthRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun resolveSipInbound (Lio/getstream/android/video/generated/models/ResolveSipInboundRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun ringCall (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/RingCallRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun ringCall (Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -667,22 +671,24 @@ public final class io/getstream/android/video/generated/models/CallDurationRepor } public final class io/getstream/android/video/generated/models/CallEndedEvent : io/getstream/android/video/generated/models/VideoEvent, io/getstream/android/video/generated/models/WSCallEvent { - public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/UserResponse;)V - public synthetic fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/UserResponse;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/UserResponse;)V + public synthetic fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/UserResponse;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lorg/threeten/bp/OffsetDateTime; public final fun component3 ()Lio/getstream/android/video/generated/models/CallResponse; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; - public final fun component6 ()Lio/getstream/android/video/generated/models/UserResponse; - public final fun copy (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/UserResponse;)Lio/getstream/android/video/generated/models/CallEndedEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallEndedEvent;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/UserResponse;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallEndedEvent; + public final fun component6 ()Ljava/util/List; + public final fun component7 ()Lio/getstream/android/video/generated/models/UserResponse; + public final fun copy (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/UserResponse;)Lio/getstream/android/video/generated/models/CallEndedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallEndedEvent;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/UserResponse;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallEndedEvent; public fun equals (Ljava/lang/Object;)Z public final fun getCall ()Lio/getstream/android/video/generated/models/CallResponse; public fun getCallCID ()Ljava/lang/String; public final fun getCallCid ()Ljava/lang/String; public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; public fun getEventType ()Ljava/lang/String; + public final fun getMembers ()Ljava/util/List; public final fun getReason ()Ljava/lang/String; public final fun getType ()Ljava/lang/String; public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponse; @@ -853,6 +859,24 @@ public final class io/getstream/android/video/generated/models/CallIngressRespon public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/CallLevelEventPayload { + public fun (Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()I + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;)Lio/getstream/android/video/generated/models/CallLevelEventPayload; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallLevelEventPayload;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallLevelEventPayload; + public fun equals (Ljava/lang/Object;)Z + public final fun getEventType ()Ljava/lang/String; + public final fun getPayload ()Ljava/util/Map; + public final fun getTimestamp ()I + public final fun getUserId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/CallLiveStartedEvent : io/getstream/android/video/generated/models/VideoEvent, io/getstream/android/video/generated/models/WSCallEvent { public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallResponse;Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; @@ -2026,43 +2050,59 @@ public final class io/getstream/android/video/generated/models/CallStatsParticip } public final class io/getstream/android/video/generated/models/CallStatsParticipantCounts { - public fun (IIIIIILjava/lang/Integer;)V - public synthetic fun (IIIIIILjava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (IIIIIIILjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)V + public synthetic fun (IIIIIIILjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()I + public final fun component10 ()Ljava/lang/Integer; + public final fun component11 ()Ljava/lang/Integer; + public final fun component12 ()Ljava/lang/Integer; + public final fun component13 ()Ljava/lang/Integer; public final fun component2 ()I public final fun component3 ()I public final fun component4 ()I public final fun component5 ()I public final fun component6 ()I - public final fun component7 ()Ljava/lang/Integer; - public final fun copy (IIIIIILjava/lang/Integer;)Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;IIIIIILjava/lang/Integer;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; + public final fun component7 ()I + public final fun component8 ()Ljava/lang/Integer; + public final fun component9 ()Ljava/lang/Integer; + public final fun copy (IIIIIIILjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;IIIIIIILjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; public fun equals (Ljava/lang/Object;)Z + public final fun getAverageJitterMs ()Ljava/lang/Integer; + public final fun getAverageLatencyMs ()Ljava/lang/Integer; + public final fun getCallEventCount ()Ljava/lang/Integer; + public final fun getCqScore ()Ljava/lang/Integer; public final fun getLiveSessions ()I + public final fun getMaxFreezesDurationMs ()Ljava/lang/Integer; public final fun getParticipants ()I public final fun getPeakConcurrentSessions ()I public final fun getPeakConcurrentUsers ()I public final fun getPublishers ()I public final fun getSessions ()I + public final fun getSfusUsed ()I public final fun getTotalParticipantDuration ()Ljava/lang/Integer; public fun hashCode ()I public fun toString ()Ljava/lang/String; } public final class io/getstream/android/video/generated/models/CallStatsParticipantSession { - public fun (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;)V - public synthetic fun (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;)V + public synthetic fun (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Z public final fun component10 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component11 ()Ljava/lang/String; + public final fun component11 ()Ljava/lang/Integer; public final fun component12 ()Ljava/lang/String; - public final fun component13 ()Ljava/lang/String; - public final fun component14 ()Ljava/lang/String; - public final fun component15 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component13 ()Ljava/lang/Integer; + public final fun component14 ()Ljava/lang/Integer; + public final fun component15 ()Ljava/lang/String; public final fun component16 ()Ljava/lang/String; public final fun component17 ()Ljava/lang/String; - public final fun component18 ()Lio/getstream/android/video/generated/models/CallStatsLocation; + public final fun component18 ()Ljava/lang/String; + public final fun component19 ()Lorg/threeten/bp/OffsetDateTime; public final fun component2 ()Ljava/lang/String; + public final fun component20 ()Ljava/lang/String; + public final fun component21 ()Ljava/lang/String; + public final fun component22 ()Lio/getstream/android/video/generated/models/CallStatsLocation; public final fun component3 ()Lio/getstream/android/video/generated/models/PublishedTrackFlags; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -2070,8 +2110,8 @@ public final class io/getstream/android/video/generated/models/CallStatsParticip public final fun component7 ()Ljava/lang/String; public final fun component8 ()Ljava/lang/String; public final fun component9 ()Ljava/lang/Float; - public final fun copy (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;)Lio/getstream/android/video/generated/models/CallStatsParticipantSession; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsParticipantSession;ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsParticipantSession; + public final fun copy (ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;)Lio/getstream/android/video/generated/models/CallStatsParticipantSession; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsParticipantSession;ZLjava/lang/String;Lio/getstream/android/video/generated/models/PublishedTrackFlags;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Float;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsLocation;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsParticipantSession; public fun equals (Ljava/lang/Object;)Z public final fun getBrowser ()Ljava/lang/String; public final fun getBrowserVersion ()Ljava/lang/String; @@ -2080,6 +2120,10 @@ public final class io/getstream/android/video/generated/models/CallStatsParticip public final fun getCurrentSfu ()Ljava/lang/String; public final fun getDistanceToSfuKilometers ()Ljava/lang/Float; public final fun getEndedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getFreezesDurationMs ()Ljava/lang/Integer; + public final fun getIngress ()Ljava/lang/String; + public final fun getJitterMs ()Ljava/lang/Integer; + public final fun getLatencyMs ()Ljava/lang/Integer; public final fun getLocation ()Lio/getstream/android/video/generated/models/CallStatsLocation; public final fun getOs ()Ljava/lang/String; public final fun getPublishedTracks ()Lio/getstream/android/video/generated/models/PublishedTrackFlags; @@ -2096,21 +2140,28 @@ public final class io/getstream/android/video/generated/models/CallStatsParticip } public final class io/getstream/android/video/generated/models/CallStatsReportReadyEvent : io/getstream/android/video/generated/models/VideoEvent, io/getstream/android/video/generated/models/WSCallEvent { - public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;)V + public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;)V + public synthetic fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lorg/threeten/bp/OffsetDateTime; public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent; + public final fun component4 ()Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/Boolean; + public final fun component7 ()Ljava/util/List; + public final fun copy (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;)Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsReportReadyEvent; public fun equals (Ljava/lang/Object;)Z public fun getCallCID ()Ljava/lang/String; public final fun getCallCid ()Ljava/lang/String; + public final fun getCounts ()Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; public fun getEventType ()Ljava/lang/String; + public final fun getParticipantsOverview ()Ljava/util/List; public final fun getSessionId ()Ljava/lang/String; public final fun getType ()Ljava/lang/String; public fun hashCode ()I + public final fun isTrimmed ()Ljava/lang/Boolean; public fun toString ()Ljava/lang/String; } @@ -2140,6 +2191,30 @@ public final class io/getstream/android/video/generated/models/CallStatsReportSu public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/CallStatsSessionResponse { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component5 ()Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; + public final fun component6 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component7 ()Lorg/threeten/bp/OffsetDateTime; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;)Lio/getstream/android/video/generated/models/CallStatsSessionResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CallStatsSessionResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CallStatsSessionResponse; + public fun equals (Ljava/lang/Object;)Z + public final fun getCallEndedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCallId ()Ljava/lang/String; + public final fun getCallSessionId ()Ljava/lang/String; + public final fun getCallStartedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCallType ()Ljava/lang/String; + public final fun getCounts ()Lio/getstream/android/video/generated/models/CallStatsParticipantCounts; + public final fun getGeneratedAt ()Lorg/threeten/bp/OffsetDateTime; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/CallTranscription { public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; @@ -2355,6 +2430,96 @@ public final class io/getstream/android/video/generated/models/ChatActivityStats public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/ChatPreferencesResponse { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/ChatPreferencesResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ChatPreferencesResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ChatPreferencesResponse; + public fun equals (Ljava/lang/Object;)Z + public final fun getChannelMentions ()Ljava/lang/String; + public final fun getDefaultPreference ()Ljava/lang/String; + public final fun getDirectMentions ()Ljava/lang/String; + public final fun getGroupMentions ()Ljava/lang/String; + public final fun getHereMentions ()Ljava/lang/String; + public final fun getRoleMentions ()Ljava/lang/String; + public final fun getThreadReplies ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/android/video/generated/models/ClientEvent { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()Ljava/lang/String; + public final fun component11 ()Ljava/lang/String; + public final fun component12 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component13 ()Ljava/lang/Integer; + public final fun component14 ()Ljava/lang/String; + public final fun component15 ()Ljava/lang/String; + public final fun component16 ()Ljava/lang/String; + public final fun component17 ()Ljava/lang/String; + public final fun component18 ()Ljava/lang/String; + public final fun component19 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component20 ()Ljava/lang/String; + public final fun component21 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component22 ()Ljava/lang/String; + public final fun component23 ()Ljava/lang/String; + public final fun component24 ()Ljava/lang/String; + public final fun component25 ()Ljava/lang/String; + public final fun component26 ()Ljava/lang/String; + public final fun component27 ()Ljava/lang/Boolean; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/Integer; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/lang/String; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/ClientEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ClientEvent;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ClientEvent; + public fun equals (Ljava/lang/Object;)Z + public final fun getCallSessionId ()Ljava/lang/String; + public final fun getCameraPermissionStatus ()Ljava/lang/String; + public final fun getCoordinatorConnectId ()Ljava/lang/String; + public final fun getElapsedTime ()Ljava/lang/Integer; + public final fun getEventType ()Ljava/lang/String; + public final fun getIceState ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public final fun getJoinAttemptId ()Ljava/lang/String; + public final fun getMicrophonePermissionStatus ()Ljava/lang/String; + public final fun getOutcome ()Ljava/lang/String; + public final fun getPeerConnection ()Ljava/lang/String; + public final fun getPreviouslyConnectedTimestamp ()Lorg/threeten/bp/OffsetDateTime; + public final fun getRetryCountAttempt ()Ljava/lang/Integer; + public final fun getRetryFailureCode ()Ljava/lang/String; + public final fun getRetryFailureReason ()Ljava/lang/String; + public final fun getScreenShareStatus ()Ljava/lang/String; + public final fun getSdkVersion ()Ljava/lang/String; + public final fun getSfuId ()Ljava/lang/String; + public final fun getStage ()Ljava/lang/String; + public final fun getStageId ()Ljava/lang/String; + public final fun getTimestamp ()Lorg/threeten/bp/OffsetDateTime; + public final fun getTrackId ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public final fun getUserAgent ()Ljava/lang/String; + public final fun getUserId ()Ljava/lang/String; + public final fun getUserSessionId ()Ljava/lang/String; + public final fun getWasPreviouslyConnected ()Ljava/lang/Boolean; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/ClosedCaptionEvent : io/getstream/android/video/generated/models/VideoEvent, io/getstream/android/video/generated/models/WSCallEvent { public fun (Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallClosedCaption;Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; @@ -2476,12 +2641,12 @@ public final class io/getstream/android/video/generated/models/ConnectionErrorEv public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/Coordinates { +public final class io/getstream/android/video/generated/models/CoordinatesResponse { public fun (FF)V public final fun component1 ()F public final fun component2 ()F - public final fun copy (FF)Lio/getstream/android/video/generated/models/Coordinates; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/Coordinates;FFILjava/lang/Object;)Lio/getstream/android/video/generated/models/Coordinates; + public final fun copy (FF)Lio/getstream/android/video/generated/models/CoordinatesResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CoordinatesResponse;FFILjava/lang/Object;)Lio/getstream/android/video/generated/models/CoordinatesResponse; public fun equals (Ljava/lang/Object;)Z public final fun getLatitude ()F public final fun getLongitude ()F @@ -2503,15 +2668,17 @@ public final class io/getstream/android/video/generated/models/CountByMinuteResp } public final class io/getstream/android/video/generated/models/CreateDeviceRequest { - public fun (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/Boolean;)V - public synthetic fun (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider; public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Ljava/lang/Boolean; - public final fun copy (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/CreateDeviceRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CreateDeviceRequest;Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CreateDeviceRequest; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/CreateDeviceRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/CreateDeviceRequest;Ljava/lang/String;Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/CreateDeviceRequest; public fun equals (Ljava/lang/Object;)Z + public final fun getHardwareId ()Ljava/lang/String; public final fun getId ()Ljava/lang/String; public final fun getPushProvider ()Lio/getstream/android/video/generated/models/CreateDeviceRequest$PushProvider; public final fun getPushProviderName ()Ljava/lang/String; @@ -2759,20 +2926,9 @@ public final class io/getstream/android/video/generated/models/DeleteTranscripti public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/DeliveryReceipts { - public fun (Z)V - public final fun component1 ()Z - public final fun copy (Z)Lio/getstream/android/video/generated/models/DeliveryReceipts; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/DeliveryReceipts;ZILjava/lang/Object;)Lio/getstream/android/video/generated/models/DeliveryReceipts; - public fun equals (Ljava/lang/Object;)Z - public final fun getEnabled ()Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - public final class io/getstream/android/video/generated/models/DeviceResponse { - public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V - public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; @@ -2780,13 +2936,15 @@ public final class io/getstream/android/video/generated/models/DeviceResponse { public final fun component5 ()Ljava/lang/Boolean; public final fun component6 ()Ljava/lang/String; public final fun component7 ()Ljava/lang/String; - public final fun component8 ()Ljava/lang/Boolean; - public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/DeviceResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/DeviceResponse;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/DeviceResponse; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/Boolean; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/DeviceResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/DeviceResponse;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/DeviceResponse; public fun equals (Ljava/lang/Object;)Z public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; public final fun getDisabled ()Ljava/lang/Boolean; public final fun getDisabledReason ()Ljava/lang/String; + public final fun getHardwareId ()Ljava/lang/String; public final fun getId ()Ljava/lang/String; public final fun getPushProvider ()Ljava/lang/String; public final fun getPushProviderName ()Ljava/lang/String; @@ -2893,19 +3051,23 @@ public final class io/getstream/android/video/generated/models/EndCallResponse { public final class io/getstream/android/video/generated/models/FeedsPreferencesResponse { public fun ()V - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; - public final fun component6 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/lang/String; + public final fun component8 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; public fun equals (Ljava/lang/Object;)Z public final fun getComment ()Ljava/lang/String; + public final fun getCommentMention ()Ljava/lang/String; public final fun getCommentReaction ()Ljava/lang/String; + public final fun getCommentReply ()Ljava/lang/String; public final fun getCustomActivityTypes ()Ljava/util/Map; public final fun getFollow ()Ljava/lang/String; public final fun getMention ()Ljava/lang/String; @@ -3433,12 +3595,15 @@ public final class io/getstream/android/video/generated/models/IndividualRecordi } public final class io/getstream/android/video/generated/models/IndividualRecordingSettingsRequest { - public fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;)V + public fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;Ljava/util/List;)V + public synthetic fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode; - public final fun copy (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest;Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest; + public final fun component2 ()Ljava/util/List; + public final fun copy (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;Ljava/util/List;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest;Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest; public fun equals (Ljava/lang/Object;)Z public final fun getMode ()Lio/getstream/android/video/generated/models/IndividualRecordingSettingsRequest$Mode; + public final fun getOutputTypes ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -3486,12 +3651,15 @@ public final class io/getstream/android/video/generated/models/IndividualRecordi } public final class io/getstream/android/video/generated/models/IndividualRecordingSettingsResponse { - public fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;)V + public fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;Ljava/util/List;)V + public synthetic fun (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode; - public final fun copy (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse;Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse; + public final fun component2 ()Ljava/util/List; + public final fun copy (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;Ljava/util/List;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse;Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse; public fun equals (Ljava/lang/Object;)Z public final fun getMode ()Lio/getstream/android/video/generated/models/IndividualRecordingSettingsResponse$Mode; + public final fun getOutputTypes ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -3890,20 +4058,20 @@ public final class io/getstream/android/video/generated/models/IngressVideoLayer } public final class io/getstream/android/video/generated/models/JoinCallRequest { - public fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/CallRequest;Ljava/lang/Boolean;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/CallRequest;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Lio/getstream/android/video/generated/models/CallRequest;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Lio/getstream/android/video/generated/models/CallRequest;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; - public final fun component10 ()Ljava/lang/Boolean; + public final fun component10 ()Lio/getstream/android/video/generated/models/CallRequest; public final fun component2 ()Ljava/lang/Boolean; - public final fun component3 ()Ljava/lang/Integer; - public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Ljava/util/List; + public final fun component3 ()Ljava/lang/Boolean; + public final fun component4 ()Ljava/lang/Integer; + public final fun component5 ()Ljava/lang/String; public final fun component6 ()Ljava/lang/Boolean; public final fun component7 ()Ljava/lang/Boolean; public final fun component8 ()Ljava/lang/Boolean; - public final fun component9 ()Lio/getstream/android/video/generated/models/CallRequest; - public final fun copy (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/CallRequest;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/JoinCallRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/JoinCallRequest;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/CallRequest;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/JoinCallRequest; + public final fun component9 ()Ljava/util/List; + public final fun copy (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Lio/getstream/android/video/generated/models/CallRequest;)Lio/getstream/android/video/generated/models/JoinCallRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/JoinCallRequest;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Lio/getstream/android/video/generated/models/CallRequest;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/JoinCallRequest; public fun equals (Ljava/lang/Object;)Z public final fun getCreate ()Ljava/lang/Boolean; public final fun getData ()Lio/getstream/android/video/generated/models/CallRequest; @@ -4162,13 +4330,13 @@ public abstract class io/getstream/android/video/generated/models/LocalEvent : i public fun ()V } -public final class io/getstream/android/video/generated/models/Location { +public final class io/getstream/android/video/generated/models/LocationResponse { public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/Location; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/Location;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/Location; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/LocationResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/LocationResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/LocationResponse; public fun equals (Ljava/lang/Object;)Z public final fun getContinentCode ()Ljava/lang/String; public final fun getCountryIsoCode ()Ljava/lang/String; @@ -4875,23 +5043,6 @@ public final class io/getstream/android/video/generated/models/PinResponse { public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/PrivacySettings { - public fun ()V - public fun (Lio/getstream/android/video/generated/models/DeliveryReceipts;Lio/getstream/android/video/generated/models/ReadReceipts;Lio/getstream/android/video/generated/models/TypingIndicators;)V - public synthetic fun (Lio/getstream/android/video/generated/models/DeliveryReceipts;Lio/getstream/android/video/generated/models/ReadReceipts;Lio/getstream/android/video/generated/models/TypingIndicators;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Lio/getstream/android/video/generated/models/DeliveryReceipts; - public final fun component2 ()Lio/getstream/android/video/generated/models/ReadReceipts; - public final fun component3 ()Lio/getstream/android/video/generated/models/TypingIndicators; - public final fun copy (Lio/getstream/android/video/generated/models/DeliveryReceipts;Lio/getstream/android/video/generated/models/ReadReceipts;Lio/getstream/android/video/generated/models/TypingIndicators;)Lio/getstream/android/video/generated/models/PrivacySettings; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/PrivacySettings;Lio/getstream/android/video/generated/models/DeliveryReceipts;Lio/getstream/android/video/generated/models/ReadReceipts;Lio/getstream/android/video/generated/models/TypingIndicators;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/PrivacySettings; - public fun equals (Ljava/lang/Object;)Z - public final fun getDeliveryReceipts ()Lio/getstream/android/video/generated/models/DeliveryReceipts; - public final fun getReadReceipts ()Lio/getstream/android/video/generated/models/ReadReceipts; - public final fun getTypingIndicators ()Lio/getstream/android/video/generated/models/TypingIndicators; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - public final class io/getstream/android/video/generated/models/PublishedTrackFlags { public fun (ZZZZ)V public final fun component1 ()Z @@ -4952,18 +5103,20 @@ public final class io/getstream/android/video/generated/models/PublisherStatsRes public final class io/getstream/android/video/generated/models/PushPreferencesResponse { public fun ()V - public fun (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/ChatPreferencesResponse;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/ChatPreferencesResponse;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Lorg/threeten/bp/OffsetDateTime; public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;)Lio/getstream/android/video/generated/models/PushPreferencesResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/PushPreferencesResponse;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/PushPreferencesResponse; + public final fun component5 ()Lio/getstream/android/video/generated/models/ChatPreferencesResponse; + public final fun component6 ()Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/ChatPreferencesResponse;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;)Lio/getstream/android/video/generated/models/PushPreferencesResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/PushPreferencesResponse;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/ChatPreferencesResponse;Lio/getstream/android/video/generated/models/FeedsPreferencesResponse;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/PushPreferencesResponse; public fun equals (Ljava/lang/Object;)Z public final fun getCallLevel ()Ljava/lang/String; public final fun getChatLevel ()Ljava/lang/String; + public final fun getChatPreferences ()Lio/getstream/android/video/generated/models/ChatPreferencesResponse; public final fun getDisabledUntil ()Lorg/threeten/bp/OffsetDateTime; public final fun getFeedsLevel ()Ljava/lang/String; public final fun getFeedsPreferences ()Lio/getstream/android/video/generated/models/FeedsPreferencesResponse; @@ -5150,11 +5303,12 @@ public final class io/getstream/android/video/generated/models/QueryCallParticip } public final class io/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component10 ()Ljava/lang/String; public final fun component11 ()Ljava/lang/String; + public final fun component12 ()Ljava/util/List; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; @@ -5163,10 +5317,11 @@ public final class io/getstream/android/video/generated/models/QueryCallSessionP public final fun component7 ()Lorg/threeten/bp/OffsetDateTime; public final fun component8 ()Lorg/threeten/bp/OffsetDateTime; public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse; public fun equals (Ljava/lang/Object;)Z public final fun getCallEndedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCallEvents ()Ljava/util/List; public final fun getCallId ()Ljava/lang/String; public final fun getCallSessionId ()Ljava/lang/String; public final fun getCallStartedAt ()Lorg/threeten/bp/OffsetDateTime; @@ -5205,6 +5360,45 @@ public final class io/getstream/android/video/generated/models/QueryCallSessionP public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/QueryCallSessionStatsRequest { + public fun ()V + public fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/Integer; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/util/List; + public final fun component5 ()Ljava/util/Map; + public final fun copy (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;)Lio/getstream/android/video/generated/models/QueryCallSessionStatsRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/QueryCallSessionStatsRequest;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/QueryCallSessionStatsRequest; + public fun equals (Ljava/lang/Object;)Z + public final fun getFilterConditions ()Ljava/util/Map; + public final fun getLimit ()Ljava/lang/Integer; + public final fun getNext ()Ljava/lang/String; + public final fun getPrev ()Ljava/lang/String; + public final fun getSort ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/android/video/generated/models/QueryCallSessionStatsResponse { + public fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/QueryCallSessionStatsResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/QueryCallSessionStatsResponse;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/QueryCallSessionStatsResponse; + public fun equals (Ljava/lang/Object;)Z + public final fun getCallStats ()Ljava/util/List; + public final fun getDuration ()Ljava/lang/String; + public final fun getNext ()Ljava/lang/String; + public final fun getPrev ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/QueryCallStatsMapResponse { public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsMapPublishers;Lio/getstream/android/video/generated/models/CallStatsMapSFUs;Lio/getstream/android/video/generated/models/CallStatsMapSubscribers;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CallStatsParticipantCounts;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/CallStatsMapPublishers;Lio/getstream/android/video/generated/models/CallStatsMapSFUs;Lio/getstream/android/video/generated/models/CallStatsMapSubscribers;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5534,11 +5728,14 @@ public final class io/getstream/android/video/generated/models/RawRecordingRespo } public final class io/getstream/android/video/generated/models/RawRecordingSettingsRequest { - public fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;)V + public fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;Ljava/lang/Boolean;)V + public synthetic fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode; - public final fun copy (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;)Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest;Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest; + public final fun component2 ()Ljava/lang/Boolean; + public final fun copy (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest;Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest; public fun equals (Ljava/lang/Object;)Z + public final fun getAudioOnly ()Ljava/lang/Boolean; public final fun getMode ()Lio/getstream/android/video/generated/models/RawRecordingSettingsRequest$Mode; public fun hashCode ()I public fun toString ()Ljava/lang/String; @@ -5587,11 +5784,14 @@ public final class io/getstream/android/video/generated/models/RawRecordingSetti } public final class io/getstream/android/video/generated/models/RawRecordingSettingsResponse { - public fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;)V + public fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;Ljava/lang/Boolean;)V + public synthetic fun (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode; - public final fun copy (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;)Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse;Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse; + public final fun component2 ()Ljava/lang/Boolean; + public final fun copy (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;Ljava/lang/Boolean;)Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse;Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse; public fun equals (Ljava/lang/Object;)Z + public final fun getAudioOnly ()Ljava/lang/Boolean; public final fun getMode ()Lio/getstream/android/video/generated/models/RawRecordingSettingsResponse$Mode; public fun hashCode ()I public fun toString ()Ljava/lang/String; @@ -5657,17 +5857,6 @@ public final class io/getstream/android/video/generated/models/ReactionResponse public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/ReadReceipts { - public fun (Z)V - public final fun component1 ()Z - public final fun copy (Z)Lio/getstream/android/video/generated/models/ReadReceipts; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ReadReceipts;ZILjava/lang/Object;)Lio/getstream/android/video/generated/models/ReadReceipts; - public fun equals (Ljava/lang/Object;)Z - public final fun getEnabled ()Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - public final class io/getstream/android/video/generated/models/RecordSettingsRequest { public fun (Lio/getstream/android/video/generated/models/RecordSettingsRequest$Mode;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/RecordSettingsRequest$Quality;)V public synthetic fun (Lio/getstream/android/video/generated/models/RecordSettingsRequest$Mode;Ljava/lang/Boolean;Lio/getstream/android/video/generated/models/RecordSettingsRequest$Quality;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5855,6 +6044,30 @@ public final class io/getstream/android/video/generated/models/ReportByHistogram public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/ReportClientEventRequest { + public fun ()V + public fun (Ljava/util/List;)V + public synthetic fun (Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/util/List; + public final fun copy (Ljava/util/List;)Lio/getstream/android/video/generated/models/ReportClientEventRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ReportClientEventRequest;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ReportClientEventRequest; + public fun equals (Ljava/lang/Object;)Z + public final fun getEvents ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/android/video/generated/models/ReportClientEventResponse { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/android/video/generated/models/ReportClientEventResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ReportClientEventResponse;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ReportClientEventResponse; + public fun equals (Ljava/lang/Object;)Z + public final fun getDuration ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/ReportResponse { public fun (Lio/getstream/android/video/generated/models/CallReportResponse;Lio/getstream/android/video/generated/models/ParticipantReportResponse;Lio/getstream/android/video/generated/models/UserRatingReportResponse;)V public final fun component1 ()Lio/getstream/android/video/generated/models/CallReportResponse; @@ -5909,22 +6122,62 @@ public final class io/getstream/android/video/generated/models/ResolutionMetrics public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/ResolveSipAuthRequest { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/ResolveSipAuthRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ResolveSipAuthRequest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ResolveSipAuthRequest; + public fun equals (Ljava/lang/Object;)Z + public final fun getFromHost ()Ljava/lang/String; + public final fun getSipCallerNumber ()Ljava/lang/String; + public final fun getSipTrunkNumber ()Ljava/lang/String; + public final fun getSourceIp ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/android/video/generated/models/ResolveSipAuthResponse { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/ResolveSipAuthResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ResolveSipAuthResponse;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ResolveSipAuthResponse; + public fun equals (Ljava/lang/Object;)Z + public final fun getAuthResult ()Ljava/lang/String; + public final fun getDuration ()Ljava/lang/String; + public final fun getPassword ()Ljava/lang/String; + public final fun getTrunkId ()Ljava/lang/String; + public final fun getUsername ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/ResolveSipInboundRequest { - public fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallenge;Ljava/lang/String;Ljava/util/Map;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallenge;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallengeRequest;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallengeRequest;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Lio/getstream/android/video/generated/models/SIPChallenge; + public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallenge;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/android/video/generated/models/ResolveSipInboundRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ResolveSipInboundRequest;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallenge;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ResolveSipInboundRequest; + public final fun component5 ()Lio/getstream/android/video/generated/models/SIPChallengeRequest; + public final fun component6 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallengeRequest;Ljava/util/Map;)Lio/getstream/android/video/generated/models/ResolveSipInboundRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/ResolveSipInboundRequest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/SIPChallengeRequest;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/ResolveSipInboundRequest; public fun equals (Ljava/lang/Object;)Z - public final fun getChallenge ()Lio/getstream/android/video/generated/models/SIPChallenge; + public final fun getChallenge ()Lio/getstream/android/video/generated/models/SIPChallengeRequest; public final fun getRoutingNumber ()Ljava/lang/String; public final fun getSipCallerNumber ()Ljava/lang/String; public final fun getSipHeaders ()Ljava/util/Map; public final fun getSipTrunkNumber ()Ljava/lang/String; + public final fun getTrunkId ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -6045,21 +6298,21 @@ public final class io/getstream/android/video/generated/models/SDKUsageReportRes } public final class io/getstream/android/video/generated/models/SFULocationResponse { - public fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/Coordinates;Lio/getstream/android/video/generated/models/Location;Ljava/lang/Integer;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/Coordinates;Lio/getstream/android/video/generated/models/Location;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CoordinatesResponse;Lio/getstream/android/video/generated/models/LocationResponse;Ljava/lang/Integer;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CoordinatesResponse;Lio/getstream/android/video/generated/models/LocationResponse;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Lio/getstream/android/video/generated/models/Coordinates; - public final fun component4 ()Lio/getstream/android/video/generated/models/Location; + public final fun component3 ()Lio/getstream/android/video/generated/models/CoordinatesResponse; + public final fun component4 ()Lio/getstream/android/video/generated/models/LocationResponse; public final fun component5 ()Ljava/lang/Integer; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/Coordinates;Lio/getstream/android/video/generated/models/Location;Ljava/lang/Integer;)Lio/getstream/android/video/generated/models/SFULocationResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SFULocationResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/Coordinates;Lio/getstream/android/video/generated/models/Location;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SFULocationResponse; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CoordinatesResponse;Lio/getstream/android/video/generated/models/LocationResponse;Ljava/lang/Integer;)Lio/getstream/android/video/generated/models/SFULocationResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SFULocationResponse;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/CoordinatesResponse;Lio/getstream/android/video/generated/models/LocationResponse;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SFULocationResponse; public fun equals (Ljava/lang/Object;)Z - public final fun getCoordinates ()Lio/getstream/android/video/generated/models/Coordinates; + public final fun getCoordinates ()Lio/getstream/android/video/generated/models/CoordinatesResponse; public final fun getCount ()Ljava/lang/Integer; public final fun getDatacenter ()Ljava/lang/String; public final fun getId ()Ljava/lang/String; - public final fun getLocation ()Lio/getstream/android/video/generated/models/Location; + public final fun getLocation ()Lio/getstream/android/video/generated/models/LocationResponse; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -6106,7 +6359,7 @@ public final class io/getstream/android/video/generated/models/SIPCallerConfigsR public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/SIPChallenge { +public final class io/getstream/android/video/generated/models/SIPChallengeRequest { public fun ()V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6126,8 +6379,8 @@ public final class io/getstream/android/video/generated/models/SIPChallenge { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Ljava/lang/String; public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lio/getstream/android/video/generated/models/SIPChallenge; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SIPChallenge;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SIPChallenge; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lio/getstream/android/video/generated/models/SIPChallengeRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SIPChallengeRequest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SIPChallengeRequest; public fun equals (Ljava/lang/Object;)Z public final fun getA1 ()Ljava/lang/String; public final fun getAlgorithm ()Ljava/lang/String; @@ -6238,8 +6491,8 @@ public final class io/getstream/android/video/generated/models/SIPPinProtectionC } public final class io/getstream/android/video/generated/models/SIPTrunkResponse { - public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V - public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; @@ -6248,9 +6501,11 @@ public final class io/getstream/android/video/generated/models/SIPTrunkResponse public final fun component6 ()Ljava/lang/String; public final fun component7 ()Ljava/lang/String; public final fun component8 ()Ljava/util/List; - public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)Lio/getstream/android/video/generated/models/SIPTrunkResponse; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SIPTrunkResponse;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SIPTrunkResponse; + public final fun component9 ()Ljava/util/List; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lio/getstream/android/video/generated/models/SIPTrunkResponse; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SIPTrunkResponse;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SIPTrunkResponse; public fun equals (Ljava/lang/Object;)Z + public final fun getAllowedIps ()Ljava/util/List; public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; public final fun getId ()Ljava/lang/String; public final fun getName ()Ljava/lang/String; @@ -6420,17 +6675,19 @@ public final class io/getstream/android/video/generated/models/SessionWarningRes } public final class io/getstream/android/video/generated/models/SipInboundCredentials { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Ljava/util/Map; + public final fun component5 ()Ljava/lang/String; public final fun component6 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)Lio/getstream/android/video/generated/models/SipInboundCredentials; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SipInboundCredentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SipInboundCredentials; + public final fun component7 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)Lio/getstream/android/video/generated/models/SipInboundCredentials; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SipInboundCredentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SipInboundCredentials; public fun equals (Ljava/lang/Object;)Z + public final fun getApiKey ()Ljava/lang/String; public final fun getCallCustomData ()Ljava/util/Map; public final fun getCallId ()Ljava/lang/String; public final fun getCallType ()Ljava/lang/String; @@ -6443,59 +6700,17 @@ public final class io/getstream/android/video/generated/models/SipInboundCredent public final class io/getstream/android/video/generated/models/SortParamRequest { public fun ()V - public fun (Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/android/video/generated/models/SortParamRequest$Type;)V - public synthetic fun (Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/android/video/generated/models/SortParamRequest$Type;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Integer; public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Lio/getstream/android/video/generated/models/SortParamRequest$Type; - public final fun copy (Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/android/video/generated/models/SortParamRequest$Type;)Lio/getstream/android/video/generated/models/SortParamRequest; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SortParamRequest;Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/android/video/generated/models/SortParamRequest$Type;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SortParamRequest; + public final fun component3 ()Ljava/lang/String; + public final fun copy (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/android/video/generated/models/SortParamRequest; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SortParamRequest;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SortParamRequest; public fun equals (Ljava/lang/Object;)Z public final fun getDirection ()Ljava/lang/Integer; public final fun getField ()Ljava/lang/String; - public final fun getType ()Lio/getstream/android/video/generated/models/SortParamRequest$Type; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public abstract class io/getstream/android/video/generated/models/SortParamRequest$Type { - public static final field Companion Lio/getstream/android/video/generated/models/SortParamRequest$Type$Companion; - public synthetic fun (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getValue ()Ljava/lang/String; - public fun toString ()Ljava/lang/String; -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$Boolean : io/getstream/android/video/generated/models/SortParamRequest$Type { - public static final field INSTANCE Lio/getstream/android/video/generated/models/SortParamRequest$Type$Boolean; -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$Companion { - public final fun fromString (Ljava/lang/String;)Lio/getstream/android/video/generated/models/SortParamRequest$Type; -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$Empty : io/getstream/android/video/generated/models/SortParamRequest$Type { - public static final field INSTANCE Lio/getstream/android/video/generated/models/SortParamRequest$Type$Empty; -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$Number : io/getstream/android/video/generated/models/SortParamRequest$Type { - public static final field INSTANCE Lio/getstream/android/video/generated/models/SortParamRequest$Type$Number; -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$TypeAdapter : com/squareup/moshi/JsonAdapter { - public fun ()V - public fun fromJson (Lcom/squareup/moshi/JsonReader;)Lio/getstream/android/video/generated/models/SortParamRequest$Type; - public synthetic fun fromJson (Lcom/squareup/moshi/JsonReader;)Ljava/lang/Object; - public fun toJson (Lcom/squareup/moshi/JsonWriter;Lio/getstream/android/video/generated/models/SortParamRequest$Type;)V - public synthetic fun toJson (Lcom/squareup/moshi/JsonWriter;Ljava/lang/Object;)V -} - -public final class io/getstream/android/video/generated/models/SortParamRequest$Type$Unknown : io/getstream/android/video/generated/models/SortParamRequest$Type { - public fun (Ljava/lang/String;)V - public final fun component1 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;)Lio/getstream/android/video/generated/models/SortParamRequest$Type$Unknown; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/SortParamRequest$Type$Unknown;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/SortParamRequest$Type$Unknown; - public fun equals (Ljava/lang/Object;)Z - public final fun getUnknownValue ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -7829,17 +8044,6 @@ public final class io/getstream/android/video/generated/models/TranslationSettin public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/TypingIndicators { - public fun (Z)V - public final fun component1 ()Z - public final fun copy (Z)Lio/getstream/android/video/generated/models/TypingIndicators; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/TypingIndicators;ZILjava/lang/Object;)Lio/getstream/android/video/generated/models/TypingIndicators; - public fun equals (Ljava/lang/Object;)Z - public final fun getEnabled ()Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - public final class io/getstream/android/video/generated/models/UnblockUserRequest { public fun (Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; @@ -8031,100 +8235,103 @@ public final class io/getstream/android/video/generated/models/UpdatedCallPermis public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/User { - public fun (ZLjava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;)V - public synthetic fun (ZLjava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Z +public final class io/getstream/android/video/generated/models/UserBannedEvent : io/getstream/android/video/generated/models/VideoEvent { + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; public final fun component10 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component11 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component12 ()Ljava/lang/Boolean; - public final fun component13 ()Ljava/lang/String; - public final fun component14 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component15 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component16 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component17 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component18 ()Ljava/util/List; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Z + public final fun component11 ()Ljava/lang/String; + public final fun component12 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component13 ()Ljava/lang/Boolean; + public final fun component14 ()Ljava/lang/String; + public final fun component15 ()Ljava/lang/Integer; + public final fun component16 ()Ljava/util/Map; + public final fun component17 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component2 ()Ljava/util/Map; + public final fun component3 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Ljava/util/Map; - public final fun component6 ()Ljava/util/Map; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/Integer; public final fun component7 ()Ljava/lang/Integer; - public final fun component8 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component9 ()Lorg/threeten/bp/OffsetDateTime; - public final fun copy (ZLjava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;)Lio/getstream/android/video/generated/models/User; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/User;ZLjava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/User; - public fun equals (Ljava/lang/Object;)Z - public final fun getAvgResponseTime ()Ljava/lang/Integer; - public final fun getBanExpires ()Lorg/threeten/bp/OffsetDateTime; - public final fun getBanned ()Z - public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getCustom ()Ljava/util/Map; - public final fun getDeactivatedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getDeletedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getId ()Ljava/lang/String; - public final fun getInvisible ()Ljava/lang/Boolean; - public final fun getLanguage ()Ljava/lang/String; - public final fun getLastActive ()Lorg/threeten/bp/OffsetDateTime; - public final fun getLastEngagedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getOnline ()Z - public final fun getRevokeTokensIssuedBefore ()Lorg/threeten/bp/OffsetDateTime; - public final fun getRole ()Ljava/lang/String; - public final fun getTeams ()Ljava/util/List; - public final fun getTeamsRole ()Ljava/util/Map; - public final fun getUpdatedAt ()Lorg/threeten/bp/OffsetDateTime; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class io/getstream/android/video/generated/models/UserBannedEvent : io/getstream/android/video/generated/models/VideoEvent { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ZLio/getstream/android/video/generated/models/User;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ZLio/getstream/android/video/generated/models/User;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component10 ()Ljava/lang/String; - public final fun component11 ()Lio/getstream/android/video/generated/models/User; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component5 ()Z - public final fun component6 ()Lio/getstream/android/video/generated/models/User; - public final fun component7 ()Ljava/lang/String; - public final fun component8 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component8 ()Ljava/lang/String; public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ZLio/getstream/android/video/generated/models/User;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)Lio/getstream/android/video/generated/models/UserBannedEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserBannedEvent;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ZLio/getstream/android/video/generated/models/User;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserBannedEvent; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)Lio/getstream/android/video/generated/models/UserBannedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserBannedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserBannedEvent; public fun equals (Ljava/lang/Object;)Z + public final fun getChannelCustom ()Ljava/util/Map; public final fun getChannelId ()Ljava/lang/String; + public final fun getChannelMemberCount ()Ljava/lang/Integer; + public final fun getChannelMessageCount ()Ljava/lang/Integer; public final fun getChannelType ()Ljava/lang/String; public final fun getCid ()Ljava/lang/String; public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/User; + public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun getCustom ()Ljava/util/Map; public fun getEventType ()Ljava/lang/String; public final fun getExpiration ()Lorg/threeten/bp/OffsetDateTime; public final fun getReason ()Ljava/lang/String; - public final fun getShadow ()Z + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getShadow ()Ljava/lang/Boolean; public final fun getTeam ()Ljava/lang/String; + public final fun getTotalBans ()Ljava/lang/Integer; public final fun getType ()Ljava/lang/String; - public final fun getUser ()Lio/getstream/android/video/generated/models/User; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; public fun hashCode ()I public fun toString ()Ljava/lang/String; } public final class io/getstream/android/video/generated/models/UserDeactivatedEvent : io/getstream/android/video/generated/models/VideoEvent { - public fun (Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/User;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)V - public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/User;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component2 ()Lio/getstream/android/video/generated/models/User; - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Lio/getstream/android/video/generated/models/User; - public final fun copy (Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/User;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)Lio/getstream/android/video/generated/models/UserDeactivatedEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserDeactivatedEvent;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/User;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserDeactivatedEvent; + public final fun component2 ()Ljava/util/Map; + public final fun component3 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component6 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)Lio/getstream/android/video/generated/models/UserDeactivatedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserDeactivatedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserDeactivatedEvent; public fun equals (Ljava/lang/Object;)Z public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; - public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/User; + public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun getCustom ()Ljava/util/Map; public fun getEventType ()Ljava/lang/String; + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; public final fun getType ()Ljava/lang/String; - public final fun getUser ()Lio/getstream/android/video/generated/models/User; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/android/video/generated/models/UserDeletedEvent : io/getstream/android/video/generated/models/VideoEvent { + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZZLjava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZZLjava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component10 ()Ljava/lang/String; + public final fun component11 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Z + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Z + public final fun component7 ()Z + public final fun component8 ()Ljava/util/Map; + public final fun component9 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZZLjava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;)Lio/getstream/android/video/generated/models/UserDeletedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserDeletedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZZLjava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserDeletedEvent; + public fun equals (Ljava/lang/Object;)Z + public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCustom ()Ljava/util/Map; + public final fun getDeleteConversation ()Ljava/lang/String; + public final fun getDeleteConversationChannels ()Z + public final fun getDeleteMessages ()Ljava/lang/String; + public final fun getDeleteUser ()Ljava/lang/String; + public fun getEventType ()Ljava/lang/String; + public final fun getHardDelete ()Z + public final fun getMarkMessagesDeleted ()Z + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getType ()Ljava/lang/String; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -8156,23 +8363,23 @@ public final class io/getstream/android/video/generated/models/UserFeedbackRepor public fun toString ()Ljava/lang/String; } -public final class io/getstream/android/video/generated/models/UserMutedEvent : io/getstream/android/video/generated/models/VideoEvent { - public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/User;)V - public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/User;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +public final class io/getstream/android/video/generated/models/UserPresenceChangedEvent : io/getstream/android/video/generated/models/VideoEvent { + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Ljava/util/List; - public final fun component5 ()Lio/getstream/android/video/generated/models/User; - public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/User;)Lio/getstream/android/video/generated/models/UserMutedEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserMutedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lio/getstream/android/video/generated/models/User;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserMutedEvent; + public final fun component2 ()Ljava/util/Map; + public final fun component3 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lorg/threeten/bp/OffsetDateTime; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;)Lio/getstream/android/video/generated/models/UserPresenceChangedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserPresenceChangedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserPresenceChangedEvent; public fun equals (Ljava/lang/Object;)Z public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCustom ()Ljava/util/Map; public fun getEventType ()Ljava/lang/String; - public final fun getTargetUser ()Ljava/lang/String; - public final fun getTargetUsers ()Ljava/util/List; + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; public final fun getType ()Ljava/lang/String; - public final fun getUser ()Lio/getstream/android/video/generated/models/User; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -8191,18 +8398,24 @@ public final class io/getstream/android/video/generated/models/UserRatingReportR } public final class io/getstream/android/video/generated/models/UserReactivatedEvent : io/getstream/android/video/generated/models/VideoEvent { - public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)V - public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Lio/getstream/android/video/generated/models/User; - public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;)Lio/getstream/android/video/generated/models/UserReactivatedEvent; - public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserReactivatedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lio/getstream/android/video/generated/models/User;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserReactivatedEvent; + public final fun component2 ()Ljava/util/Map; + public final fun component3 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component6 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)Lio/getstream/android/video/generated/models/UserReactivatedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserReactivatedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserReactivatedEvent; public fun equals (Ljava/lang/Object;)Z public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun getCustom ()Ljava/util/Map; public fun getEventType ()Ljava/lang/String; + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; public final fun getType ()Ljava/lang/String; - public final fun getUser ()Lio/getstream/android/video/generated/models/User; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -8271,6 +8484,48 @@ public final class io/getstream/android/video/generated/models/UserResponse { public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/UserResponseCommonFields { + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component10 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component11 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component12 ()Ljava/lang/String; + public final fun component13 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component14 ()Ljava/lang/String; + public final fun component15 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component16 ()Ljava/util/Map; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component6 ()Ljava/util/List; + public final fun component7 ()Ljava/util/List; + public final fun component8 ()Ljava/util/Map; + public final fun component9 ()Ljava/lang/Integer; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;)Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserResponseCommonFields;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public fun equals (Ljava/lang/Object;)Z + public final fun getAvgResponseTime ()Ljava/lang/Integer; + public final fun getBlockedUserIds ()Ljava/util/List; + public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCustom ()Ljava/util/Map; + public final fun getDeactivatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getDeletedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getId ()Ljava/lang/String; + public final fun getImage ()Ljava/lang/String; + public final fun getLanguage ()Ljava/lang/String; + public final fun getLastActive ()Lorg/threeten/bp/OffsetDateTime; + public final fun getName ()Ljava/lang/String; + public final fun getRevokeTokensIssuedBefore ()Lorg/threeten/bp/OffsetDateTime; + public final fun getRole ()Ljava/lang/String; + public final fun getTeams ()Ljava/util/List; + public final fun getTeamsRole ()Ljava/util/Map; + public final fun getUpdatedAt ()Lorg/threeten/bp/OffsetDateTime; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/UserResponsePrivacyFields { public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/Boolean;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;)V public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Ljava/lang/Integer;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Ljava/lang/Boolean;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -8315,6 +8570,45 @@ public final class io/getstream/android/video/generated/models/UserResponsePriva public fun toString ()Ljava/lang/String; } +public final class io/getstream/android/video/generated/models/UserUnbannedEvent : io/getstream/android/video/generated/models/VideoEvent { + public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)V + public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component10 ()Lorg/threeten/bp/OffsetDateTime; + public final fun component11 ()Ljava/lang/Boolean; + public final fun component12 ()Ljava/lang/String; + public final fun component13 ()Ljava/util/Map; + public final fun component14 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component2 ()Ljava/util/Map; + public final fun component3 ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/Integer; + public final fun component7 ()Ljava/lang/Integer; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/String; + public final fun copy (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;)Lio/getstream/android/video/generated/models/UserUnbannedEvent; + public static synthetic fun copy$default (Lio/getstream/android/video/generated/models/UserUnbannedEvent;Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponseCommonFields;ILjava/lang/Object;)Lio/getstream/android/video/generated/models/UserUnbannedEvent; + public fun equals (Ljava/lang/Object;)Z + public final fun getChannelCustom ()Ljava/util/Map; + public final fun getChannelId ()Ljava/lang/String; + public final fun getChannelMemberCount ()Ljava/lang/Integer; + public final fun getChannelMessageCount ()Ljava/lang/Integer; + public final fun getChannelType ()Ljava/lang/String; + public final fun getCid ()Ljava/lang/String; + public final fun getCreatedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getCreatedBy ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public final fun getCustom ()Ljava/util/Map; + public fun getEventType ()Ljava/lang/String; + public final fun getReceivedAt ()Lorg/threeten/bp/OffsetDateTime; + public final fun getShadow ()Ljava/lang/Boolean; + public final fun getTeam ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public final fun getUser ()Lio/getstream/android/video/generated/models/UserResponseCommonFields; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/android/video/generated/models/UserUpdatedEvent : io/getstream/android/video/generated/models/VideoEvent { public fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponsePrivacyFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;)V public synthetic fun (Lorg/threeten/bp/OffsetDateTime;Ljava/util/Map;Lio/getstream/android/video/generated/models/UserResponsePrivacyFields;Ljava/lang/String;Lorg/threeten/bp/OffsetDateTime;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -8700,6 +8994,87 @@ public final class io/getstream/video/android/core/CallKt { public static final field sfuReconnectTimeoutMillis I } +public final class io/getstream/video/android/core/CallLeaveReason$Backend : io/getstream/video/android/core/CallLeaveReason { + public fun (Lio/getstream/video/android/core/BackendCause;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Lio/getstream/video/android/core/BackendCause;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lio/getstream/video/android/core/BackendCause; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/util/Map; + public final fun copy (Lio/getstream/video/android/core/BackendCause;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/video/android/core/CallLeaveReason$Backend; + public static synthetic fun copy$default (Lio/getstream/video/android/core/CallLeaveReason$Backend;Lio/getstream/video/android/core/BackendCause;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/CallLeaveReason$Backend; + public fun equals (Ljava/lang/Object;)Z + public final fun getCause ()Lio/getstream/video/android/core/BackendCause; + public fun getMessage ()Ljava/lang/String; + public fun getMetadata ()Ljava/util/Map; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/CallLeaveReason$Custom : io/getstream/video/android/core/CallLeaveReason { + public fun ()V + public fun (Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/util/Map;)Lio/getstream/video/android/core/CallLeaveReason$Custom; + public static synthetic fun copy$default (Lio/getstream/video/android/core/CallLeaveReason$Custom;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/CallLeaveReason$Custom; + public fun equals (Ljava/lang/Object;)Z + public fun getMessage ()Ljava/lang/String; + public fun getMetadata ()Ljava/util/Map; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/CallLeaveReason$RetryExhausted : io/getstream/video/android/core/CallLeaveReason { + public fun (ILjava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (ILjava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()I + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/util/Map; + public final fun copy (ILjava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/video/android/core/CallLeaveReason$RetryExhausted; + public static synthetic fun copy$default (Lio/getstream/video/android/core/CallLeaveReason$RetryExhausted;ILjava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/CallLeaveReason$RetryExhausted; + public fun equals (Ljava/lang/Object;)Z + public final fun getFailureCode ()Ljava/lang/String; + public fun getMessage ()Ljava/lang/String; + public fun getMetadata ()Ljava/util/Map; + public final fun getRetryCount ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/CallLeaveReason$SdkDriven : io/getstream/video/android/core/CallLeaveReason { + public fun (Lio/getstream/video/android/core/SdkCause;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Lio/getstream/video/android/core/SdkCause;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lio/getstream/video/android/core/SdkCause; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/util/Map; + public final fun copy (Lio/getstream/video/android/core/SdkCause;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/video/android/core/CallLeaveReason$SdkDriven; + public static synthetic fun copy$default (Lio/getstream/video/android/core/CallLeaveReason$SdkDriven;Lio/getstream/video/android/core/SdkCause;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/CallLeaveReason$SdkDriven; + public fun equals (Ljava/lang/Object;)Z + public final fun getCause ()Lio/getstream/video/android/core/SdkCause; + public fun getMessage ()Ljava/lang/String; + public fun getMetadata ()Ljava/util/Map; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/CallLeaveReason$UserAction : io/getstream/video/android/core/CallLeaveReason { + public fun (Lio/getstream/video/android/core/UserActionCause;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Lio/getstream/video/android/core/UserActionCause;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lio/getstream/video/android/core/UserActionCause; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/util/Map; + public final fun copy (Lio/getstream/video/android/core/UserActionCause;Ljava/lang/String;Ljava/util/Map;)Lio/getstream/video/android/core/CallLeaveReason$UserAction; + public static synthetic fun copy$default (Lio/getstream/video/android/core/CallLeaveReason$UserAction;Lio/getstream/video/android/core/UserActionCause;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/CallLeaveReason$UserAction; + public fun equals (Ljava/lang/Object;)Z + public final fun getCause ()Lio/getstream/video/android/core/UserActionCause; + public fun getMessage ()Ljava/lang/String; + public fun getMetadata ()Ljava/util/Map; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/video/android/core/CallState { public fun (Lio/getstream/video/android/core/StreamVideo;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Lkotlinx/coroutines/CoroutineScope;)V public final fun clearParticipants ()V diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/apis/ProductvideoApi.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/apis/ProductvideoApi.kt index 252b8703282..de3b2e7aabf 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/apis/ProductvideoApi.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/apis/ProductvideoApi.kt @@ -717,6 +717,32 @@ interface ProductvideoApi { @Path("filename") filename: kotlin.String ): io.getstream.android.video.generated.models.DeleteTranscriptionResponse + /** + * Report client-side events + * Reports a batch of client-side telemetry events. Events are processed independently; one invalid event does not block the rest of the batch. + */ + @POST("/video/call_client_event") + suspend fun reportClientCallEvent( + @Body reportClientEventRequest: io.getstream.android.video.generated.models.ReportClientEventRequest + ): io.getstream.android.video.generated.models.ReportClientEventResponse + + /** + * Query call session stats + * + */ + @POST("/video/call_stats") + suspend fun queryCallSessionStats( + @Body queryCallSessionStatsRequest: io.getstream.android.video.generated.models.QueryCallSessionStatsRequest + ): io.getstream.android.video.generated.models.QueryCallSessionStatsResponse + + /** + * Query call session stats + * + */ + @POST("/video/call_stats") + suspend fun queryCallSessionStats( + ): io.getstream.android.video.generated.models.QueryCallSessionStatsResponse + /** * Map call participants by location * @@ -851,6 +877,15 @@ interface ProductvideoApi { suspend fun videoConnect( ) + /** + * Resolve SIP Auth + * Determine authentication requirements for an inbound SIP call before sending a digest challenge + */ + @POST("/video/sip/auth") + suspend fun resolveSipAuth( + @Body resolveSipAuthRequest: io.getstream.android.video.generated.models.ResolveSipAuthRequest + ): io.getstream.android.video.generated.models.ResolveSipAuthResponse + /** * Resolve SIP Inbound Routing * Resolve SIP inbound routing based on trunk number, caller number, and challenge authentication diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/infrastructure/Serializer.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/infrastructure/Serializer.kt index f611659ac97..e38a6358875 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/infrastructure/Serializer.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/infrastructure/Serializer.kt @@ -52,7 +52,6 @@ object Serializer { .add(io.getstream.android.video.generated.models.RawRecordingSettingsResponse.Mode.ModeAdapter()) .add(io.getstream.android.video.generated.models.RecordSettingsRequest.Mode.ModeAdapter()) .add(io.getstream.android.video.generated.models.RecordSettingsRequest.Quality.QualityAdapter()) - .add(io.getstream.android.video.generated.models.SortParamRequest.Type.TypeAdapter()) .add(io.getstream.android.video.generated.models.StartClosedCaptionsRequest.Language.LanguageAdapter()) .add(io.getstream.android.video.generated.models.StartTranscriptionRequest.Language.LanguageAdapter()) .add(io.getstream.android.video.generated.models.TranscriptionSettingsRequest.ClosedCaptionMode.ClosedCaptionModeAdapter()) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallEndedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallEndedEvent.kt index c05fb192070..45d5947e2e5 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallEndedEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallEndedEvent.kt @@ -54,6 +54,9 @@ data class CallEndedEvent ( @Json(name = "reason") val reason: kotlin.String? = null, + @Json(name = "members") + val members: kotlin.collections.List? = emptyList(), + @Json(name = "user") val user: io.getstream.android.video.generated.models.UserResponse? = null ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReadReceipts.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallLevelEventPayload.kt similarity index 77% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReadReceipts.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallLevelEventPayload.kt index efa0da4108d..c75660eb9bc 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReadReceipts.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallLevelEventPayload.kt @@ -38,7 +38,16 @@ import com.squareup.moshi.ToJson * */ -data class ReadReceipts ( - @Json(name = "enabled") - val enabled: kotlin.Boolean +data class CallLevelEventPayload ( + @Json(name = "event_type") + val eventType: kotlin.String, + + @Json(name = "timestamp") + val timestamp: kotlin.Int, + + @Json(name = "user_id") + val userId: kotlin.String, + + @Json(name = "payload") + val payload: kotlin.collections.Map? = emptyMap() ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantCounts.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantCounts.kt index 8b4d9b2bb16..2438afbbb47 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantCounts.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantCounts.kt @@ -57,6 +57,24 @@ data class CallStatsParticipantCounts ( @Json(name = "sessions") val sessions: kotlin.Int, + @Json(name = "sfus_used") + val sfusUsed: kotlin.Int, + + @Json(name = "average_jitter_ms") + val averageJitterMs: kotlin.Int? = null, + + @Json(name = "average_latency_ms") + val averageLatencyMs: kotlin.Int? = null, + + @Json(name = "call_event_count") + val callEventCount: kotlin.Int? = null, + + @Json(name = "cq_score") + val cqScore: kotlin.Int? = null, + + @Json(name = "max_freezes_duration_ms") + val maxFreezesDurationMs: kotlin.Int? = null, + @Json(name = "total_participant_duration") val totalParticipantDuration: kotlin.Int? = null ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantSession.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantSession.kt index ce8e49588a9..822681ac48c 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantSession.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsParticipantSession.kt @@ -69,6 +69,18 @@ data class CallStatsParticipantSession ( @Json(name = "ended_at") val endedAt: org.threeten.bp.OffsetDateTime? = null, + @Json(name = "freezes_duration_ms") + val freezesDurationMs: kotlin.Int? = null, + + @Json(name = "ingress") + val ingress: kotlin.String? = null, + + @Json(name = "jitter_ms") + val jitterMs: kotlin.Int? = null, + + @Json(name = "latency_ms") + val latencyMs: kotlin.Int? = null, + @Json(name = "os") val os: kotlin.String? = null, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsReportReadyEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsReportReadyEvent.kt index c002187193c..aa097fce3b8 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsReportReadyEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsReportReadyEvent.kt @@ -48,8 +48,17 @@ data class CallStatsReportReadyEvent ( @Json(name = "session_id") val sessionId: kotlin.String, + @Json(name = "counts") + val counts: io.getstream.android.video.generated.models.CallStatsParticipantCounts, + @Json(name = "type") - val type: kotlin.String + val type: kotlin.String, + + @Json(name = "is_trimmed") + val isTrimmed: kotlin.Boolean? = null, + + @Json(name = "participants_overview") + val participantsOverview: kotlin.collections.List? = emptyList() ) : io.getstream.android.video.generated.models.VideoEvent(), io.getstream.android.video.generated.models.WSCallEvent { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsSessionResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsSessionResponse.kt new file mode 100644 index 00000000000..6f47076e4be --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CallStatsSessionResponse.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * + */ + +data class CallStatsSessionResponse ( + @Json(name = "call_id") + val callId: kotlin.String, + + @Json(name = "call_session_id") + val callSessionId: kotlin.String, + + @Json(name = "call_type") + val callType: kotlin.String, + + @Json(name = "generated_at") + val generatedAt: org.threeten.bp.OffsetDateTime, + + @Json(name = "counts") + val counts: io.getstream.android.video.generated.models.CallStatsParticipantCounts, + + @Json(name = "call_ended_at") + val callEndedAt: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "call_started_at") + val callStartedAt: org.threeten.bp.OffsetDateTime? = null +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ChatPreferencesResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ChatPreferencesResponse.kt new file mode 100644 index 00000000000..9941dab2a37 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ChatPreferencesResponse.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * + */ + +data class ChatPreferencesResponse ( + @Json(name = "channel_mentions") + val channelMentions: kotlin.String? = null, + + @Json(name = "default_preference") + val defaultPreference: kotlin.String? = null, + + @Json(name = "direct_mentions") + val directMentions: kotlin.String? = null, + + @Json(name = "group_mentions") + val groupMentions: kotlin.String? = null, + + @Json(name = "here_mentions") + val hereMentions: kotlin.String? = null, + + @Json(name = "role_mentions") + val roleMentions: kotlin.String? = null, + + @Json(name = "thread_replies") + val threadReplies: kotlin.String? = null +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ClientEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ClientEvent.kt new file mode 100644 index 00000000000..1c9c0c5af27 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ClientEvent.kt @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * A single client-side telemetry event. When stage is CoordinatorJoin, CoordinatorWS, WSJoin, or PeerConnectionConnect the event reports a join-lifecycle attempt; initiation and completion of a stage attempt share the same stage_id. FirstAudioFrame and FirstVideoFrame report media readiness and only ever carry an initiated event. MediaDevicePermission reports the result of requesting screen-share, microphone, and camera permissions. Other stage values denote generic client events. + */ + +data class ClientEvent ( + @Json(name = "call_session_id") + val callSessionId: kotlin.String? = null, + + @Json(name = "camera_permission_status") + val cameraPermissionStatus: kotlin.String? = null, + + @Json(name = "coordinator_connect_id") + val coordinatorConnectId: kotlin.String? = null, + + @Json(name = "elapsed_time") + val elapsedTime: kotlin.Int? = null, + + @Json(name = "event_type") + val eventType: kotlin.String? = null, + + @Json(name = "ice_state") + val iceState: kotlin.String? = null, + + @Json(name = "id") + val id: kotlin.String? = null, + + @Json(name = "join_attempt_id") + val joinAttemptId: kotlin.String? = null, + + @Json(name = "microphone_permission_status") + val microphonePermissionStatus: kotlin.String? = null, + + @Json(name = "outcome") + val outcome: kotlin.String? = null, + + @Json(name = "peer_connection") + val peerConnection: kotlin.String? = null, + + @Json(name = "previously_connected_timestamp") + val previouslyConnectedTimestamp: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "retry_count_attempt") + val retryCountAttempt: kotlin.Int? = null, + + @Json(name = "retry_failure_code") + val retryFailureCode: kotlin.String? = null, + + @Json(name = "retry_failure_reason") + val retryFailureReason: kotlin.String? = null, + + @Json(name = "screen_share_status") + val screenShareStatus: kotlin.String? = null, + + @Json(name = "sdk_version") + val sdkVersion: kotlin.String? = null, + + @Json(name = "sfu_id") + val sfuId: kotlin.String? = null, + + @Json(name = "stage") + val stage: kotlin.String? = null, + + @Json(name = "stage_id") + val stageId: kotlin.String? = null, + + @Json(name = "timestamp") + val timestamp: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "track_id") + val trackId: kotlin.String? = null, + + @Json(name = "type") + val type: kotlin.String? = null, + + @Json(name = "user_agent") + val userAgent: kotlin.String? = null, + + @Json(name = "user_id") + val userId: kotlin.String? = null, + + @Json(name = "user_session_id") + val userSessionId: kotlin.String? = null, + + @Json(name = "was_previously_connected") + val wasPreviouslyConnected: kotlin.Boolean? = null +) { + internal fun toLog(): String { + return buildString { + append("ClientEvent(") + + appendIfNotNull("type", type) + appendIfNotNull("eventType", eventType) + appendIfNotNull("stage", stage) + appendIfNotNull("outcome", outcome) + + appendIfNotNull("callSessionId", callSessionId) + appendIfNotNull("stageId", stageId) + appendIfNotNull("userSessionId", userSessionId) + appendIfNotNull("joinAttemptId", joinAttemptId) + appendIfNotNull("coordinatorConnectId", coordinatorConnectId) + + appendIfNotNull("userId", userId) + appendIfNotNull("sfuId", sfuId) + + appendIfNotNull("peerConnection", peerConnection) + appendIfNotNull("iceState", iceState) + + appendIfNotNull("retryCountAttempt", retryCountAttempt) + appendIfNotNull("retryFailureCode", retryFailureCode) + appendIfNotNull("retryFailureReason", retryFailureReason) + + appendIfNotNull("elapsedTime", elapsedTime) + + appendIfNotNull( + "wasPreviouslyConnected", + wasPreviouslyConnected + ) + + appendIfNotNull( + "previouslyConnectedTimestamp", + previouslyConnectedTimestamp + ) + + appendIfNotNull("sdkVersion", sdkVersion) + appendIfNotNull("timestamp", timestamp) + appendIfNotNull("cameraPermissionStatus", cameraPermissionStatus) + appendIfNotNull("microphonePermissionStatus", microphonePermissionStatus) + appendIfNotNull("screenShareStatus", screenShareStatus) + appendIfNotNull("trackId", trackId) + + append(")") + } + } + + private fun StringBuilder.appendIfNotNull( + key: String, + value: Any?, + ) { + if (value == null) return + + if (!endsWith("(")) { + append(",\n") + } + + append(key) + append("=") + append(value) + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Coordinates.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CoordinatesResponse.kt similarity index 95% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Coordinates.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CoordinatesResponse.kt index 9fcd2acba77..dbbb8d63edb 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Coordinates.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CoordinatesResponse.kt @@ -35,10 +35,10 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * Geographic coordinates */ -data class Coordinates ( +data class CoordinatesResponse ( @Json(name = "latitude") val latitude: kotlin.Float, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CreateDeviceRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CreateDeviceRequest.kt index f61b31333fc..864fbf13507 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CreateDeviceRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/CreateDeviceRequest.kt @@ -45,6 +45,9 @@ data class CreateDeviceRequest ( @Json(name = "push_provider") val pushProvider: PushProvider, + @Json(name = "hardware_id") + val hardwareId: kotlin.String? = null, + @Json(name = "push_provider_name") val pushProviderName: kotlin.String? = null, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeviceResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeviceResponse.kt index 8ba795cd7b3..3437894fcac 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeviceResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeviceResponse.kt @@ -57,6 +57,9 @@ data class DeviceResponse ( @Json(name = "disabled_reason") val disabledReason: kotlin.String? = null, + @Json(name = "hardware_id") + val hardwareId: kotlin.String? = null, + @Json(name = "push_provider_name") val pushProviderName: kotlin.String? = null, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/FeedsPreferencesResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/FeedsPreferencesResponse.kt index 843633138c6..a7959eb54fa 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/FeedsPreferencesResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/FeedsPreferencesResponse.kt @@ -42,9 +42,15 @@ data class FeedsPreferencesResponse ( @Json(name = "comment") val comment: kotlin.String? = null, + @Json(name = "comment_mention") + val commentMention: kotlin.String? = null, + @Json(name = "comment_reaction") val commentReaction: kotlin.String? = null, + @Json(name = "comment_reply") + val commentReply: kotlin.String? = null, + @Json(name = "follow") val follow: kotlin.String? = null, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ICEServer.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ICEServer.kt index 00d727d69ac..121d977e229 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ICEServer.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ICEServer.kt @@ -35,7 +35,7 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * ICE server configuration for WebRTC connections */ data class ICEServer ( diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsRequest.kt index 1356d5e2a3b..c4bed824528 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsRequest.kt @@ -40,7 +40,10 @@ import com.squareup.moshi.ToJson data class IndividualRecordingSettingsRequest ( @Json(name = "mode") - val mode: Mode + val mode: Mode, + + @Json(name = "output_types") + val outputTypes: kotlin.collections.List? = emptyList() ) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsResponse.kt index e08e63ea85d..eef0586d67b 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/IndividualRecordingSettingsResponse.kt @@ -40,7 +40,10 @@ import com.squareup.moshi.ToJson data class IndividualRecordingSettingsResponse ( @Json(name = "mode") - val mode: Mode + val mode: Mode, + + @Json(name = "output_types") + val outputTypes: kotlin.collections.List? = emptyList() ) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/JoinCallRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/JoinCallRequest.kt index ef10fba56c0..6847ae63337 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/JoinCallRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/JoinCallRequest.kt @@ -45,15 +45,15 @@ data class JoinCallRequest ( @Json(name = "create") val create: kotlin.Boolean? = null, + @Json(name = "hint_high_scale_livestream_publisher") + val hintHighScaleLivestreamPublisher: kotlin.Boolean? = null, + @Json(name = "members_limit") val membersLimit: kotlin.Int? = null, @Json(name = "migrating_from") val migratingFrom: kotlin.String? = null, - @Json(name = "migrating_from_list") - val migratingFromList: kotlin.collections.List? = null, - @Json(name = "notify") val notify: kotlin.Boolean? = null, @@ -63,9 +63,9 @@ data class JoinCallRequest ( @Json(name = "video") val video: kotlin.Boolean? = null, - @Json(name = "data") - val data: io.getstream.android.video.generated.models.CallRequest? = null, + @Json(name = "migrating_from_list") + val migratingFromList: kotlin.collections.List? = emptyList(), - @Json(name = "hint_high_scale_livestream_publisher") - val hintHighScaleLivestreamPublisher: kotlin.Boolean? = null + @Json(name = "data") + val data: io.getstream.android.video.generated.models.CallRequest? = null ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Location.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/LocationResponse.kt similarity index 95% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Location.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/LocationResponse.kt index 04d8c09a45a..59506265fea 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/Location.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/LocationResponse.kt @@ -35,10 +35,10 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * Geographic location metadata */ -data class Location ( +data class LocationResponse ( @Json(name = "continent_code") val continentCode: kotlin.String, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PushPreferencesResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PushPreferencesResponse.kt index 3f077dcd089..f917dbaa12f 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PushPreferencesResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PushPreferencesResponse.kt @@ -51,6 +51,9 @@ data class PushPreferencesResponse ( @Json(name = "feeds_level") val feedsLevel: kotlin.String? = null, + @Json(name = "chat_preferences") + val chatPreferences: io.getstream.android.video.generated.models.ChatPreferencesResponse? = null, + @Json(name = "feeds_preferences") val feedsPreferences: io.getstream.android.video.generated.models.FeedsPreferencesResponse? = null ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse.kt index d80a7b2be92..caf03241048 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionParticipantStatsResponse.kt @@ -70,5 +70,8 @@ data class QueryCallSessionParticipantStatsResponse ( val prev: kotlin.String? = null, @Json(name = "tmp_data_source") - val tmpDataSource: kotlin.String? = null + val tmpDataSource: kotlin.String? = null, + + @Json(name = "call_events") + val callEvents: kotlin.collections.List? = emptyList() ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsRequest.kt new file mode 100644 index 00000000000..f663ebc93ad --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsRequest.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * + */ + +data class QueryCallSessionStatsRequest ( + @Json(name = "limit") + val limit: kotlin.Int? = null, + + @Json(name = "next") + val next: kotlin.String? = null, + + @Json(name = "prev") + val prev: kotlin.String? = null, + + @Json(name = "sort") + val sort: kotlin.collections.List? = emptyList(), + + @Json(name = "filter_conditions") + val filterConditions: kotlin.collections.Map? = emptyMap() +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsResponse.kt new file mode 100644 index 00000000000..4a6184828c8 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/QueryCallSessionStatsResponse.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * Basic response information + */ + +data class QueryCallSessionStatsResponse ( + @Json(name = "duration") + val duration: kotlin.String, + + @Json(name = "call_stats") + val callStats: kotlin.collections.List = emptyList(), + + @Json(name = "next") + val next: kotlin.String? = null, + + @Json(name = "prev") + val prev: kotlin.String? = null +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsRequest.kt index b09284cea3a..ea05930e912 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsRequest.kt @@ -40,7 +40,10 @@ import com.squareup.moshi.ToJson data class RawRecordingSettingsRequest ( @Json(name = "mode") - val mode: Mode + val mode: Mode, + + @Json(name = "audio_only") + val audioOnly: kotlin.Boolean? = null ) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsResponse.kt index a2c7bbf04d9..8787ee437f3 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/RawRecordingSettingsResponse.kt @@ -40,7 +40,10 @@ import com.squareup.moshi.ToJson data class RawRecordingSettingsResponse ( @Json(name = "mode") - val mode: Mode + val mode: Mode, + + @Json(name = "audio_only") + val audioOnly: kotlin.Boolean? = null ) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventRequest.kt new file mode 100644 index 00000000000..7e3d7ba91c1 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventRequest.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * Reports a batch of client-side telemetry events. Each event is validated and processed independently; one invalid event does not block the rest of the batch. + */ + +data class ReportClientEventRequest ( + @Json(name = "events") + val events: kotlin.collections.List = emptyList() +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeliveryReceipts.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventResponse.kt similarity index 87% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeliveryReceipts.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventResponse.kt index 1896c2be46f..3406dafe068 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/DeliveryReceipts.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ReportClientEventResponse.kt @@ -35,10 +35,10 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * Response for reporting client-side telemetry events */ -data class DeliveryReceipts ( - @Json(name = "enabled") - val enabled: kotlin.Boolean +data class ReportClientEventResponse ( + @Json(name = "duration") + val duration: kotlin.String ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthRequest.kt new file mode 100644 index 00000000000..9a4edebad10 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthRequest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * Request to determine SIP trunk authentication requirements + */ + +data class ResolveSipAuthRequest ( + @Json(name = "sip_caller_number") + val sipCallerNumber: kotlin.String, + + @Json(name = "sip_trunk_number") + val sipTrunkNumber: kotlin.String, + + @Json(name = "from_host") + val fromHost: kotlin.String? = null, + + @Json(name = "source_ip") + val sourceIp: kotlin.String? = null +) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PrivacySettings.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthResponse.kt similarity index 71% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PrivacySettings.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthResponse.kt index 44f611ec9ac..3719bfff87b 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/PrivacySettings.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipAuthResponse.kt @@ -35,16 +35,22 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * Response containing the pre-authentication decision for a SIP trunk */ -data class PrivacySettings ( - @Json(name = "delivery_receipts") - val deliveryReceipts: io.getstream.android.video.generated.models.DeliveryReceipts? = null, +data class ResolveSipAuthResponse ( + @Json(name = "auth_result") + val authResult: kotlin.String, - @Json(name = "read_receipts") - val readReceipts: io.getstream.android.video.generated.models.ReadReceipts? = null, + @Json(name = "duration") + val duration: kotlin.String, - @Json(name = "typing_indicators") - val typingIndicators: io.getstream.android.video.generated.models.TypingIndicators? = null + @Json(name = "password") + val password: kotlin.String? = null, + + @Json(name = "trunk_id") + val trunkId: kotlin.String? = null, + + @Json(name = "username") + val username: kotlin.String? = null ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipInboundRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipInboundRequest.kt index 89dd1902e9b..0492f2ebb06 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipInboundRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/ResolveSipInboundRequest.kt @@ -45,12 +45,15 @@ data class ResolveSipInboundRequest ( @Json(name = "sip_trunk_number") val sipTrunkNumber: kotlin.String, - @Json(name = "challenge") - val challenge: io.getstream.android.video.generated.models.SIPChallenge, - @Json(name = "routing_number") val routingNumber: kotlin.String? = null, + @Json(name = "trunk_id") + val trunkId: kotlin.String? = null, + + @Json(name = "challenge") + val challenge: io.getstream.android.video.generated.models.SIPChallengeRequest? = null, + @Json(name = "sip_headers") val sipHeaders: kotlin.collections.Map? = emptyMap() ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SFULocationResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SFULocationResponse.kt index 87aac384f26..bebb6398910 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SFULocationResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SFULocationResponse.kt @@ -46,10 +46,10 @@ data class SFULocationResponse ( val id: kotlin.String, @Json(name = "coordinates") - val coordinates: io.getstream.android.video.generated.models.Coordinates, + val coordinates: io.getstream.android.video.generated.models.CoordinatesResponse, @Json(name = "location") - val location: io.getstream.android.video.generated.models.Location, + val location: io.getstream.android.video.generated.models.LocationResponse, @Json(name = "count") val count: kotlin.Int? = null diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallenge.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallengeRequest.kt similarity index 96% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallenge.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallengeRequest.kt index e6ee0932acc..7522eefb8da 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallenge.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPChallengeRequest.kt @@ -35,10 +35,10 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * SIP digest challenge authentication data */ -data class SIPChallenge ( +data class SIPChallengeRequest ( @Json(name = "a1") val a1: kotlin.String? = null, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPTrunkResponse.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPTrunkResponse.kt index 443059f75ac..7cec3dd240b 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPTrunkResponse.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SIPTrunkResponse.kt @@ -60,6 +60,9 @@ data class SIPTrunkResponse ( @Json(name = "username") val username: kotlin.String, + @Json(name = "allowed_ips") + val allowedIps: kotlin.collections.List = emptyList(), + @Json(name = "numbers") val numbers: kotlin.collections.List = emptyList() ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SipInboundCredentials.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SipInboundCredentials.kt index 72e16aaa232..6806b56102f 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SipInboundCredentials.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SipInboundCredentials.kt @@ -39,6 +39,9 @@ import com.squareup.moshi.ToJson */ data class SipInboundCredentials ( + @Json(name = "api_key") + val apiKey: kotlin.String, + @Json(name = "call_id") val callId: kotlin.String, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SortParamRequest.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SortParamRequest.kt index de682733e84..2ec5e310295 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SortParamRequest.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/SortParamRequest.kt @@ -46,41 +46,5 @@ data class SortParamRequest ( val field: kotlin.String? = null, @Json(name = "type") - val type: Type? = null + val type: kotlin.String? = null ) -{ - - /** - * Type Enum - */ - sealed class Type(val value: kotlin.String) { - override fun toString(): String = value - - companion object { - fun fromString(s: kotlin.String): Type = when (s) { - "boolean" -> Boolean - "" -> Empty - "number" -> Number - else -> Unknown(s) - } - } - object Boolean : Type("boolean") - object Empty : Type("") - object Number : Type("number") - data class Unknown(val unknownValue: kotlin.String) : Type(unknownValue) - - - class TypeAdapter : JsonAdapter() { - @FromJson - override fun fromJson(reader: JsonReader): Type? { - val s = reader.nextString() ?: return null - return Type.fromString(s) - } - - @ToJson - override fun toJson(writer: JsonWriter, value: Type?) { - writer.value(value?.value) - } - } - } -} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserBannedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserBannedEvent.kt index e98e0e668b2..008505dc948 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserBannedEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserBannedEvent.kt @@ -35,42 +35,60 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * This event is sent when a user gets banned. The event contains information about the user that was banned. */ data class UserBannedEvent ( - @Json(name = "channel_id") - val channelId: kotlin.String, - - @Json(name = "channel_type") - val channelType: kotlin.String, - - @Json(name = "cid") - val cid: kotlin.String, - @Json(name = "created_at") val createdAt: org.threeten.bp.OffsetDateTime, - @Json(name = "shadow") - val shadow: kotlin.Boolean, + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), - @Json(name = "created_by") - val createdBy: io.getstream.android.video.generated.models.User, + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, @Json(name = "type") val type: kotlin.String, + @Json(name = "channel_id") + val channelId: kotlin.String? = null, + + @Json(name = "channel_member_count") + val channelMemberCount: kotlin.Int? = null, + + @Json(name = "channel_message_count") + val channelMessageCount: kotlin.Int? = null, + + @Json(name = "channel_type") + val channelType: kotlin.String? = null, + + @Json(name = "cid") + val cid: kotlin.String? = null, + @Json(name = "expiration") val expiration: org.threeten.bp.OffsetDateTime? = null, @Json(name = "reason") val reason: kotlin.String? = null, + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "shadow") + val shadow: kotlin.Boolean? = null, + @Json(name = "team") val team: kotlin.String? = null, - @Json(name = "user") - val user: io.getstream.android.video.generated.models.User? = null + @Json(name = "total_bans") + val totalBans: kotlin.Int? = null, + + @Json(name = "channel_custom") + val channelCustom: kotlin.collections.Map? = emptyMap(), + + @Json(name = "created_by") + val createdBy: io.getstream.android.video.generated.models.UserResponseCommonFields? = null ) : io.getstream.android.video.generated.models.VideoEvent() { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeactivatedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeactivatedEvent.kt index 3c8c12a9cb2..9ca1f481ccd 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeactivatedEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeactivatedEvent.kt @@ -35,21 +35,27 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * This event is sent when a user gets deactivated. The event contains information about the user that was deactivated. */ data class UserDeactivatedEvent ( @Json(name = "created_at") val createdAt: org.threeten.bp.OffsetDateTime, - @Json(name = "created_by") - val createdBy: io.getstream.android.video.generated.models.User, + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), + + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, @Json(name = "type") val type: kotlin.String, - @Json(name = "user") - val user: io.getstream.android.video.generated.models.User? = null + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "created_by") + val createdBy: io.getstream.android.video.generated.models.UserResponseCommonFields? = null ) : io.getstream.android.video.generated.models.VideoEvent() { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeletedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeletedEvent.kt new file mode 100644 index 00000000000..77da9110465 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserDeletedEvent.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * This event is sent when a user gets deleted. The event contains information about the user that was deleted and the deletion options that were used. + */ + +data class UserDeletedEvent ( + @Json(name = "created_at") + val createdAt: org.threeten.bp.OffsetDateTime, + + @Json(name = "delete_conversation") + val deleteConversation: kotlin.String, + + @Json(name = "delete_conversation_channels") + val deleteConversationChannels: kotlin.Boolean, + + @Json(name = "delete_messages") + val deleteMessages: kotlin.String, + + @Json(name = "delete_user") + val deleteUser: kotlin.String, + + @Json(name = "hard_delete") + val hardDelete: kotlin.Boolean, + + @Json(name = "mark_messages_deleted") + val markMessagesDeleted: kotlin.Boolean, + + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), + + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, + + @Json(name = "type") + val type: kotlin.String, + + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null +) +: io.getstream.android.video.generated.models.VideoEvent() +{ + + override fun getEventType(): kotlin.String { + return type + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserMutedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserPresenceChangedEvent.kt similarity index 76% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserMutedEvent.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserPresenceChangedEvent.kt index 19d35c49d9b..8d97219f8c5 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserMutedEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserPresenceChangedEvent.kt @@ -35,24 +35,24 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * This event is sent when the presence of a user changes. The event contains information about the user whose presence changed. */ -data class UserMutedEvent ( +data class UserPresenceChangedEvent ( @Json(name = "created_at") val createdAt: org.threeten.bp.OffsetDateTime, - @Json(name = "type") - val type: kotlin.String, + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), - @Json(name = "target_user") - val targetUser: kotlin.String? = null, + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, - @Json(name = "target_users") - val targetUsers: kotlin.collections.List? = emptyList(), + @Json(name = "type") + val type: kotlin.String, - @Json(name = "user") - val user: io.getstream.android.video.generated.models.User? = null + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null ) : io.getstream.android.video.generated.models.VideoEvent() { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserReactivatedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserReactivatedEvent.kt index 09930a30f81..b71868f47a9 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserReactivatedEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserReactivatedEvent.kt @@ -35,18 +35,27 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson /** - * + * This event is sent when a user gets reactivated. The event contains information about the user that was reactivated. */ data class UserReactivatedEvent ( @Json(name = "created_at") val createdAt: org.threeten.bp.OffsetDateTime, + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), + + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, + @Json(name = "type") val type: kotlin.String, - @Json(name = "user") - val user: io.getstream.android.video.generated.models.User? = null + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "created_by") + val createdBy: io.getstream.android.video.generated.models.UserResponseCommonFields? = null ) : io.getstream.android.video.generated.models.VideoEvent() { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/User.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserResponseCommonFields.kt similarity index 75% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/User.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserResponseCommonFields.kt index e1d3012223c..9ea07b69851 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/User.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserResponseCommonFields.kt @@ -38,58 +38,52 @@ import com.squareup.moshi.ToJson * */ -data class User ( - @Json(name = "banned") - val banned: kotlin.Boolean, +data class UserResponseCommonFields ( + @Json(name = "created_at") + val createdAt: org.threeten.bp.OffsetDateTime, @Json(name = "id") val id: kotlin.String, - @Json(name = "online") - val online: kotlin.Boolean, + @Json(name = "language") + val language: kotlin.String, @Json(name = "role") val role: kotlin.String, + @Json(name = "updated_at") + val updatedAt: org.threeten.bp.OffsetDateTime, + + @Json(name = "blocked_user_ids") + val blockedUserIds: kotlin.collections.List = emptyList(), + + @Json(name = "teams") + val teams: kotlin.collections.List = emptyList(), + @Json(name = "custom") val custom: kotlin.collections.Map = emptyMap(), - @Json(name = "teams_role") - val teamsRole: kotlin.collections.Map = emptyMap(), - @Json(name = "avg_response_time") val avgResponseTime: kotlin.Int? = null, - @Json(name = "ban_expires") - val banExpires: org.threeten.bp.OffsetDateTime? = null, - - @Json(name = "created_at") - val createdAt: org.threeten.bp.OffsetDateTime? = null, - @Json(name = "deactivated_at") val deactivatedAt: org.threeten.bp.OffsetDateTime? = null, @Json(name = "deleted_at") val deletedAt: org.threeten.bp.OffsetDateTime? = null, - @Json(name = "invisible") - val invisible: kotlin.Boolean? = null, - - @Json(name = "language") - val language: kotlin.String? = null, + @Json(name = "image") + val image: kotlin.String? = null, @Json(name = "last_active") val lastActive: org.threeten.bp.OffsetDateTime? = null, - @Json(name = "last_engaged_at") - val lastEngagedAt: org.threeten.bp.OffsetDateTime? = null, + @Json(name = "name") + val name: kotlin.String? = null, @Json(name = "revoke_tokens_issued_before") val revokeTokensIssuedBefore: org.threeten.bp.OffsetDateTime? = null, - @Json(name = "updated_at") - val updatedAt: org.threeten.bp.OffsetDateTime? = null, - - @Json(name = "teams") - val teams: kotlin.collections.List? = emptyList() + @Json(name = "teams_role") + val teamsRole: kotlin.collections.Map? = emptyMap() ) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserUnbannedEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserUnbannedEvent.kt new file mode 100644 index 00000000000..c958db7e299 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/UserUnbannedEvent.kt @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package io.getstream.android.video.generated.models + +import kotlin.collections.List +import kotlin.collections.Map +import kotlin.collections.* +import kotlin.io.* +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * This event is sent when a user gets unbanned. The event contains information about the user that was unbanned. + */ + +data class UserUnbannedEvent ( + @Json(name = "created_at") + val createdAt: org.threeten.bp.OffsetDateTime, + + @Json(name = "custom") + val custom: kotlin.collections.Map = emptyMap(), + + @Json(name = "user") + val user: io.getstream.android.video.generated.models.UserResponseCommonFields, + + @Json(name = "type") + val type: kotlin.String, + + @Json(name = "channel_id") + val channelId: kotlin.String? = null, + + @Json(name = "channel_member_count") + val channelMemberCount: kotlin.Int? = null, + + @Json(name = "channel_message_count") + val channelMessageCount: kotlin.Int? = null, + + @Json(name = "channel_type") + val channelType: kotlin.String? = null, + + @Json(name = "cid") + val cid: kotlin.String? = null, + + @Json(name = "received_at") + val receivedAt: org.threeten.bp.OffsetDateTime? = null, + + @Json(name = "shadow") + val shadow: kotlin.Boolean? = null, + + @Json(name = "team") + val team: kotlin.String? = null, + + @Json(name = "channel_custom") + val channelCustom: kotlin.collections.Map? = emptyMap(), + + @Json(name = "created_by") + val createdBy: io.getstream.android.video.generated.models.UserResponseCommonFields? = null +) +: io.getstream.android.video.generated.models.VideoEvent() +{ + + override fun getEventType(): kotlin.String { + return type + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/VideoEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/VideoEvent.kt index 7d31a4f07fc..90432fef7b5 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/VideoEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/VideoEvent.kt @@ -129,8 +129,10 @@ class VideoEventAdapter : JsonAdapter() { "ingress.stopped" -> io.getstream.android.video.generated.models.IngressStoppedEvent::class.java "user.banned" -> io.getstream.android.video.generated.models.UserBannedEvent::class.java "user.deactivated" -> io.getstream.android.video.generated.models.UserDeactivatedEvent::class.java - "user.muted" -> io.getstream.android.video.generated.models.UserMutedEvent::class.java + "user.deleted" -> io.getstream.android.video.generated.models.UserDeletedEvent::class.java + "user.presence.changed" -> io.getstream.android.video.generated.models.UserPresenceChangedEvent::class.java "user.reactivated" -> io.getstream.android.video.generated.models.UserReactivatedEvent::class.java + "user.unbanned" -> io.getstream.android.video.generated.models.UserUnbannedEvent::class.java "user.updated" -> io.getstream.android.video.generated.models.UserUpdatedEvent::class.java else -> UnsupportedVideoEvent::class.java } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ActiveStateGate.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ActiveStateGate.kt index 0be74b77679..403ad040e27 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ActiveStateGate.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ActiveStateGate.kt @@ -149,7 +149,12 @@ internal class ActiveStateGate( } catch (e: CallJoinInterceptionException) { val message = "[CallJoinInterceptor] aborted with reason: ${e.reason}" logger.e(e) { message } - call.leave(reason = message) + call.leave( + CallLeaveReason.UserAction( + cause = UserActionCause.CALL_JOIN_ABORT, + message = e.reason, + ), + ) clearAllJobs() false } catch (e: Exception) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt index 7234a5a77a0..5a6aebfac9d 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt @@ -60,6 +60,8 @@ import io.getstream.result.Result import io.getstream.result.Result.Failure import io.getstream.result.Result.Success import io.getstream.result.flatMap +import io.getstream.video.android.core.analytics.CallAnalyticsCoordinator +import io.getstream.video.android.core.analytics.observer.model.TelemetryModel import io.getstream.video.android.core.audio.StreamAudioDevice import io.getstream.video.android.core.call.FastReconnectResult import io.getstream.video.android.core.call.RtcSession @@ -138,13 +140,14 @@ import kotlin.coroutines.resume level = DeprecationLevel.WARNING, ) const val sfuReconnectTimeoutMillis = 30_000 +internal typealias CallSessionId = String /** * Outcome of a single reconnect attempt. Each reconnect method returns one of * these instead of throwing, making the control flow in the reconnect loop * explicit and exhaustively checked by the compiler. */ -private sealed class ReconnectOutcome { +internal sealed class ReconnectOutcome { /** Reconnect succeeded — exit the loop. */ object Success : ReconnectOutcome() @@ -313,6 +316,17 @@ public class Call( _peerConnectionFactory = value } + internal val callAnalyticsCoordinator = + CallAnalyticsCoordinator( + clientImpl.context, + this.id, + this.type, + state.connection, + state.participants, + client.state.clientEventReporter, + scope, + ) + /** * Checks if the audioBitrateProfile has changed since the factory was created, * and recreates the factory if needed. This should only be called before joining. @@ -430,10 +444,11 @@ public class Call( } return@launch } + val message = "Leaving after being disconnected for ${clientImpl.leaveAfterDisconnectSeconds}" logger.d { - "[NetworkStateListener#onDisconnected] #network; Leaving after being disconnected for ${clientImpl.leaveAfterDisconnectSeconds} (connection=$conn)" + "[NetworkStateListener#onDisconnected] #network; $message (connection=$conn)" } - leave() + leave(CallLeaveReason.Backend(cause = BackendCause.LEAVE_TIMEOUT_AFTER_DISCONNECT, message = message)) // TODO Rahul before merge } logger.d { "[NetworkStateListener#onDisconnected] #network; at $lastDisconnect" } } @@ -449,6 +464,8 @@ public class Call( private var sfuListener: Job? = null private var sfuEvents: Job? = null + /** Reports join lifecycle events to the backend for success-rate analytics. Set by StreamVideoClient. */ + init { scope.launch { soundInputProcessor.currentAudioLevel.collect { @@ -550,6 +567,8 @@ public class Call( hintHighScaleLivestreamPublisher: Boolean? = null, callJoinInterceptor: CallJoinInterceptor? = null, ): Result { + callAnalyticsCoordinator.joinObserver.onJoinFunctionStart() + callAnalyticsCoordinator.mediaPermissionObserver.mediaPermissionStatus() logger.d { "[join] #ringing; #track; create: $create, ring: $ring, notify: $notify, createOptions: $createOptions" } @@ -584,8 +603,16 @@ public class Call( atomicLeave = AtomicUnitCall() while (retryCount < 3) { - result = _join(create, createOptions, ring, notify, hintHighScaleLivestreamPublisher) - if (result is Success) { + val tempResult = + _join( + create, + createOptions, + ring, + notify, + hintHighScaleLivestreamPublisher, + TelemetryModel(retryCount), + ) + if (tempResult is Success) { // we initialise the camera, mic and other according to local + backend settings // only when the call is joined to make sure we don't switch and override // the settings during a call. @@ -598,13 +625,20 @@ public class Call( "is joined. MediaManager will not be initialised with server settings." } } + + result = Success(tempResult.value.first) return result } - if (result is Failure) { + if (tempResult is Failure) { + result = tempResult session.value = null logger.e { "Join failed with error $result" } if (isPermanentError(result.value)) { state._connection.value = RealtimeConnection.Failed(result.value) + callAnalyticsCoordinator.joinObserver.onJoinRequestPermanentError( + retryCount, + result.value.message, + ) return result } else { retryCount += 1 @@ -615,6 +649,10 @@ public class Call( session.value = null val errorMessage = "Join failed after 3 retries" state._connection.value = RealtimeConnection.Failed(errorMessage) + callAnalyticsCoordinator.joinObserver.onJoinRequestRetryExhausted( + retryCount, + errorMessage, + ) return Failure(value = Error.GenericError(errorMessage)) } @@ -639,7 +677,12 @@ public class Call( }.onError { logger.e { "[joinAndRing] Ring failed #ringing; #track; error: $it" } state.toggleJoinAndRingProgress(false) - leave("ring-failed (${it.message})") + leave( + CallLeaveReason.Backend( + BackendCause.RING_FAILED, + message = "ring-failed (${it.message})", + ), + ) } } } @@ -659,7 +702,8 @@ public class Call( ring: Boolean = false, notify: Boolean = false, hintHighScaleLivestreamPublisher: Boolean? = null, - ): Result { + telemetryModel: TelemetryModel, + ): Result> { nonFastReconnectAttempts = 0 sfuEvents?.cancel() sfuListener?.cancel() @@ -675,10 +719,9 @@ public class Call( // step 1. call the join endpoint to get a list of SFUs val locationResult = clientImpl.getCachedLocation() - if (locationResult !is Success) { - return locationResult as Failure + if (locationResult is Success) { + location = locationResult.value } - location = locationResult.value val options = createOptions ?: if (create) { @@ -689,10 +732,11 @@ public class Call( val result = joinRequest( options, - locationResult.value, + location ?: "auto", ring = ring, notify = notify, hintHighScaleLivestreamPublisher = hintHighScaleLivestreamPublisher, + telemetryModel = telemetryModel, ) if (result !is Success) { @@ -737,7 +781,7 @@ public class Call( } client.state.setActiveCall(this) monitorSession(result.value) - return Success(value = session.value!!) + return Success(value = Pair(session.value!!, result.value.call.currentSessionId)) } private fun Call.monitorSession(result: JoinCallResponse) { @@ -756,7 +800,8 @@ public class Call( } } monitorPublisherPCStateJob?.cancel() - + callAnalyticsCoordinator.peerConnectionObserver.stop() + callAnalyticsCoordinator.peerConnectionObserver.observePeerConnections(session) monitorPublisherPCStateJob = scope.launch { session .filterNotNull() @@ -769,7 +814,7 @@ public class Call( PeerConnection.IceConnectionState.FAILED, PeerConnection.IceConnectionState.DISCONNECTED, -> { - publisher.connection.restartIce() + publisher.connection.restartIce() // TODO Rahul might send a request to the server } else -> { logger.d { "[monitorPubConnectionState] Ice connection state is $state" } @@ -783,7 +828,7 @@ public class Call( session.value?.subscriber?.value?.iceState?.collect { when (it) { PeerConnection.IceConnectionState.FAILED, PeerConnection.IceConnectionState.DISCONNECTED -> { - session.value?.requestSubscriberIceRestart() + session.value?.requestSubscriberIceRestart() // TODO Rahul might send a request to the server } else -> { @@ -963,16 +1008,16 @@ public class Call( val outcome = when (currentStrategy) { WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_FAST, WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_UNSPECIFIED, - -> reconnectFast(reason) + -> { reconnectFast(reason, TelemetryModel(loopIteration)) } WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_REJOIN -> { nonFastReconnectAttempts++ - reconnectRejoin(reason) + reconnectRejoin(reason, TelemetryModel(nonFastReconnectAttempts)) } WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_MIGRATE -> { nonFastReconnectAttempts++ - reconnectMigrate() + reconnectMigrate(TelemetryModel(nonFastReconnectAttempts)) } WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_DISCONNECT -> @@ -984,7 +1029,9 @@ public class Call( is ReconnectOutcome.Disconnect -> { logger.w { "[reconnect] DISCONNECT requested — leaving call" } - leave("SFU:DISCONNECT") + leave( + CallLeaveReason.Backend(BackendCause.SFU_DISCONNECT, "SFU:DISCONNECT"), + ) break } @@ -1026,7 +1073,17 @@ public class Call( if (state.connection.value is RealtimeConnection.ReconnectingFailed) { logger.w { "[reconnect] All recovery attempts exhausted — leaving call ($reason)" } - leave("reconnect-failed:$reason") + callAnalyticsCoordinator.joinObserver.onJoinRequestRetryExhausted( + loopIteration, + "All recovery attempts exhausted — leaving call ($reason)", + ) + leave( + CallLeaveReason.RetryExhausted( + loopIteration, + "reconnect-failed", + "All recovery attempts exhausted — leaving call ($reason)", + ), + ) } } finally { // Always release the mutex — even on exceptions or coroutine @@ -1043,7 +1100,10 @@ public class Call( * Reuses the existing session ID — no previous_session_id needed since the * SFU already knows this participant. */ - private suspend fun reconnectFast(reason: String): ReconnectOutcome { + private suspend fun reconnectFast( + reason: String, + telemetryModel: TelemetryModel? = null, + ): ReconnectOutcome { logger.d { "[reconnectFast] reconnectAttempts=$nonFastReconnectAttempts" } val currentSession = session.value ?: return ReconnectOutcome.PreconditionNotMet("No active session for fast reconnect") @@ -1064,7 +1124,7 @@ public class Call( reconnect_attempt = nonFastReconnectAttempts, reason = reason, ) - return when (val result = currentSession.fastReconnect(reconnectDetails)) { + return when (val result = currentSession.fastReconnect(reconnectDetails, telemetryModel)) { is FastReconnectResult.Connected -> ReconnectOutcome.Success is FastReconnectResult.PeerConnectionStale -> ReconnectOutcome.PeerConnectionStale is FastReconnectResult.Failed -> ReconnectOutcome.Failed(result.error) @@ -1076,16 +1136,20 @@ public class Call( * previous_session_id is set so the SFU can transfer state (tracks, * subscriptions) from the old session to the new one. */ - private suspend fun reconnectRejoin(reason: String): ReconnectOutcome { + private suspend fun reconnectRejoin( + reason: String, + telemetryModel: TelemetryModel, + ): ReconnectOutcome { logger.d { "[reconnectRejoin] reconnectAttempts=$nonFastReconnectAttempts" } state._connection.value = RealtimeConnection.Reconnecting - val loc = location - ?: return ReconnectOutcome.PreconditionNotMet("No location available for rejoin") + val loc = location ?: "auto" +// ?: return ReconnectOutcome.PreconditionNotMet("No location available for rejoin") val oldSession = session.value ?: return ReconnectOutcome.PreconditionNotMet("No active session for rejoin") reconnectStartTime = System.currentTimeMillis() - val joinResponse = joinRequest(location = loc) + val joinResponse = + joinRequest(location = loc, telemetryModel = telemetryModel) if (joinResponse !is Success) { return ReconnectOutcome.Failed( Exception("Failed to get join response: ${joinResponse.errorOrNull()}"), @@ -1124,7 +1188,13 @@ public class Call( ) this.session.value = newSession - return when (val result = newSession.connectInternal(reconnectDetails, currentOptions)) { + return when ( + val result = newSession.connectInternal( + reconnectDetails, + currentOptions, + TelemetryModel(telemetryModel.retryAttempt), + ) + ) { is SfuConnectionResult.Connected -> { newSession.sfuTracer.trace("rejoin", reason) monitorSession(joinResponse.value) @@ -1138,17 +1208,22 @@ public class Call( * Migrate to another SFU. Reuses the same session ID — the SFU * identifies the participant via from_sfu_id, not previous_session_id. */ - private suspend fun reconnectMigrate(): ReconnectOutcome { + private suspend fun reconnectMigrate(telemetryModel: TelemetryModel): ReconnectOutcome { logger.d { "[reconnectMigrate] Migrating" } state._connection.value = RealtimeConnection.Migrating - val loc = location - ?: return ReconnectOutcome.PreconditionNotMet("No location available for migrate") + val loc = location ?: "auto" +// ?: return ReconnectOutcome.PreconditionNotMet("No location available for migrate") val oldSession = session.value ?: return ReconnectOutcome.PreconditionNotMet("No active session for migrate") reconnectStartTime = System.currentTimeMillis() addFailedSfuId(oldSession.sfuName) - val joinResponse = joinRequest(location = loc, migratingFrom = oldSession.sfuName) + val joinResponse = + joinRequest( + location = loc, + migratingFrom = oldSession.sfuName, + telemetryModel = telemetryModel, + ) if (joinResponse !is Success) { return ReconnectOutcome.Failed( Exception( @@ -1193,7 +1268,11 @@ public class Call( this.session.value = newSession return try { - val result = newSession.connectInternal(reconnectDetails, currentOptions) + val result = newSession.connectInternal( + reconnectDetails, + currentOptions, + TelemetryModel(telemetryModel.retryAttempt), + ) when (result) { is SfuConnectionResult.Connected -> { monitorSession(joinResponse.value) @@ -1222,14 +1301,21 @@ public class Call( // endregion /** Leave the call, but don't end it for other users */ + @InternalStreamVideoApi + fun leave(reason: CallLeaveReason) { + logger.d { "[leave] #ringing; call_cid:$cid" } + internalLeave(reason) + } + fun leave(reason: String = "user") { logger.d { "[leave] #ringing; no args, call_cid:$cid" } - internalLeave(null, reason) + internalLeave(CallLeaveReason.Custom(reason)) } - private fun internalLeave(disconnectionReason: Throwable?, reason: String) = atomicLeave { + private fun internalLeave(reason: CallLeaveReason) = atomicLeave { monitorSubscriberPCStateJob?.cancel() monitorPublisherPCStateJob?.cancel() + callAnalyticsCoordinator.stopObservers() monitorPublisherPCStateJob = null monitorSubscriberPCStateJob = null leaveTimeoutAfterDisconnect?.cancel() @@ -1237,7 +1323,7 @@ public class Call( sfuListener?.cancel() sfuEvents?.cancel() state._connection.value = RealtimeConnection.Disconnected - logger.v { "[leave] #ringing; disconnectionReason: $disconnectionReason, call_id = $id" } + logger.v { "[leave] #ringing; call_id = $id" } if (isDestroyed) { logger.w { "[leave] #ringing; Call already destroyed, ignoring" } return@atomicLeave @@ -1267,7 +1353,9 @@ public class Call( (client as StreamVideoClient).onCallCleanUp(this) clientImpl.scope.launch { - val leaveReason = "[reason=$reason, error=${disconnectionReason?.message}]" + val leaveReason = "[reason=${reason::class.simpleName}, message=${reason.message}]" + callAnalyticsCoordinator.onCallLeave(reason) + safeCall { session.value?.sfuTracer?.trace("leave-call", leaveReason) val stats = collectStats() @@ -1284,7 +1372,12 @@ public class Call( // end the call for everyone val result = clientImpl.endCall(type, id) // cleanup - leave("call-ended") + leave( + CallLeaveReason.SdkDriven( + cause = SdkCause.END_CALL, + message = "CALL_ENDED", // Call ended by local user + ), + ) return result } @@ -1410,7 +1503,7 @@ public class Call( val width = videoRenderer.measuredWidth val height = videoRenderer.measuredHeight logger.i { - "[initRenderer.onFirstFrameRendered] #sfu; #track; " + + "noob [initRenderer.onFirstFrameRendered] #sfu; #track; " + "trackType: $trackType, dimension: ($width - $height), " + "sessionId: $sessionId" } @@ -1424,6 +1517,14 @@ public class Call( ) } onRendered(videoRenderer) + callAnalyticsCoordinator.videoObserver.firstVideoFrameRendered( + trackType, + width, + height, + session.value, + sessionId, + this@Call.sessionId, + ) } override fun onFrameResolutionChanged( @@ -1802,7 +1903,9 @@ public class Call( ring: Boolean = false, notify: Boolean = false, hintHighScaleLivestreamPublisher: Boolean? = null, + telemetryModel: TelemetryModel, ): Result { + callAnalyticsCoordinator.joinObserver.onJoinRequestStart() val migratingFromList = migratingFromList ?: getFailedSfuIdsSnapshot().takeIf { it.isNotEmpty() } val result = clientImpl.joinCall( type, id, @@ -1820,6 +1923,10 @@ public class Call( hintHighScaleLivestreamPublisher = hintHighScaleLivestreamPublisher, ) result.onSuccess { + callAnalyticsCoordinator.joinObserver.onJoinRequestSuccess( + telemetryModel, + it.call.currentSessionId, + ) state.updateFromResponse(it) } return result diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallLeaveReason.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallLeaveReason.kt new file mode 100644 index 00000000000..e29c2f43a9e --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallLeaveReason.kt @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core + +import io.getstream.video.android.core.internal.InternalStreamVideoApi + +@InternalStreamVideoApi +sealed interface CallLeaveReason { + + val message: String? + + val metadata: Map + + /** The local user explicitly chose to leave. */ + data class UserAction( + val cause: UserActionCause, + override val message: String? = null, + override val metadata: Map = emptyMap(), + ) : CallLeaveReason + + /** The backend ended or rejected the call (CallEndedEvent, SFU termination, etc.). */ + data class Backend( + val cause: BackendCause, + override val message: String?, + override val metadata: Map = emptyMap(), + ) : CallLeaveReason + + /** All reconnect attempts were exhausted after a network or SFU failure. */ + data class RetryExhausted( + val retryCount: Int, + val failureCode: String?, + override val message: String?, + override val metadata: Map = emptyMap(), + ) : CallLeaveReason + + /** A platform/system event (task removal, hold, wearable, interceptor, etc.) caused the leave. */ + data class SdkDriven( + val cause: SdkCause, + override val message: String? = null, + override val metadata: Map = emptyMap(), + ) : CallLeaveReason + + /** SDK consumer supplied an arbitrary reason. */ + data class Custom( + override val message: String? = null, + override val metadata: Map = emptyMap(), + ) : CallLeaveReason +} + +@InternalStreamVideoApi +enum class SdkCause { + /** App was swiped from the recents screen. */ + TASK_REMOVED, + + /** Telecom system put the call on hold for another call. */ + CALL_ON_HOLD, + + /** SDK-level cleanup (e.g. logout, StreamVideo instance teardown). */ + CLIENT_CLEANUP, + + /** Outgoing call auto-cancel timeout elapsed with no answer. */ + RING_TIMEOUT, + + ACCEPTED_ON_OTHER_DEVICE, + LOCAL_CALL_MISSED_EVENT, + REJECTED_BY_ALL, + END_CALL, + PIP_ERROR, + PIP_STOPPED, + ACTIVITY_DESTROYED, + STREAM_CALL_ACTIVITY_EXCEPTION, +} + +@InternalStreamVideoApi +enum class UserActionCause { + /** User rejected the call from a paired wearable device. */ + WEARABLE_REJECTED, + WEARABLE_CANCEL, + + /** A [io.getstream.video.android.core.CallJoinInterceptor] aborted the join sequence. */ + CALL_JOIN_ABORT, + REJECTED_BY_SELF, + CANCELLED_BY_SELF, + LEAVE_FROM_NOTIFICATION, +} + +@InternalStreamVideoApi +enum class BackendCause { + LEAVE_TIMEOUT_AFTER_DISCONNECT, + SFU_DISCONNECT, + CALL_ENDED_EVENT, + CALL_ENDED_SFU_EVENT, + RING_FAILED, +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt index 5b27c97ca14..8a8a4080561 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt @@ -837,7 +837,14 @@ public class CallState( } else if (callRingState is RingingState.Incoming && event.user.id == client.userId) { // Call accepted by me + this device is Incoming => I accepted on another device // Then leave the call on this device - if (!acceptedOnThisDevice) call.leave("accepted-on-another-device") + if (!acceptedOnThisDevice) { + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.ACCEPTED_ON_OTHER_DEVICE, + message = "accepted-on-another-device", + ), + ) + } } call.fireEvent( LocalCallAcceptedPostEvent( @@ -889,7 +896,12 @@ public class CallState( } _rejectedBy.value = newRejectedBySet.toSet() _ringingState.value = RingingState.RejectedByAll - call.leave("LocalCallMissedEvent") + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.LOCAL_CALL_MISSED_EVENT, + message = "LocalCallMissedEvent", + ), + ) val activeCallExists = client.state.activeCall.value != null if (activeCallExists) { @@ -910,12 +922,22 @@ public class CallState( _endedAt.value = OffsetDateTime.now(Clock.systemUTC()) _endedByUser.value = event.user?.toUser() updateRingingState() - call.leave("CallEndedEvent") + call.leave( + CallLeaveReason.Backend( + cause = BackendCause.CALL_ENDED_EVENT, + message = "CallEndedEvent", + ), + ) // Call ended by backend } is CallEndedSfuEvent -> { _endedAt.value = OffsetDateTime.now(Clock.systemUTC()) - call.leave("CallEndedSfuEvent") + call.leave( + CallLeaveReason.Backend( + cause = BackendCause.CALL_ENDED_SFU_EVENT, + message = "CallEndedSfuEvent", + ), + ) // Call ended by SFU } is CallMemberUpdatedEvent -> { @@ -1339,13 +1361,23 @@ public class CallState( cancelTimeout() RingingState.RejectedByAll } else if (isRejectedByMe) { - call.leave("updateRingingState-rejected-self") + call.leave( + CallLeaveReason.UserAction( + UserActionCause.REJECTED_BY_SELF, + message = "updateRingingState-rejected-self", + ), + ) // User rejected the call cancelTimeout() RingingState.RejectedByAll } else if ((rejectedBy.isNotEmpty() && rejectedBy.size >= outgoingMembersCount) || (rejectedBy.contains(createdBy?.id) && hasRingingCall) ) { - call.leave("updateRingingState-rejected") + call.leave( + CallLeaveReason.SdkDriven( + cause = SdkCause.REJECTED_BY_ALL, + message = "All participants rejected the call", + ), + ) cancelTimeout() if (rejectReason?.alias == REJECT_REASON_TIMEOUT) { @@ -1474,7 +1506,8 @@ public class CallState( if (_ringingState.value is RingingState.Outgoing || _ringingState.value is RingingState.Incoming && client.state.activeCall.value == null) { isJoinAndRingInProgress.set(false) call.reject(reason = RejectReason.Custom(alias = REJECT_REASON_TIMEOUT)) - call.leave("start-ringing-timeout") + val leaveMessage = if (_ringingState.value is RingingState.Outgoing) "Outgoing call timed out with no answer" else "Incoming call timed out with no answer" + call.leave(CallLeaveReason.SdkDriven(cause = SdkCause.RING_TIMEOUT, message = leaveMessage)) } } else { logger.w { "[startRingingTimer] No autoCancelTimeoutMs set - call ring with no timeout" } @@ -1842,7 +1875,7 @@ public class CallState( .collect { isOnHold -> when (ringingState.value) { is RingingState.Active -> { - call.leave("call-on-hold") + call.leave(CallLeaveReason.SdkDriven(cause = SdkCause.CALL_ON_HOLD, message = "Call put on hold by the system")) } else -> {} } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt index 3f56f463da7..7f8ed347504 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt @@ -23,6 +23,12 @@ import io.getstream.android.video.generated.models.ConnectedEvent import io.getstream.android.video.generated.models.VideoEvent import io.getstream.log.taggedLogger import io.getstream.result.Error +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import io.getstream.video.android.core.analytics.reporting.ImmediateEventSender +import io.getstream.video.android.core.analytics.reporting.datasource.InMemoryPendingEventDataSource +import io.getstream.video.android.core.faultinjector.FailureInjector +import io.getstream.video.android.core.faultinjector.NoOpFailureInjector +import io.getstream.video.android.core.header.HeadersUtil import io.getstream.video.android.core.internal.InternalStreamVideoApi import io.getstream.video.android.core.notifications.internal.service.CallService import io.getstream.video.android.core.notifications.internal.service.ServiceIntentBuilder @@ -87,6 +93,18 @@ class ClientState(private val client: StreamVideo) { public val callConfigRegistry = (client as StreamVideoClient).callServiceConfigRegistry private val serviceLauncher = ServiceLauncher(client.context) + internal val clientEventReporter = + ClientEventReporter( + sender = ImmediateEventSender( + api = streamVideoClient.coordinatorConnectionModule.api, + dataSource = InMemoryPendingEventDataSource(), + ), + userAgent = { HeadersUtil().buildSdkTrackingHeaders() }, + sdkVersion = BuildConfig.STREAM_VIDEO_VERSION, + ) + + @InternalStreamVideoApi + public var failureInjector: FailureInjector = NoOpFailureInjector() @InternalStreamVideoApi public val rejectCallWhenBusy: Boolean = (client as StreamVideoClient).rejectCallWhenBusy diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ExternalCallRejectionHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ExternalCallRejectionHandler.kt index 36ba54d23fa..0ab8e84a7ab 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ExternalCallRejectionHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ExternalCallRejectionHandler.kt @@ -68,7 +68,12 @@ internal class ExternalCallRejectionHandler() { * onSuccess: (suspend (Call) -> Unit)?, * onError: (suspend (Exception) -> Unit)?,) */ - call.leave("rejected-on-wearable") + call.leave( + CallLeaveReason.UserAction( + cause = UserActionCause.WEARABLE_REJECTED, + message = "Call rejected on wearable", + ), + ) } } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.kt index b2dad697f82..b08b1031954 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoClient.kt @@ -83,10 +83,12 @@ import io.getstream.result.Error import io.getstream.result.Result import io.getstream.result.Result.Failure import io.getstream.result.Result.Success +import io.getstream.video.android.core.analytics.observer.CoordinatorSocketObserver import io.getstream.video.android.core.audio.AudioExecutionContext import io.getstream.video.android.core.call.CallBusyHandler import io.getstream.video.android.core.errors.VideoErrorCode import io.getstream.video.android.core.events.VideoEventListener +import io.getstream.video.android.core.faultinjector.FailureKey import io.getstream.video.android.core.filter.Filters import io.getstream.video.android.core.filter.toMap import io.getstream.video.android.core.internal.module.CoordinatorConnectionModule @@ -218,6 +220,64 @@ internal class StreamVideoClient internal constructor( internal fun getAudioContext(): AudioExecutionContext = audioExecutionContext val socketImpl = coordinatorConnectionModule.socketConnection + var location: String? = null + val coordinatorAnalytics = CoordinatorSocketObserver(scope, state.clientEventReporter) + + init { + // listen to socket events and errors + scope.launch(CoroutineName("init#coordinatorSocket.events.collect")) { + coordinatorConnectionModule.socketConnection.events().collect { + fireEvent(it) + } + } + scope.launch { + coordinatorConnectionModule.socketConnection.state().collect { + state.handleState(it) + } + } + + scope.launch { + coordinatorAnalytics + .startObserver(coordinatorConnectionModule.socketConnection.state()) + } + + scope.launch(CoroutineName("init#coordinatorSocket.errors.collect")) { + coordinatorConnectionModule.socketConnection.errors().collect { error -> + state.handleError(error.streamError) + } + } + + scope.launch(CoroutineName("init#coordinatorSocket.connectionState.collect")) { + coordinatorConnectionModule.socketConnection.state().collect { it -> + // If the socket is reconnected then we have a new connection ID. + // We need to re-watch every watched call with the new connection ID + // (otherwise the WS events will stop) + val watchedCalls = calls + if (it is VideoSocketState.Connected && watchedCalls.isNotEmpty()) { + val filter = Filters.`in`("cid", watchedCalls.values.map { it.cid }).toMap() + queryCalls(filters = filter, watch = true).also { + if (it is Failure) { + logger.e { "Failed to re-watch calls (${it.value}" } + } + } + } + } + } + + scope.launch { + /** + * Invoke the reject API only when the busy check is triggered from the video client. + * + * Network calls initiated from background notification flows may be suspended + * by the OS, so API calls are intentionally avoided in those cases. + */ + callBusyHandler.callBusyHandlerState.filterNotNull() + .filter { it.source == CallBusyHandler.CallBusyHandlerCheckerSource.VIDEO_CLIENT } + .map { it.streamCallId }.collect { streamCallId -> + call(streamCallId.type, streamCallId.id).reject(RejectReason.Busy) + } + } + } fun onCallCleanUp(call: Call) { if (enableCallUpdatesAfterLeave) { @@ -251,8 +311,11 @@ internal class StreamVideoClient internal constructor( } } } - activeCall?.leave("client-cleanup") + activeCall?.leave( + CallLeaveReason.SdkDriven(cause = SdkCause.CLIENT_CLEANUP, message = "client-cleanup"), + ) // SDK client cleanup audioExecutionContext.release() + coordinatorAnalytics.endObserver() } /** @@ -386,60 +449,10 @@ internal class StreamVideoClient internal constructor( coordinatorConnectionModule.socketConnection.connect(user) } - init { - // listen to socket events and errors - scope.launch(CoroutineName("init#coordinatorSocket.events.collect")) { - coordinatorConnectionModule.socketConnection.events().collect { - fireEvent(it) - } - } - scope.launch { - coordinatorConnectionModule.socketConnection.state().collect { - state.handleState(it) - } - } - - scope.launch(CoroutineName("init#coordinatorSocket.errors.collect")) { - coordinatorConnectionModule.socketConnection.errors().collect { error -> - state.handleError(error.streamError) - } - } - - scope.launch(CoroutineName("init#coordinatorSocket.connectionState.collect")) { - coordinatorConnectionModule.socketConnection.state().collect { it -> - // If the socket is reconnected then we have a new connection ID. - // We need to re-watch every watched call with the new connection ID - // (otherwise the WS events will stop) - val watchedCalls = calls - if (it is VideoSocketState.Connected && watchedCalls.isNotEmpty()) { - val filter = Filters.`in`("cid", watchedCalls.values.map { it.cid }).toMap() - queryCalls(filters = filter, watch = true).also { - if (it is Failure) { - logger.e { "Failed to re-watch calls (${it.value}" } - } - } - } - } - } - - scope.launch { - /** - * Invoke the reject API only when the busy check is triggered from the video client. - * - * Network calls initiated from background notification flows may be suspended - * by the OS, so API calls are intentionally avoided in those cases. - */ - callBusyHandler.callBusyHandlerState.filterNotNull() - .filter { it.source == CallBusyHandler.CallBusyHandlerCheckerSource.VIDEO_CLIENT } - .map { it.streamCallId }.collect { streamCallId -> - call(streamCallId.type, streamCallId.id).reject(RejectReason.Busy) - } - } - } - - var location: String? = null - internal suspend fun getCachedLocation(): Result { + if (state.failureInjector.isEnabled(FailureKey.FAIL_LOCATION)) { + return state.failureInjector.sendFailResult(FailureKey.FAIL_LOCATION) + } val job = loadLocationAsync() job.join() location?.let { @@ -809,6 +822,11 @@ internal class StreamVideoClient internal constructor( migratingFromList: List? = null, hintHighScaleLivestreamPublisher: Boolean? = null, ): Result { + with(state.failureInjector) { + if (isEnabled(FailureKey.FAIL_JOIN_CALL)) { + return sendFailResult(FailureKey.FAIL_JOIN_CALL) + } + } val joinCallRequest = JoinCallRequest( create = create, data = CallRequest( @@ -1168,7 +1186,10 @@ internal class StreamVideoClient internal constructor( override fun logOut() { scope.launch( CoroutineName("logOut"), - ) { streamNotificationManager.deviceTokenStorage.clear() } + ) { + streamNotificationManager.deviceTokenStorage.clear() + // TODO Rahul should we flush our pending analytics events + } } override fun call(type: String, id: String): Call { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/CallAnalyticsCoordinator.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/CallAnalyticsCoordinator.kt new file mode 100644 index 00000000000..73ed2400e6e --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/CallAnalyticsCoordinator.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics + +import android.content.Context +import io.getstream.log.taggedLogger +import io.getstream.video.android.core.CallLeaveReason +import io.getstream.video.android.core.ParticipantState +import io.getstream.video.android.core.RealtimeConnection +import io.getstream.video.android.core.analytics.observer.AudioObserver +import io.getstream.video.android.core.analytics.observer.JoinObserver +import io.getstream.video.android.core.analytics.observer.MediaPermissionObserver +import io.getstream.video.android.core.analytics.observer.PeerConnectionObserver +import io.getstream.video.android.core.analytics.observer.SfuSocketObserver +import io.getstream.video.android.core.analytics.observer.VideoObserver +import io.getstream.video.android.core.analytics.observer.model.Stage +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import io.getstream.video.android.core.analytics.reporting.model.AnalyticsCallAbortReason +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow + +internal class CallAnalyticsCoordinator( + val context: Context, + val callId: String, + val callType: String, + val connectionFlow: StateFlow, + val participants: StateFlow>, + val eventReporter: ClientEventReporter, + val scope: CoroutineScope, +) { + val logger by taggedLogger("CallAnalyticsHooks") + + val joinObserver = JoinObserver(callId, callType, eventReporter) { + resetAfterJoinSuccess() + } + val sfuSocketObserver = + SfuSocketObserver(callId, callType, connectionFlow, scope, eventReporter) { + joinObserver.joinStageAttemptId + } + val peerConnectionObserver = PeerConnectionObserver(callId, callType, scope, eventReporter) { + joinObserver.joinStageAttemptId + } + val mediaPermissionObserver = + MediaPermissionObserver(context, callId, callType, eventReporter) { + joinObserver.joinStageAttemptId + } + val audioObserver = + AudioObserver(callId, callType, eventReporter, { sfuSocketObserver.sfuName }) { + joinObserver.joinStageAttemptId + } + val videoObserver = + VideoObserver(callId, callType, eventReporter, { sfuSocketObserver.sfuName }) { + joinObserver.joinStageAttemptId + } + + fun resetAfterJoinSuccess() { + audioObserver.reset() + videoObserver.reset() + audioObserver.observeParticipantsForFirstRemoteAudioFrame(participants, scope) + } + + fun onCallLeave(callLeaveReason: CallLeaveReason) { + val isAnyStageInProgress = + joinObserver.joinStage == Stage.IN_PROGRESS || + sfuSocketObserver.wsStage == Stage.IN_PROGRESS || + peerConnectionObserver.publisherStage == Stage.IN_PROGRESS || + peerConnectionObserver.subscriberStage == Stage.IN_PROGRESS + logger.d { "noob isAnyStageInProgress:$isAnyStageInProgress" } + + if (isAnyStageInProgress) { + val abortReason = when (callLeaveReason) { + is CallLeaveReason.Backend -> AnalyticsCallAbortReason.BACKEND_LEAVE + else -> AnalyticsCallAbortReason.CLIENT_ABORTED + } + eventReporter.abortAllPostCallInFlight(abortReason) + } + } + + fun stopObservers() { + peerConnectionObserver.stop() + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/AudioObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/AudioObserver.kt new file mode 100644 index 00000000000..f435eb772fc --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/AudioObserver.kt @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import io.getstream.log.taggedLogger +import io.getstream.video.android.core.ParticipantState +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.launch +import org.webrtc.AudioTrackSink +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicBoolean + +private typealias TrackId = String + +internal class AudioObserver( + private val callId: String, + private val callType: String, + private val clientEventReporter: ClientEventReporter, + private val onSfuId: () -> String, + val getJoinStageAttemptId: () -> String, +) { + + val logger by taggedLogger("AudioObserver") + var recordedFirstFrame: AtomicBoolean = AtomicBoolean(false) + + private val trackSinks = + ConcurrentHashMap>() + private var observeJob: Job? = null + + fun observeParticipantsForFirstRemoteAudioFrame( + participants: StateFlow>, + scope: CoroutineScope, + ) { + observeJob?.cancel() + observeJob = scope.launch { + participants + .flatMapLatest { list -> + val audioTrackFlows = list + .filter { !it.isLocal } + .map { it.audioTrack.filterNotNull() } + if (audioTrackFlows.isEmpty()) { + emptyFlow() + } else { + merge(*audioTrackFlows.toTypedArray()) + } + } + .collect { modelAudioTrack -> + if (trackSinks.containsKey(modelAudioTrack.streamId)) return@collect + val webRtcTrack = modelAudioTrack.audio + val sink = + AudioTrackSink { audioData, bitsPerSample, sampleRate, numberOfChannels, numberOfFrames, _ -> + // onData fires on the WebRTC native audio thread every ~10ms. + // Rules: + // - No logging (I/O on a real-time thread) + // - No removeSink (deadlocks the sink-list lock WebRTC holds here) + // - No blocking calls + // CAS here so exactly ONE coroutine is ever launched, then + // hand off all real work (reporting + cleanup) to the coroutine. + if (numberOfFrames > 0 && sampleRate > 0 && numberOfChannels > 0 && audioData.hasRemaining()) { + scope.launch { + if (recordedFirstFrame.compareAndSet(false, true)) { + reportAndCleanup() + } + } + } + } + trackSinks[modelAudioTrack.streamId] = Pair(webRtcTrack, sink) + webRtcTrack.addSink(sink) + } + } + } + + // Called from a coroutine — safe to do I/O, removeSink, and job cancellation here. + private fun reportAndCleanup() { + clientEventReporter.reportFirstAudioFrameRendered( + onSfuId(), + callId, + callType, + getJoinStageAttemptId(), + ) + trackSinks.forEach { (_, pair) -> pair.first.removeSink(pair.second) } + trackSinks.clear() + observeJob?.cancel() + observeJob = null + } + + fun reset() { + logger.d { "noob [reset]" } + recordedFirstFrame.set(false) + trackSinks.forEach { (_, pair) -> pair.first.removeSink(pair.second) } + trackSinks.clear() + observeJob?.cancel() + observeJob = null + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/CoordinatorSocketObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/CoordinatorSocketObserver.kt new file mode 100644 index 00000000000..90009b9cf3c --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/CoordinatorSocketObserver.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import io.getstream.video.android.core.socket.coordinator.CoordinatorSocketStateService +import io.getstream.video.android.core.socket.coordinator.state.VideoSocketConnectionType +import io.getstream.video.android.core.socket.coordinator.state.VideoSocketState +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch + +internal class CoordinatorSocketObserver( + private val scope: CoroutineScope, + private val eventReporter: ClientEventReporter, +) { + + private var job: Job? = null + private var stageId = "" + + internal fun startObserver(videoSocketStateFlow: StateFlow) { + endObserver() + job = scope.launch { + videoSocketStateFlow.collect { + when (it) { + is VideoSocketState.Connecting -> { + when (it.connectionType) { + VideoSocketConnectionType.INITIAL_CONNECTION -> { + stageId = eventReporter.reportCoordinatorWSInitiated() + } + + VideoSocketConnectionType.AUTOMATIC_RECONNECTION -> {} + VideoSocketConnectionType.FORCE_RECONNECTION -> {} + } + } + + is VideoSocketState.Connected -> { + if (stageId.isNotEmpty()) { + eventReporter.reportCoordinatorWSCompleted( + stageId, + true, + CoordinatorSocketStateService.lastRetryAttempts, + ) + } + } + + is VideoSocketState.Disconnected.DisconnectedPermanently -> { + if (stageId.isNotEmpty()) { + eventReporter.reportCoordinatorWSCompleted( + stageId, + false, + CoordinatorSocketStateService.lastRetryAttempts, + ) + } + } + + else -> {} + } + } + } + } + + fun endObserver() { + job?.cancel() + job = null + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/JoinObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/JoinObserver.kt new file mode 100644 index 00000000000..1768f51e039 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/JoinObserver.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import io.getstream.video.android.core.analytics.observer.model.Stage +import io.getstream.video.android.core.analytics.observer.model.TelemetryModel +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import java.util.UUID + +internal class JoinObserver( + val callId: String, + val callType: String, + val eventReporter: ClientEventReporter, + val onJoinSuccess: () -> Unit, +) { + + var stageId = "" + var joinStage = Stage.NOT_STARTED + var joinStageAttemptId = "" + + fun onJoinFunctionStart() { + joinStageAttemptId = UUID.randomUUID().toString() + eventReporter.reportSdkMethodJoinInitiated( + callType = callType, + callId = callId, + joinStageAttemptId = joinStageAttemptId, + ) + } + + fun onJoinRequestStart() { + if (joinStage == Stage.NOT_STARTED) { + stageId = eventReporter.reportCoordinatorJoinInitiated( + callType = callType, + callId = callId, + joinStageAttemptId = joinStageAttemptId, + ) + joinStage = Stage.IN_PROGRESS + } + } + + fun onJoinRequestSuccess(telemetryModel: TelemetryModel, currentSessionId: String) { + if (joinStage == Stage.IN_PROGRESS) { + if (stageId.isNotEmpty()) { + eventReporter.reportCoordinatorJoinCompleted( + stageId = stageId, + success = true, + retryCount = telemetryModel.retryAttempt, + callSessionId = currentSessionId, + ) + onJoinSuccess() + } + resetStage() + } + } + + fun onJoinRequestPermanentError(retryCount: Int, message: String) { + if (joinStage == Stage.IN_PROGRESS) { + if (stageId.isNotEmpty()) { + eventReporter.reportCoordinatorJoinCompleted( + stageId = stageId, + success = false, + retryCount = retryCount, + failureReason = message, + ) + } + resetStage() + } + } + + fun onJoinRequestRetryExhausted(retryCount: Int, message: String) { + onJoinRequestPermanentError(retryCount, message) + } + + fun resetStage() { + joinStage = Stage.NOT_STARTED + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/MediaPermissionObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/MediaPermissionObserver.kt new file mode 100644 index 00000000000..f44996841bb --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/MediaPermissionObserver.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import androidx.core.content.ContextCompat +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter + +internal class MediaPermissionObserver( + val context: Context, + val callId: String, + val callType: String, + val eventReporter: ClientEventReporter, + val getJoinStageAttemptId: () -> String, +) { + + fun mediaPermissionStatus() { + eventReporter.reportMediaPermissionStatus( + callId, + callType, + getJoinStageAttemptId(), + isCameraPermissionGranted(), + isMicrophonePermissionGranted(), + ) + } + + fun isMicrophonePermissionGranted(): Boolean { + return ContextCompat.checkSelfPermission( + context, + Manifest.permission.RECORD_AUDIO, + ) == PackageManager.PERMISSION_GRANTED + } + + fun isCameraPermissionGranted(): Boolean { + return ContextCompat.checkSelfPermission( + context, + Manifest.permission.CAMERA, + ) == PackageManager.PERMISSION_GRANTED + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/PeerConnectionObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/PeerConnectionObserver.kt new file mode 100644 index 00000000000..a46415b2957 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/PeerConnectionObserver.kt @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import io.getstream.video.android.core.analytics.observer.model.Stage +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import io.getstream.video.android.core.analytics.reporting.model.PeerConnectionRole +import io.getstream.video.android.core.call.RtcSession +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.launch +import org.webrtc.PeerConnection + +internal class PeerConnectionObserver( + val callId: String, + val callType: String, + private val scope: CoroutineScope, + val reporter: ClientEventReporter, + val getJoinStageAttemptId: () -> String, +) { + + private var peerConnectionObserverJob: Job? = null + private var publisherJob: Job? = null + private var subscriberJob: Job? = null + var publisherStage = Stage.NOT_STARTED + var subscriberStage = Stage.NOT_STARTED + + fun observePeerConnections(session: StateFlow) { + peerConnectionObserverJob?.cancel() + peerConnectionObserverJob = scope.launch { + publisherJob?.cancel() + publisherJob = launch { + session.filterNotNull() + .flatMapLatest { it.publisher.filterNotNull() } + .flatMapLatest { it.state.filterNotNull() } + .collect { state -> + publisherStage = getStage(state) + scope.launch { + onPeerConnectionStateChanged( + role = PeerConnectionRole.PUBLISH, + iceState = session.value?.publisher?.value?.iceState?.value, + peerConnectionState = state, + ) + } + } + } + subscriberJob?.cancel() + subscriberJob = launch { + session.filterNotNull() + .flatMapLatest { it.subscriber.filterNotNull() } + .flatMapLatest { it.state.filterNotNull() } + .collect { state -> + subscriberStage = getStage(state) + scope.launch { + onPeerConnectionStateChanged( + role = PeerConnectionRole.SUBSCRIBE, + iceState = session.value?.subscriber?.value?.iceState?.value, + peerConnectionState = state, + ) + } + } + } + } + } + + private fun getStage(peerConnectionState: PeerConnection.PeerConnectionState): Stage { + return when (peerConnectionState) { + PeerConnection.PeerConnectionState.CONNECTING -> { + Stage.IN_PROGRESS // initiated + } + + PeerConnection.PeerConnectionState.FAILED, + PeerConnection.PeerConnectionState.CONNECTED, + -> { + Stage.NOT_STARTED // completed + } + + else -> { + Stage.IN_PROGRESS + } + } + } + + internal fun onPeerConnectionStateChanged( + role: PeerConnectionRole, + iceState: PeerConnection.IceConnectionState?, + peerConnectionState: PeerConnection.PeerConnectionState?, + ) { + reporter.onPeerConnectionStateChanged( + callId = callId, + callType = callType, + role = role, + iceState = iceState, + peerConnectionState = peerConnectionState, + joinStageAttemptId = getJoinStageAttemptId.invoke(), + ) + } + + fun stop() { + peerConnectionObserverJob?.cancel() + peerConnectionObserverJob = null + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/SfuSocketObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/SfuSocketObserver.kt new file mode 100644 index 00000000000..972fe7fcc81 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/SfuSocketObserver.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import io.getstream.video.android.core.RealtimeConnection +import io.getstream.video.android.core.analytics.observer.model.Stage +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow + +internal class SfuSocketObserver( + val callId: String, + val callType: String, + val connectionFlow: StateFlow, + val scope: CoroutineScope, + val reporter: ClientEventReporter, + val getJoinStageAttemptId: () -> String, +) { + var telemetryWsEventStageId = "" + var wsStage = Stage.NOT_STARTED + + var sfuName: String = "" + + fun onWsInitiated(sfuName: String, wasPreviouslyConnected: Boolean) { + if (wsStage == Stage.NOT_STARTED) { + this.sfuName = sfuName + telemetryWsEventStageId = reporter.reportWsJoinInitiated( + callId = callId, + callType = callType, + sfuId = sfuName, + wasPreviouslyConnected = wasPreviouslyConnected, + joinStageAttemptId = getJoinStageAttemptId.invoke(), + ) + wsStage = Stage.IN_PROGRESS + } + } + + fun onWsCompleted( + success: Boolean, + retryCount: Int, + failureReason: String? = null, + failureCode: String? = null, + ) { + if (wsStage == Stage.IN_PROGRESS) { + if (telemetryWsEventStageId.isNotEmpty()) { + reporter.reportWsJoinCompleted( + stageId = telemetryWsEventStageId, + success = success, + retryCount = retryCount, + failureReason = failureReason, + failureCode = failureCode, + joinStageAttemptId = getJoinStageAttemptId.invoke(), + ) + } + resetStage() + } + } + + fun resetStage() { + wsStage = Stage.NOT_STARTED + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/VideoObserver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/VideoObserver.kt new file mode 100644 index 00000000000..e7be0a74eaf --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/VideoObserver.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer + +import android.util.Log +import io.getstream.video.android.core.analytics.reporting.ClientEventReporter +import io.getstream.video.android.core.call.RtcSession +import stream.video.sfu.models.TrackType + +internal class VideoObserver( + private val callId: String, + private val callType: String, + private val clientEventReporter: ClientEventReporter, + private val onSfuId: () -> String, + val getJoinStageAttemptId: () -> String, +) { + + var stageId: String = "" + + fun firstVideoFrameRendered( + trackType: TrackType, + width: Int, + height: Int, + rtcSession: RtcSession?, + videoSessionId: String, + callSessionId: String, + ) { + when (trackType) { + TrackType.TRACK_TYPE_VIDEO, TrackType.TRACK_TYPE_SCREEN_SHARE -> { + if (videoSessionId != callSessionId) { + val videoTrackId = rtcSession?.subscriber?.value?.getTrack( + videoSessionId, + TrackType.TRACK_TYPE_VIDEO, + )?.asVideoTrack()?.video?.id() + Log.d( + "VideoObserver", + "noob [firstVideoFrameRendered]: $trackType, w:$width, h:$height, videoTrackId:$videoTrackId, videoSessionId:$videoSessionId, callSessionId:$callSessionId", + ) + videoTrackId?.let { + if (stageId.isEmpty()) { + stageId = clientEventReporter.reportFirstVideoFrameRendered( + onSfuId(), + callId, + callType, + getJoinStageAttemptId(), + videoTrackId, + ) + } + } + } + } + else -> {} + } + } + + fun reset() { + stageId = "" + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/Stage.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/Stage.kt new file mode 100644 index 00000000000..e5c0892a312 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/Stage.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer.model + +internal enum class Stage { NOT_STARTED, IN_PROGRESS } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/TelemetryModel.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/TelemetryModel.kt new file mode 100644 index 00000000000..b3010efa674 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/observer/model/TelemetryModel.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.observer.model + +internal data class TelemetryModel(val retryAttempt: Int) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventFactory.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventFactory.kt new file mode 100644 index 00000000000..aa7bea25473 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventFactory.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting + +import io.getstream.android.video.generated.models.ClientEvent +import io.getstream.video.android.core.StreamVideo +import io.getstream.video.android.core.analytics.reporting.model.EventOutcome +import io.getstream.video.android.core.analytics.reporting.model.EventStage +import io.getstream.video.android.core.analytics.reporting.model.EventType +import io.getstream.video.android.core.analytics.reporting.model.PeerConnectionRole +import org.threeten.bp.OffsetDateTime +import org.threeten.bp.ZoneOffset +import org.webrtc.PeerConnection + +internal class ClientEventFactory(val sdkVersion: String, val userAgent: () -> String, val getCoordinatorId: () -> String) { + + fun buildRequest( + callId: String? = null, + callType: String? = null, + stage: EventStage, + eventType: EventType, + stageId: String? = null, + joinStageAttemptId: String? = null, + elapsedTime: Long? = null, + outcome: EventOutcome? = null, + retryCountAttempt: Int? = null, + retryFailureReason: String? = null, + retryFailureCode: String? = null, + callSessionId: String? = null, + sfuId: String? = null, + peerConnection: PeerConnectionRole? = null, + wasPreviouslyConnected: Boolean? = null, + iceState: PeerConnection.IceConnectionState? = null, + peerConnectionState: PeerConnection.PeerConnectionState? = null, + userSessionId: String? = null, + screenShareAllowed: Boolean? = null, + microphoneAllowed: Boolean? = null, + cameraAllowed: Boolean? = null, + trackId: String? = null, + ): ClientEvent = ClientEvent( + stageId = stageId, + joinAttemptId = joinStageAttemptId, + eventType = eventType.value, + id = callId, + sdkVersion = sdkVersion, + stage = stage.value, + timestamp = OffsetDateTime.now(ZoneOffset.UTC), + type = callType, + userAgent = userAgent.invoke().take(512), + userId = StreamVideo.Companion.instanceOrNull()?.userId, + callSessionId = callSessionId, + elapsedTime = elapsedTime?.toInt(), + iceState = iceState?.name, + outcome = outcome?.value, + peerConnection = peerConnection?.value, + previouslyConnectedTimestamp = null, + retryCountAttempt = retryCountAttempt, + retryFailureCode = retryFailureCode, + retryFailureReason = retryFailureReason, + sfuId = sfuId, + userSessionId = userSessionId, + wasPreviouslyConnected = wasPreviouslyConnected, + screenShareStatus = getPermissionStatusText(screenShareAllowed), + microphonePermissionStatus = getPermissionStatusText(microphoneAllowed), + cameraPermissionStatus = getPermissionStatusText(cameraAllowed), + trackId = trackId, + coordinatorConnectId = getCoordinatorId(), + ) + + fun getPermissionStatusText(allowed: Boolean?): String? { + return if (allowed == true) "GRANTED" else if (allowed == false) "NOT_GRANTED" else null + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporter.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporter.kt new file mode 100644 index 00000000000..74ab658d32c --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporter.kt @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting + +import io.getstream.android.video.generated.models.ClientEvent +import io.getstream.log.taggedLogger +import io.getstream.video.android.core.analytics.reporting.model.AnalyticsCallAbortReason +import io.getstream.video.android.core.analytics.reporting.model.CallId +import io.getstream.video.android.core.analytics.reporting.model.EventOutcome +import io.getstream.video.android.core.analytics.reporting.model.EventStage +import io.getstream.video.android.core.analytics.reporting.model.EventType +import io.getstream.video.android.core.analytics.reporting.model.InFlightSession +import io.getstream.video.android.core.analytics.reporting.model.PeerConnectionRole +import io.getstream.video.android.core.analytics.reporting.model.PostCallFlightSession +import io.getstream.video.android.core.analytics.reporting.model.PreCallInFlightSession +import io.getstream.video.android.core.analytics.reporting.model.StageId +import org.webrtc.PeerConnection +import java.util.UUID +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.set + +/** + * TODO + * [ClientEvent.previouslyConnectedTimestamp] : Ask clarification + * [ClientEvent.retryFailureCode] : Ask clarification + */ + +internal class ClientEventReporter( + private val sender: EventSender, + private val userAgent: () -> String, + private val sdkVersion: String, +) { + private val logger by taggedLogger("ClientEventReporter") + private val clientEventFactory = ClientEventFactory(sdkVersion, userAgent) { + this.coordinatorConnectId + } + + private val postCallFlightSessions = ConcurrentHashMap() + private val joinStageAttemptIdMap = ConcurrentHashMap() + private val callSessionIdMap = ConcurrentHashMap() + + // Active event_session_id per PC role — drives the ICE state machine + private val activePcSessionIds = ConcurrentHashMap() + + // Whether each PC role has ever reached CONNECTED (for was_previously_connected) + private val pcEverConnected = ConcurrentHashMap() + private var coordinatorConnectId = "" + internal fun reportCoordinatorWSInitiated(): String { + this.coordinatorConnectId = UUID.randomUUID().toString() + val stageId = UUID.randomUUID().toString() + val now = System.currentTimeMillis() + postCallFlightSessions[stageId] = PreCallInFlightSession( + stageId = coordinatorConnectId, + coordinatorConnectId = coordinatorConnectId, + stage = EventStage.Call.COORDINATOR_JOIN, + startedAtMs = now, + ) + sender.send( + clientEventFactory.buildRequest( + stageId = stageId, + stage = EventStage.CoordinatorWs, + eventType = EventType.INITIATED, + ), + ) + return stageId + } + + internal fun reportCoordinatorWSCompleted( + stageId: String, + success: Boolean, + retryCount: Int? = null, + failureCode: String? = null, + failureReason: String? = null, + ) { + val session = postCallFlightSessions.remove(stageId) ?: return + if (session is PreCallInFlightSession) { + val elapsedTime = System.currentTimeMillis() - session.startedAtMs + sender.send( + clientEventFactory.buildRequest( + stage = EventStage.CoordinatorWs, + outcome = if (success) EventOutcome.SUCCESS else EventOutcome.FAILURE, + retryCountAttempt = retryCount, + retryFailureCode = failureCode, + elapsedTime = elapsedTime, + retryFailureReason = failureReason, + eventType = EventType.COMPLETED, + ), + ) + } + } + + internal fun reportSdkMethodJoinInitiated( + callId: String, + callType: String, + joinStageAttemptId: String, + ) { + joinStageAttemptIdMap[callId] = joinStageAttemptId + sender.send( + clientEventFactory.buildRequest( + callId, + callType, + stage = EventStage.Call.JOIN_INITIATED, + eventType = EventType.INITIATED, + joinStageAttemptId = joinStageAttemptId, + ), + ) + } + + // --- CoordinatorJoin --- + + internal fun reportCoordinatorJoinInitiated( + callId: String, + callType: String, + joinStageAttemptId: String, + ): String { + val stageId = UUID.randomUUID().toString() + joinStageAttemptIdMap[callId] = joinStageAttemptId + val now = System.currentTimeMillis() + postCallFlightSessions[stageId] = PostCallFlightSession( + stageId = stageId, + callId = callId, + callType = callType, + stage = EventStage.Call.COORDINATOR_JOIN, + startedAtMs = now, + joinStageAttemptIdSnapshot = joinStageAttemptId, + ) + sender.send( + clientEventFactory.buildRequest( + callId, + callType, + stage = EventStage.Call.COORDINATOR_JOIN, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + ), + ) + return stageId + } + + internal fun reportCoordinatorJoinCompleted( + stageId: String, + success: Boolean, + retryCount: Int, + failureReason: String? = null, + failureCode: String? = null, // TODO Rahul, ask tomorrow + callSessionId: String? = null, + ) { + val session = postCallFlightSessions.remove(stageId) ?: return + if (session is PostCallFlightSession) { + val elapsedTime = System.currentTimeMillis() - session.startedAtMs + callSessionIdMap[session.callId] = callSessionId ?: "" + sender.send( + clientEventFactory.buildRequest( + callId = session.callId, + callType = session.callType, + stage = EventStage.Call.COORDINATOR_JOIN, + eventType = EventType.COMPLETED, + stageId = stageId, + elapsedTime = elapsedTime, + outcome = if (success) EventOutcome.SUCCESS else EventOutcome.FAILURE, + retryCountAttempt = retryCount, + retryFailureReason = if (!success) failureReason else null, + retryFailureCode = if (!success) failureCode else null, + callSessionId = callSessionId, + joinStageAttemptId = session.joinStageAttemptIdSnapshot, + ), + ) + } + } + + // --- WSJoin --- + + internal fun reportWsJoinInitiated( + sfuId: String, + callId: String, + callType: String, + joinStageAttemptId: String, + wasPreviouslyConnected: Boolean, + ): String { + val stageId = UUID.randomUUID().toString() + val now = System.currentTimeMillis() + val callSessionId = callSessionIdMap[callId] + postCallFlightSessions[stageId] = PostCallFlightSession( + callId = callId, + callType = callType, + stageId = stageId, + stage = EventStage.Call.WS_JOIN, + startedAtMs = now, + joinStageAttemptIdSnapshot = joinStageAttemptIdMap[callId] ?: "", + sfuId = sfuId, + wasPreviouslyConnected = wasPreviouslyConnected, + callSessionId = callSessionId, + ) + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callType = callType, + stage = EventStage.Call.WS_JOIN, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + sfuId = sfuId, + wasPreviouslyConnected = wasPreviouslyConnected, + callSessionId = callSessionId, + ), + ) + return stageId + } + + internal fun reportWsJoinCompleted( + stageId: String, + joinStageAttemptId: String, + success: Boolean, + retryCount: Int, + failureReason: String? = null, + failureCode: String? = null, + ) { + val session = postCallFlightSessions.remove(stageId) ?: return + val elapsedTime = System.currentTimeMillis() - session.startedAtMs + if (session is PostCallFlightSession) { + sender.send( + clientEventFactory.buildRequest( + callId = session.callId, + callType = session.callType, + stage = EventStage.Call.WS_JOIN, + eventType = EventType.COMPLETED, + stageId = stageId, + elapsedTime = elapsedTime, + outcome = if (success) EventOutcome.SUCCESS else EventOutcome.FAILURE, + retryCountAttempt = retryCount, + retryFailureReason = if (!success) failureReason else null, + retryFailureCode = if (!success) failureCode else null, + sfuId = session.sfuId, + callSessionId = session.callSessionId, + joinStageAttemptId = joinStageAttemptId, + ), + ) + } + } + + // --- PeerConnectionConnect (ICE state machine) --- + + internal fun onPeerConnectionStateChanged( + callId: String, + callType: String, + joinStageAttemptId: String, + role: PeerConnectionRole, + iceState: PeerConnection.IceConnectionState?, + peerConnectionState: PeerConnection.PeerConnectionState?, + ) { + when (iceState) { + PeerConnection.IceConnectionState.CHECKING -> { + val wasPrev = pcEverConnected[role] == true + // TODO Rahul, maybe this `completePeerConnectionSession` is not needed + // If an existing session is still in-flight, close it as failed first + activePcSessionIds.remove(role)?.let { oldId -> + completePeerConnectionSession( + callId = callId, + callType = callType, + stageId = oldId, + joinStageAttemptId = joinStageAttemptId, + success = false, + iceState = iceState, + peerConnectionState = peerConnectionState, + failureReason = "ICE restart superseded previous attempt", + failureCode = "ICE_CONNECTIVITY_FAILED", + ) + } + val stageId = UUID.randomUUID().toString() + val now = System.currentTimeMillis() + postCallFlightSessions[stageId] = PostCallFlightSession( + callId = callId, + callType = callType, + stageId = stageId, + stage = EventStage.Call.PEER_CONNECTION_CONNECT, + startedAtMs = now, + joinStageAttemptIdSnapshot = joinStageAttemptIdMap[callId] ?: "", + peerConnectionRole = role, + wasPreviouslyConnected = wasPrev, + callSessionId = callSessionIdMap[callId], + ) + activePcSessionIds[role] = stageId + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callType = callType, + stage = EventStage.Call.PEER_CONNECTION_CONNECT, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + peerConnection = role, + wasPreviouslyConnected = wasPrev, + callSessionId = callSessionIdMap[callId], + iceState = iceState, + peerConnectionState = peerConnectionState, + ), + ) + } + + PeerConnection.IceConnectionState.CONNECTED -> { + val stageId = activePcSessionIds.remove(role) ?: return + pcEverConnected[role] = true + completePeerConnectionSession( + callId = callId, + callType = callType, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + success = true, + iceState = iceState, + peerConnectionState = peerConnectionState, + ) + } + + PeerConnection.IceConnectionState.FAILED -> { + val stageId = activePcSessionIds.remove(role) ?: return + completePeerConnectionSession( + callId = callId, + callType = callType, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + success = false, + iceState = iceState, + peerConnectionState = peerConnectionState, + failureReason = "ICE connectivity checks failed", + failureCode = "ICE_CONNECTIVITY_FAILED", + ) + } + + else -> { + /* DISCONNECTED handled by ICE restart → CHECKING */ + } + } + } + + private fun completePeerConnectionSession( + callId: String, + callType: String, + stageId: String, + joinStageAttemptId: String, + success: Boolean, + iceState: PeerConnection.IceConnectionState, + peerConnectionState: PeerConnection.PeerConnectionState?, + failureReason: String? = null, + failureCode: String? = null, + ) { + val session = postCallFlightSessions.remove(stageId) ?: return + val elapsedTime = System.currentTimeMillis() - session.startedAtMs + val callSessionId = callSessionIdMap[callId] + if (session is PostCallFlightSession) { + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callSessionId = callSessionId, + callType = callType, + stage = EventStage.Call.PEER_CONNECTION_CONNECT, + eventType = EventType.COMPLETED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + elapsedTime = elapsedTime, + outcome = if (success) EventOutcome.SUCCESS else EventOutcome.FAILURE, + retryCountAttempt = 0, + retryFailureReason = if (!success) failureReason else null, + retryFailureCode = if (!success) failureCode else null, + peerConnection = session.peerConnectionRole, + wasPreviouslyConnected = session.wasPreviouslyConnected, + iceState = iceState, + peerConnectionState = peerConnectionState, + ), + ) + } + } + + internal fun reportFirstAudioFrameRendered( + sfuId: String, + callId: String, + callType: String, + joinStageAttemptId: String, + ): String { + val stageId = UUID.randomUUID().toString() + val callSessionId = callSessionIdMap[callId] + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callType = callType, + stage = EventStage.Call.FIRST_AUDIO_FRAME_RENDERED, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + callSessionId = callSessionId, + sfuId = sfuId, + ), + ) + return stageId + } + + internal fun reportFirstVideoFrameRendered( + sfuId: String, + callId: String, + callType: String, + joinStageAttemptId: String, + trackId: String, + ): String { + val stageId = UUID.randomUUID().toString() + val callSessionId = callSessionIdMap[callId] + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callType = callType, + stage = EventStage.Call.FIRST_VIDEO_FRAME_RENDERED, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + callSessionId = callSessionId, + sfuId = sfuId, + trackId = trackId, + ), + ) + return stageId + } + + internal fun reportMediaPermissionStatus( + callId: String, + callType: String, + joinStageAttemptId: String, + isCameraGranted: Boolean, + isMicrophoneGranted: Boolean, + ): String { + val stageId = UUID.randomUUID().toString() + val callSessionId = callSessionIdMap[callId] + sender.send( + clientEventFactory.buildRequest( + callId = callId, + callType = callType, + stage = EventStage.Call.MEDIA_DEVICE_PERMISSION, + eventType = EventType.INITIATED, + stageId = stageId, + joinStageAttemptId = joinStageAttemptId, + callSessionId = callSessionId, + cameraAllowed = isCameraGranted, + microphoneAllowed = isMicrophoneGranted, + ), + ) + return stageId + } + + internal fun abortAllPostCallInFlight(reason: AnalyticsCallAbortReason) { + val snapshot: List = + postCallFlightSessions.values.filterIsInstance().toList() + postCallFlightSessions.clear() + activePcSessionIds.clear() + val now = System.currentTimeMillis() + val events = snapshot.map { session -> + clientEventFactory.buildRequest( + callId = session.callId, + callType = session.callType, + stage = session.stage, + eventType = EventType.COMPLETED, + stageId = session.stageId, + elapsedTime = now - session.startedAtMs, + outcome = EventOutcome.FAILURE, + retryCountAttempt = 0, + retryFailureReason = reason.message, + retryFailureCode = reason.code, + sfuId = session.sfuId, + callSessionId = session.callSessionId, + peerConnection = session.peerConnectionRole, + wasPreviouslyConnected = session.wasPreviouslyConnected, + userSessionId = session.userSessionId, + joinStageAttemptId = session.joinStageAttemptIdSnapshot, + ) + } + sender.sendAll(events) + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporterErrorMappers.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporterErrorMappers.kt new file mode 100644 index 00000000000..d719bb3bfb9 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/ClientEventReporterErrorMappers.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting + +import io.getstream.video.android.core.ReconnectOutcome + +internal class ClientEventReporterErrorMappers { + + fun getFailureReason(result: ReconnectOutcome): String { + return when (result) { + is ReconnectOutcome.Success -> { + "" + } + + is ReconnectOutcome.PreconditionNotMet -> { + result.reason + } + + is ReconnectOutcome.PeerConnectionStale -> { + "Peer connections are stale and can't be reused. Should escalate to REJOIN" + } + + is ReconnectOutcome.Disconnect -> { + "Server-initiated disconnect" + } + + is ReconnectOutcome.Failed -> { + result.error.message ?: result.error.toString() + } + } + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/EventSender.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/EventSender.kt new file mode 100644 index 00000000000..9971f875697 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/EventSender.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting + +import io.getstream.android.video.generated.apis.ProductvideoApi +import io.getstream.android.video.generated.models.ClientEvent +import io.getstream.android.video.generated.models.ReportClientEventRequest +import io.getstream.log.taggedLogger +import io.getstream.video.android.core.analytics.reporting.datasource.InMemoryPendingEventDataSource +import io.getstream.video.android.core.analytics.reporting.datasource.PendingEventDataSource +import io.getstream.video.android.core.socket.common.scope.ClientScope +import io.getstream.video.android.core.socket.common.scope.UserScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * Responsible for delivering telemetry [ClientEvent]s to the backend. + * Failed events are handed to a [PendingEventDataSource] and can be retried via [retryPending]. + */ +internal interface EventSender { + fun send(event: ClientEvent) + fun sendAll(events: List) + + /** + * Retries any events that previously failed to send. + * Call this when connectivity is restored or on a suitable recovery point. + */ + fun retryPending() +} + +/** + * Sends each event immediately in a coroutine. + * On network failure the events are saved to [dataSource] for later retry. + */ +internal class ImmediateEventSender( + private val api: ProductvideoApi, + private val scope: CoroutineScope = UserScope(ClientScope()), + private val dataSource: PendingEventDataSource = InMemoryPendingEventDataSource(), +) : EventSender { + + private val logger by taggedLogger("ImmediateEventSender") + + override fun send(event: ClientEvent) = sendAll(listOf(event)) + + override fun sendAll(events: List) { + if (events.isEmpty()) return + scope.launch { + runCatching { + logger.d { events.joinToString(",") { it.toLog() } } + api.reportClientCallEvent(ReportClientEventRequest(events)) + }.onFailure { e -> + logger.w { "[sendAll] Failed — saving ${events.size} event(s) for retry: ${e.message}" } + dataSource.save(events) + } + } + } + + override fun retryPending() { + if (dataSource.isEmpty()) return + val pending = dataSource.loadAndClear() + sendAll(pending) + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/FileBasedPendingEventDataSource.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/FileBasedPendingEventDataSource.kt new file mode 100644 index 00000000000..79a3447ca24 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/FileBasedPendingEventDataSource.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.datasource + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import io.getstream.android.video.generated.infrastructure.Serializer +import io.getstream.android.video.generated.models.ClientEvent +import io.getstream.log.taggedLogger +import java.io.File + +/** + * Persists pending telemetry events to a single NDJSON file across process restarts. + * + * [loadAndClear] reads up to [batchSize] events and removes them from the file. + * The lock only covers the file read/write itself — not the network call — so the + * blocked window is microseconds, not seconds. + * + * This class is not thread-safe on its own; wrap with [SynchronizedPendingEventDataSource]. + */ +internal class FileBasedPendingEventDataSource( + storageDir: File, + moshi: Moshi = Serializer.moshi, + private val batchSize: Int = DEFAULT_BATCH_SIZE, +) : PendingEventDataSource { + + private val logger by taggedLogger("FileBasedPendingEventDataSource") + + private val file = File(storageDir, "pending_events.ndjson") + private val adapter: JsonAdapter = moshi.adapter(ClientEvent::class.java) + + override fun save(events: List) { + if (events.isEmpty()) return + try { + if (file.parentFile?.exists() == false) file.parentFile?.mkdirs() + val lines = events.joinToString(separator = "\n", postfix = "\n") { adapter.toJson(it) } + file.appendText(lines) + } catch (e: Exception) { + logger.w { "[save] Failed to persist ${events.size} event(s): ${e.message}" } + } + } + + override fun loadAndClear(): List { + if (!file.exists() || file.length() == 0L) return emptyList() + return try { + val allLines = file.readLines().filter { it.isNotBlank() } + val batch = allLines.take(batchSize) + val remaining = allLines.drop(batchSize) + if (remaining.isEmpty()) { + file.delete() + } else { + file.writeText(remaining.joinToString(separator = "\n", postfix = "\n")) + } + logger.d { "[loadAndClear] batch=${batch.size}, remaining=${remaining.size}" } + batch.mapNotNull { line -> runCatching { adapter.fromJson(line) }.getOrNull() } + } catch (e: Exception) { + logger.w { "[loadAndClear] Failed: ${e.message}" } + emptyList() + } + } + + override fun isEmpty(): Boolean = !file.exists() || file.length() == 0L + + companion object { + const val DEFAULT_BATCH_SIZE = 10 + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/PendingEventDataSource.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/PendingEventDataSource.kt new file mode 100644 index 00000000000..fbac606f9bd --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/PendingEventDataSource.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.datasource + +import io.getstream.android.video.generated.models.ClientEvent +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Storage for telemetry events that failed to send. + * Implementations may store events in-memory (lost on process kill) + * or on disk (survives process restarts). + */ +internal interface PendingEventDataSource { + fun save(events: List) + fun loadAndClear(): List + fun isEmpty(): Boolean +} + +/** + * In-memory implementation. Events are retained within the same process session + * and lost if the process is killed before retry. + */ +internal class InMemoryPendingEventDataSource : PendingEventDataSource { + private val queue = CopyOnWriteArrayList() + + override fun save(events: List) { + queue.addAll(events) + } + + override fun loadAndClear(): List = queue.toList().also { queue.clear() } + + override fun isEmpty(): Boolean = queue.isEmpty() +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/SynchronizedPendingEventDataSource.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/SynchronizedPendingEventDataSource.kt new file mode 100644 index 00000000000..d3cb1afa550 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/datasource/SynchronizedPendingEventDataSource.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.datasource + +import io.getstream.android.video.generated.models.ClientEvent +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.concurrent.read +import kotlin.concurrent.write + +/** + * Decorator that adds thread-safety to any [PendingEventDataSource]. + * + * Concurrency is the only concern here — all actual storage logic lives in [delegate]. + * + * Usage: + * ``` + * SynchronizedPendingEventDataSource(FileBasedPendingEventDataSource(storageDir)) + * SynchronizedPendingEventDataSource(InMemoryPendingEventDataSource()) + * ``` + * + * [save] and [loadAndClear] acquire a write lock because they mutate state. + * [isEmpty] acquires a read lock so multiple callers can check concurrently + * without blocking each other. + */ +internal class SynchronizedPendingEventDataSource( + private val delegate: PendingEventDataSource, +) : PendingEventDataSource { + + private val lock = ReentrantReadWriteLock() + + override fun save(events: List) = lock.write { delegate.save(events) } + + override fun loadAndClear(): List = lock.write { delegate.loadAndClear() } + + override fun isEmpty(): Boolean = lock.read { delegate.isEmpty() } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsCallAbortReason.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsCallAbortReason.kt new file mode 100644 index 00000000000..201209a76dd --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsCallAbortReason.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal enum class AnalyticsCallAbortReason(val code: String, val message: String) { + CLIENT_ABORTED("CLIENT_ABORTED", "Aborted: user left during retry"), + BACKEND_LEAVE("BACKEND_LEAVE", "Aborted: backend ended call during connect"), +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsFailureCodes.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsFailureCodes.kt new file mode 100644 index 00000000000..a7e3c46f831 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/AnalyticsFailureCodes.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal enum class AnalyticsFailureCodes(val code: String, val message: String) { + CLIENT_ABORTED("CLIENT_ABORTED", "Aborted: user left during retry"), + BACKEND_LEAVE("BACKEND_LEAVE", "Aborted: backend ended call during connect"), + NETWORK_OFFLINE("NETWORK_OFFLINE", "Device offline"), + ICE_GATHERING_FAILED("ICE_GATHERING_FAILED", "ICE gathering failed"), + ICE_CONNECTIVITY_FAILED("ICE_CONNECTIVITY_FAILED", "ICE connectivity failed"), + REQUEST_TIMEOUT("REQUEST_TIMEOUT", "Device offline"), + SFU_REQUEST_TIMEOUT("REQUEST_TIMEOUT", "SFU connection timed out"), +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventOutcome.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventOutcome.kt new file mode 100644 index 00000000000..8f96f4b0301 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventOutcome.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal enum class EventOutcome(val value: String) { + SUCCESS("success"), + FAILURE("failure"), +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventStage.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventStage.kt new file mode 100644 index 00000000000..dfb959dbb60 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventStage.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal sealed interface EventStage { + val value: String + + data object CoordinatorWs : EventStage { + override val value = "CoordinatorWS" + } + + enum class Call(override val value: String) : EventStage { + JOIN_INITIATED("JoinInitiated"), + COORDINATOR_JOIN("CoordinatorJoin"), + WS_JOIN("WSJoin"), + PEER_CONNECTION_CONNECT("PeerConnectionConnect"), + FIRST_AUDIO_FRAME_RENDERED("FirstAudioFrame"), + FIRST_VIDEO_FRAME_RENDERED("FirstVideoFrame"), + MEDIA_DEVICE_PERMISSION("MediaDevicePermission"), + } +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventType.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventType.kt new file mode 100644 index 00000000000..5e262a9fea5 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/EventType.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal enum class EventType(val value: String) { + INITIATED("initiated"), + COMPLETED("completed"), +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/InFlightSession.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/InFlightSession.kt new file mode 100644 index 00000000000..743dd479709 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/InFlightSession.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal typealias StageId = String +internal typealias CallId = String + +internal sealed class InFlightSession( + open val stage: EventStage.Call, + open val startedAtMs: Long, + open val stageId: StageId, +) + +internal data class PostCallFlightSession( + val callId: String, + val callType: String, + override val stageId: StageId, + override val stage: EventStage.Call, + override val startedAtMs: Long, + val joinStageAttemptIdSnapshot: String, + val sfuId: String? = null, + val callSessionId: String? = null, + val userSessionId: String? = null, + val peerConnectionRole: PeerConnectionRole? = null, + val wasPreviouslyConnected: Boolean = false, +) : InFlightSession(stage, startedAtMs, stageId) + +internal data class PreCallInFlightSession( + override val stage: EventStage.Call, + override val startedAtMs: Long, + override val stageId: StageId, + val coordinatorConnectId: String, +) : InFlightSession(stage, startedAtMs, stageId) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/PeerConnectionRole.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/PeerConnectionRole.kt new file mode 100644 index 00000000000..f955d072da9 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/analytics/reporting/model/PeerConnectionRole.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.analytics.reporting.model + +internal enum class PeerConnectionRole(val value: String) { + PUBLISH("publish"), + SUBSCRIBE("subscribe"), +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt index ec4ac64d443..72cb4b97ca2 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt @@ -45,6 +45,8 @@ import io.getstream.video.android.core.MediaManagerImpl import io.getstream.video.android.core.RealtimeConnection import io.getstream.video.android.core.StreamVideo import io.getstream.video.android.core.StreamVideoClient +import io.getstream.video.android.core.analytics.observer.model.TelemetryModel +import io.getstream.video.android.core.analytics.reporting.model.AnalyticsFailureCodes import io.getstream.video.android.core.call.connection.Publisher import io.getstream.video.android.core.call.connection.StreamPeerConnection import io.getstream.video.android.core.call.connection.Subscriber @@ -162,6 +164,7 @@ import stream.video.sfu.signal.UpdateMuteStatesResponse import stream.video.sfu.signal.UpdateSubscriptionsRequest import stream.video.sfu.signal.UpdateSubscriptionsResponse import java.util.Collections + /** * Keeps track of which track is being rendered at what resolution. * Also stores if the track is visible or not @@ -678,7 +681,7 @@ public class RtcSession internal constructor( stateJob = coroutineScope.launch { sfuConnectionModule.socketConnection.state().collect { sfuSocketState -> logger.d { - "[stateJob] SFU socket: $sfuSocketState | " + + "noob [stateJob] SFU socket: $sfuSocketState | " + "connection: ${call.state.connection.value} ($sfuName)" } _sfuSfuSocketState.value = sfuSocketState @@ -708,8 +711,8 @@ public class RtcSession internal constructor( is SfuSocketState.Disconnected.DisconnectedTemporarily -> { val strategy = sfuSocketState.reconnectStrategy val reason = "SFU:${sfuSocketState.error.message}:$strategy" - logger.w { "[stateJob] SFU sent $strategy for $sfuName" } - coroutineScope.launch { call.reconnect(strategy, reason) } + logger.w { "noob [stateJob] SFU sent $strategy for $sfuName" } + call.scope.launch { call.reconnect(strategy, reason) } } is SfuSocketState.Disconnected.WebSocketEventLost -> { @@ -878,8 +881,14 @@ public class RtcSession internal constructor( internal suspend fun connectInternal( reconnectDetails: ReconnectDetails? = null, options: List? = null, + telemetryModel: TelemetryModel? = null, ): SfuConnectionResult { - logger.i { "[connectInternal] #sfu; #track; reconnect=${reconnectDetails?.strategy}" } + logger.i { "noob [connectInternal] #sfu; #track; reconnect=${reconnectDetails?.strategy}" } + call.callAnalyticsCoordinator.sfuSocketObserver.onWsInitiated( + sfuName, + reconnectDetails != null, + ) + val request = buildJoinRequest(reconnectDetails, options) sfuTracer.trace( PeerConnectionTraceKey.JOIN_REQUEST.value, @@ -896,6 +905,11 @@ public class RtcSession internal constructor( } return when (terminalState) { is SfuSocketState.Connected -> { + call.callAnalyticsCoordinator.sfuSocketObserver.onWsCompleted( + success = true, + retryCount = 0, + ) + sendConnectionTimeStats(reconnectDetails?.strategy) SfuConnectionResult.Connected } @@ -909,11 +923,24 @@ public class RtcSession internal constructor( } logger.w { "[connectInternal] $msg" } sfuTracer.trace("connect-failed", msg) + call.callAnalyticsCoordinator.sfuSocketObserver.onWsCompleted( + success = false, + retryCount = telemetryModel?.retryAttempt ?: 0, + failureReason = msg, + failureCode = "WS_DISCONNECTED", + ) sendCallStats() SfuConnectionResult.Failed(Exception(msg)) } else -> { sfuTracer.trace("connect-failed", "Connection timed out") + call.callAnalyticsCoordinator.sfuSocketObserver.onWsCompleted( + success = false, + retryCount = telemetryModel?.retryAttempt ?: 0, + failureReason = AnalyticsFailureCodes.SFU_REQUEST_TIMEOUT.message, + failureCode = AnalyticsFailureCodes.SFU_REQUEST_TIMEOUT.code, + ) + sendCallStats() SfuConnectionResult.Failed(Exception("SFU connection timed out")) } @@ -1107,7 +1134,7 @@ public class RtcSession internal constructor( private val atomicCleanup = AtomicUnitCall() fun cleanup() = atomicCleanup { - logger.i { "[cleanup] #sfu; #track; no args" } + logger.i { "noob [cleanup] #sfu; #track; no args" } coroutineScope.launch { serialProcessor.submit("cleanupSfuConnections") { @@ -1335,7 +1362,7 @@ public class RtcSession internal constructor( rejoin = { logger.d { "[createPublisher] rejoin attempt, connection state: ${call.state.connection.value}" } if (call.state.connection.value !is RealtimeConnection.Reconnecting) { - coroutineScope.launch { + call.scope.launch { // TODO Rahul, self cancelling coroutine code serialProcessor.submit("publisherRejoin") { logger.d { "[createPublisher] rejoin attempt EXECUTE, connection state: ${call.state.connection.value} " @@ -1889,7 +1916,7 @@ public class RtcSession internal constructor( return Triple(previousSessionId, currentSubscriptions, publisherTracks) } - internal suspend fun fastReconnect(reconnectDetails: ReconnectDetails?): FastReconnectResult { + internal suspend fun fastReconnect(reconnectDetails: ReconnectDetails?, telemetryModel: TelemetryModel? = null): FastReconnectResult { logger.d { "[fastReconnect] Starting fast reconnect." } sfuTracer.trace("fastReconnect", reconnectDetails.toString()) val (_, _, publisherTracks) = currentSfuInfo() @@ -1898,6 +1925,7 @@ public class RtcSession internal constructor( val connectResult = connectInternal( reconnectDetails, publisher.value?.currentOptions(), + telemetryModel, ) if (connectResult is SfuConnectionResult.Failed) { return FastReconnectResult.Failed(connectResult.error) @@ -1966,11 +1994,13 @@ public class RtcSession internal constructor( // Tears down the old session after migration is confirmed (or timed out). // No sendLeaveEvent — matches JS SDK behavior (just close WS, no explicit leave for migration). internal fun finalizeMigration() { + logger.d { "noob [finalizeMigration]" } eventJob?.cancel() cleanup() } internal suspend fun prepareRejoin(reason: String) { + logger.d { "noob [prepareRejoin] reason: $reason" } val stats = call.collectStats() sendCallStats(stats) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnection.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnection.kt index ab79ab0b21d..116cc1fd6ac 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnection.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnection.kt @@ -96,6 +96,7 @@ open class StreamPeerConnection( // see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState internal val state = MutableStateFlow(null) internal val iceState = MutableStateFlow(null) + internal val iceError = MutableStateFlow(null) open suspend fun stats(): ComputedStats? = null @@ -173,6 +174,7 @@ open class StreamPeerConnection( this.statsTracer = StatsTracer(connection, type.toPeerType()) this.state.value = this.connection.connectionState() this.iceState.value = this.connection.iceConnectionState() + this.iceError.value = null } /** @@ -539,6 +541,12 @@ open class StreamPeerConnection( override fun onConnectionChange(newState: PeerConnection.PeerConnectionState) { logger.i { "[onConnectionChange] #sfu; #$typeTag; newState: $newState" } state.value = newState + when (newState) { + PeerConnection.PeerConnectionState.CONNECTED -> { + iceError.value = null + } + else -> {} + } tracer.trace(PeerConnectionTraceKey.ON_CONNECTION_STATE_CHANGE.value, newState.name) } @@ -613,6 +621,7 @@ open class StreamPeerConnection( override fun onIceCandidateError(event: IceCandidateErrorEvent?) { logger.e { "[onIceCandidateError] #sfu; #$typeTag; event: ${event?.stringify()}" } + iceError.value = event } override fun onSelectedCandidatePairChanged(event: CandidatePairChangeEvent?) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnectionFactory.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnectionFactory.kt index e28647cc048..1d1fcb5c3ee 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnectionFactory.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/connection/StreamPeerConnectionFactory.kt @@ -88,6 +88,7 @@ public class StreamPeerConnectionFactory( private val audioLogger by taggedLogger("Call:AudioTrackCallback") private var audioSampleCallback: ((AudioSamples) -> Unit)? = null + private var playbackSamplesReadyCallback: (() -> Unit)? = null private var audioRecordDataCallback: ( (audioFormat: Int, channelCount: Int, sampleRate: Int, sampleData: ByteBuffer) -> Unit )? = null @@ -107,6 +108,10 @@ public class StreamPeerConnectionFactory( audioSampleCallback = callback } + internal fun setPlaybackSamplesReadyCallback(callback: (() -> Unit)?) { + playbackSamplesReadyCallback = callback + } + /** * Set to get callbacks when audio input from microphone is received. * This can be example used to detect whether a person is speaking @@ -273,6 +278,9 @@ public class StreamPeerConnectionFactory( ) } } + .setPlaybackSamplesReadyCallback { + playbackSamplesReadyCallback?.invoke() + } .setUseHardwareNoiseSuppressor(useHardwareNoiseSuppressor) .setAudioRecordErrorCallback(object : JavaAudioDeviceModule.AudioRecordErrorCallback { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/TypingIndicators.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureInjector.kt similarity index 51% rename from stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/TypingIndicators.kt rename to stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureInjector.kt index 2dd76e1094e..e524a828539 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/android/video/generated/models/TypingIndicators.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureInjector.kt @@ -14,31 +14,28 @@ * limitations under the License. */ -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package io.getstream.android.video.generated.models - -import kotlin.collections.List -import kotlin.collections.Map -import kotlin.collections.* -import kotlin.io.* -import com.squareup.moshi.FromJson -import com.squareup.moshi.Json -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.JsonReader -import com.squareup.moshi.JsonWriter -import com.squareup.moshi.ToJson - -/** - * - */ +package io.getstream.video.android.core.faultinjector + +import io.getstream.video.android.core.internal.InternalStreamVideoApi + +@InternalStreamVideoApi +public interface FailureInjector { + + fun enable(key: FailureKey) + + fun disable(key: FailureKey) + + fun setEnabled(key: FailureKey, enabled: Boolean) + + fun isEnabled(key: FailureKey): Boolean + + fun clear() + + fun throwDebugFault(key: FailureKey) + + fun sendFailResult(key: FailureKey): io.getstream.result.Result.Failure + + fun setCount(key: FailureKey, count: Int) -data class TypingIndicators ( - @Json(name = "enabled") - val enabled: kotlin.Boolean -) + fun getCount(key: FailureKey): Int +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureKey.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureKey.kt new file mode 100644 index 00000000000..1411d43400f --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/FailureKey.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.faultinjector + +import io.getstream.video.android.core.internal.InternalStreamVideoApi + +@InternalStreamVideoApi +public enum class FailureKey { + + // REST + FAIL_JOIN_CALL, + FAIL_LOCATION, + + // WebSocket + FAIL_WS_CONNECT, + + // Reconnect Strategy + FAIL_FAST_RECONNECT, + FAIL_FULL_REJOIN, + FAIL_MIGRATE, +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/NoOpFailureInjector.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/NoOpFailureInjector.kt new file mode 100644 index 00000000000..f2114c11c47 --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/faultinjector/NoOpFailureInjector.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.core.faultinjector + +import io.getstream.result.Error + +internal class NoOpFailureInjector : FailureInjector { + + override fun enable(key: FailureKey) {} + override fun disable(key: FailureKey) {} + override fun setEnabled(key: FailureKey, enabled: Boolean) {} + override fun isEnabled(key: FailureKey): Boolean = false + override fun clear() {} + override fun throwDebugFault(key: FailureKey) {} + override fun sendFailResult(key: FailureKey): io.getstream.result.Result.Failure { + return io.getstream.result.Result.Failure( + Error.GenericError("Failure injected: $key"), + ) + } + + override fun setCount( + key: FailureKey, + count: Int, + ) {} + + override fun getCount(key: FailureKey): Int = 0 +} diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt index a1ba9da074f..0135570cd2e 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt @@ -21,6 +21,8 @@ import android.content.Intent import androidx.core.app.NotificationManagerCompat import io.getstream.log.taggedLogger import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason +import io.getstream.video.android.core.UserActionCause import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_LEAVE_CALL import io.getstream.video.android.core.notifications.NotificationHandler.Companion.INTENT_EXTRA_NOTIFICATION_ID @@ -37,7 +39,12 @@ internal class LeaveCallBroadcastReceiver : GenericCallActionBroadcastReceiver() override suspend fun onReceive(call: Call, context: Context, intent: Intent) { logger.d { "[onReceive] #ringing; callId: ${call.id}, action: ${intent.action}" } - call.leave("LeaveCallBroadcastReceiver") + call.leave( + CallLeaveReason.UserAction( + UserActionCause.LEAVE_FROM_NOTIFICATION, + message = "User left via notification action", + ), + ) val notificationId = intent.getIntExtra(INTENT_EXTRA_NOTIFICATION_ID, 0) logger.d { "[onReceive], notificationId: $notificationId" } NotificationManagerCompat.from(context).cancel(notificationId) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/managers/CallServiceLifecycleManager.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/managers/CallServiceLifecycleManager.kt index c2c6b8f56ec..40c4645680b 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/managers/CallServiceLifecycleManager.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/managers/CallServiceLifecycleManager.kt @@ -19,7 +19,9 @@ package io.getstream.video.android.core.notifications.internal.service.managers import io.getstream.log.taggedLogger import io.getstream.result.Error import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.RingingState +import io.getstream.video.android.core.SdkCause import io.getstream.video.android.core.StreamVideo import io.getstream.video.android.core.model.RejectReason import io.getstream.video.android.model.StreamCallId @@ -96,7 +98,12 @@ internal class CallServiceLifecycleManager { } else -> { - call.leave("call-service-end-call-unknown") + call.leave( + CallLeaveReason.SdkDriven( + cause = SdkCause.TASK_REMOVED, + message = "App removed from recents (unknown call state)", + ), + ) logger.i { "[onTaskRemoved] Ended ongoing call for me" } } } @@ -114,7 +121,12 @@ internal class CallServiceLifecycleManager { logger.i { "[handleIncomingCallTaskRemoved] Ended incoming call for both users" } } } else { - call.leave("call-service-end-call-incoming") + call.leave( + CallLeaveReason.SdkDriven( + cause = SdkCause.TASK_REMOVED, + message = "App removed from recents (incoming call)", + ), + ) logger.i { "[handleIncomingCallTaskRemoved] Ended incoming call for me" } } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/IncomingCallTelecomAction.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/IncomingCallTelecomAction.kt index c30d84a49b1..7e711e7022c 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/IncomingCallTelecomAction.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/IncomingCallTelecomAction.kt @@ -16,10 +16,12 @@ package io.getstream.video.android.core.notifications.internal.telecom +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.ExternalCallRejectionHandler import io.getstream.video.android.core.ExternalCallRejectionSource import io.getstream.video.android.core.RingingState import io.getstream.video.android.core.StreamVideo +import io.getstream.video.android.core.UserActionCause import io.getstream.video.android.core.notifications.IncomingNotificationAction import io.getstream.video.android.model.StreamCallId import kotlinx.coroutines.launch @@ -48,7 +50,12 @@ internal class IncomingCallTelecomAction(private val streamVideo: StreamVideo) { } is RingingState.Active -> { - streamVideo.call(callId.type, callId.id).leave() + streamVideo.call(callId.type, callId.id).leave( + CallLeaveReason.UserAction( + UserActionCause.WEARABLE_CANCEL, + "cancel from wearable", + ), + ) } is RingingState.Incoming -> { val pendingIntentMap = streamVideo.call(callId.type, callId.id) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/coordinator/CoordinatorSocketStateService.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/coordinator/CoordinatorSocketStateService.kt index 0e81094d90b..af8424a5f39 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/coordinator/CoordinatorSocketStateService.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/coordinator/CoordinatorSocketStateService.kt @@ -30,6 +30,13 @@ import kotlinx.coroutines.flow.StateFlow internal class CoordinatorSocketStateService(initialState: VideoSocketState = VideoSocketState.Disconnected.Stopped) { private val logger by taggedLogger("Video:SocketState") + // TODO making it companion because CoordinatorSocketConnection has public constructor + // So we cannot inject CoordinatorSocketStateService from StreamBuilder without breaking apis + internal companion object { + var retryAttempts = 0 + var lastRetryAttempts = 0 + } + suspend fun observer(onNewState: suspend (VideoSocketState) -> Unit) { stateMachine.stateFlow.collect(onNewState) } @@ -43,6 +50,7 @@ internal class CoordinatorSocketStateService(initialState: VideoSocketState = Vi connectionConf: ConnectionConf, forceReconnection: Boolean, ) { + retryAttempts += 1 logger.v { "[onReconnect] user.id: '${connectionConf.user.id}', isReconnection: ${connectionConf.isReconnection}" } @@ -63,6 +71,8 @@ internal class CoordinatorSocketStateService(initialState: VideoSocketState = Vi * @param connectionConf The [VideoSocketFactory.ConnectionConf] to be used on the new connection. */ suspend fun onConnect(connectionConf: ConnectionConf) { + lastRetryAttempts = retryAttempts + retryAttempts = 0 logger.v { "[onConnect] user.id: '${connectionConf.user.id}', isReconnection: ${connectionConf.isReconnection}" } @@ -88,6 +98,8 @@ internal class CoordinatorSocketStateService(initialState: VideoSocketState = Vi * @param connectedEvent The [ConnectedEvent] received within the WebSocket connection. */ suspend fun onConnectionEstablished(connectedEvent: ConnectedEvent) { + lastRetryAttempts = retryAttempts + retryAttempts = 0 logger.i { "[onConnected] user.id: '${connectedEvent.me.id}', connectionId: ${connectedEvent.connectionId}" } @@ -100,6 +112,8 @@ internal class CoordinatorSocketStateService(initialState: VideoSocketState = Vi * @param error The [Error.NetworkError] */ suspend fun onUnrecoverableError(error: Error.NetworkError) { + lastRetryAttempts = retryAttempts + retryAttempts = 0 logger.e { "[onUnrecoverableError] error: $error" } stateMachine.sendEvent(VideoSocketStateEvent.UnrecoverableError(error)) } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt index afeb22012b7..38095832221 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocket.kt @@ -20,6 +20,7 @@ package io.getstream.video.android.core.socket.sfu import io.getstream.log.taggedLogger import io.getstream.result.Error +import io.getstream.video.android.core.StreamVideo import io.getstream.video.android.core.dispatchers.DispatcherProvider import io.getstream.video.android.core.errors.DisconnectCause import io.getstream.video.android.core.errors.VideoErrorCode @@ -29,6 +30,7 @@ import io.getstream.video.android.core.events.SFUHealthCheckEvent import io.getstream.video.android.core.events.SfuDataEvent import io.getstream.video.android.core.events.SfuDataRequest import io.getstream.video.android.core.events.UnknownEvent +import io.getstream.video.android.core.faultinjector.FailureKey import io.getstream.video.android.core.internal.network.NetworkStateProvider import io.getstream.video.android.core.lifecycle.NoOpLifecycleHandler import io.getstream.video.android.core.lifecycle.StreamLifecycleObserver @@ -107,6 +109,7 @@ internal open class SfuSocket( streamWebSocket?.close("connectUser:cleanup") when (networkStateProvider.isConnected()) { true -> { + debugFaultInjectors(connectionConf) streamWebSocket = socketFactory.createSocket(connectionConf, "#sfu").apply { listeners.forEach { it.onCreated() } @@ -219,6 +222,31 @@ internal open class SfuSocket( } } + private fun debugFaultInjectors(connectionConf: ConnectionConf.SfuConnectionConf) { + StreamVideo.instanceOrNull()?.state?.failureInjector?.let { faultInjector -> + if (faultInjector.isEnabled(FailureKey.FAIL_WS_CONNECT)) { + faultInjector.throwDebugFault(FailureKey.FAIL_WS_CONNECT) + } + val isFastReconnect = + connectionConf.joinRequest.reconnect_details?.strategy == WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_FAST + if (isFastReconnect && faultInjector.isEnabled(FailureKey.FAIL_FAST_RECONNECT)) { + faultInjector.throwDebugFault(FailureKey.FAIL_FAST_RECONNECT) + } + + val isFullRejoin = + connectionConf.joinRequest.reconnect_details?.strategy == WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_REJOIN + if (isFullRejoin && faultInjector.isEnabled(FailureKey.FAIL_FULL_REJOIN)) { + faultInjector.throwDebugFault(FailureKey.FAIL_FULL_REJOIN) + } + + val isMigrate = + connectionConf.joinRequest.reconnect_details?.strategy == WebsocketReconnectStrategy.WEBSOCKET_RECONNECT_STRATEGY_MIGRATE + if (isMigrate && faultInjector.isEnabled(FailureKey.FAIL_MIGRATE)) { + faultInjector.throwDebugFault(FailureKey.FAIL_MIGRATE) + } + } + } + suspend fun connect(joinRequest: JoinRequest) { logger.d { "[connect] request: ${joinRequest.client_details}" } socketListenerJob?.cancel() diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocketConnection.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocketConnection.kt index 8b1316dac39..848f558a90a 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocketConnection.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/sfu/SfuSocketConnection.kt @@ -165,7 +165,7 @@ class SfuSocketConnection( } override suspend fun connect(connectData: JoinRequest) { - logger.d { "[connect] request: $connectData" } + logger.d { "noob [connect] request: $connectData" } internalSocket.connect(connectData) } diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt index b03211e7723..b741845ec7d 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt @@ -70,9 +70,11 @@ import io.getstream.video.android.compose.ui.components.call.ringing.RingingCall import io.getstream.video.android.compose.ui.components.livestream.LivestreamPlayer import io.getstream.video.android.compose.ui.components.video.config.videoRenderConfig import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.MemberState import io.getstream.video.android.core.RealtimeConnection import io.getstream.video.android.core.StreamVideo +import io.getstream.video.android.core.UserActionCause import io.getstream.video.android.core.call.CallType import io.getstream.video.android.core.call.state.CallAction import io.getstream.video.android.core.call.state.CancelCall @@ -224,7 +226,12 @@ public open class StreamCallActivityComposeDelegate : StreamCallActivityComposeU call = call, centerContent = { }, onCallAction = { - call.leave() + call.leave( + CallLeaveReason.UserAction( + UserActionCause.CANCELLED_BY_SELF, + "Cancelled the call", + ), + ) safeFinish() }, ) diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioControlActions.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioControlActions.kt index c144b3f0da1..6f5879c8017 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioControlActions.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioControlActions.kt @@ -38,6 +38,8 @@ import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.compose.ui.components.base.StreamButton import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleMicrophoneAction import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason +import io.getstream.video.android.core.UserActionCause import io.getstream.video.android.mock.StreamPreviewDataUtils import io.getstream.video.android.mock.previewCall @@ -69,7 +71,12 @@ public fun AudioControlActions( style = VideoTheme.styles.buttonStyles.secondaryButtonStyle(), onClick = { onLeaveRoom?.invoke() ?: let { - call.leave() + call.leave( + CallLeaveReason.UserAction( + UserActionCause.CANCELLED_BY_SELF, + "Cancelled the call", + ), + ) activity?.onBackPressedDispatcher?.onBackPressed() } }, diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioRoomContent.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioRoomContent.kt index a1778716882..279ce5a940c 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioRoomContent.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/AudioRoomContent.kt @@ -47,7 +47,9 @@ import io.getstream.video.android.compose.pip.enterPictureInPicture import io.getstream.video.android.compose.pip.rememberIsInPipMode import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.ParticipantState +import io.getstream.video.android.core.SdkCause import io.getstream.video.android.core.pip.PictureInPictureConfiguration import io.getstream.video.android.mock.StreamPreviewDataUtils import io.getstream.video.android.mock.previewCall @@ -139,7 +141,12 @@ public fun AudioRoomContent( enterPictureInPicture(context = context, call = call, pictureInPictureConfiguration) } catch (e: Exception) { StreamLog.e(tag = "AudioRoomContent") { e.stackTraceToString() } - call.leave() + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.PIP_ERROR, + "Error in Pip: ${e.message}", + ), + ) } } else { onBackPressed.invoke() diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/activecall/CallContent.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/activecall/CallContent.kt index 505337986fa..d4718acdd78 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/activecall/CallContent.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/activecall/CallContent.kt @@ -76,7 +76,9 @@ import io.getstream.video.android.compose.ui.components.call.renderer.VideoRende import io.getstream.video.android.compose.ui.components.call.renderer.internal.LocalVideoContentSize import io.getstream.video.android.compose.ui.components.video.VideoRenderer import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.ParticipantState +import io.getstream.video.android.core.SdkCause import io.getstream.video.android.core.StreamVideo import io.getstream.video.android.core.call.state.CallAction import io.getstream.video.android.core.notifications.internal.service.CallServiceConfig @@ -189,7 +191,12 @@ public fun CallContent( enterPictureInPicture(context = context, call = call, pictureInPictureConfiguration) } catch (e: Exception) { StreamLog.e(tag = "CallContent") { e.stackTraceToString() } - call.leave() + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.PIP_ERROR, + "Error in Pip: ${e.message}", + ), + ) } } else { onBackPressed.invoke() diff --git a/stream-video-android-ui-core/api/stream-video-android-ui-core.api b/stream-video-android-ui-core/api/stream-video-android-ui-core.api index 35f2bde4592..100fe7788fa 100644 --- a/stream-video-android-ui-core/api/stream-video-android-ui-core.api +++ b/stream-video-android-ui-core/api/stream-video-android-ui-core.api @@ -41,6 +41,11 @@ public abstract interface class io/getstream/video/android/ui/common/ActivityCal public static synthetic fun reject$default (Lio/getstream/video/android/ui/common/ActivityCallOperations;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/core/model/RejectReason;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V } +public abstract interface class io/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason : io/getstream/video/android/ui/common/ActivityCallOperations { + public fun leave (Lio/getstream/video/android/core/Call;Lio/getstream/video/android/core/CallLeaveReason;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V + public static synthetic fun leave$default (Lio/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/core/CallLeaveReason;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V +} + public abstract class io/getstream/video/android/ui/common/IgnoreReason { } @@ -80,7 +85,7 @@ public abstract interface class io/getstream/video/android/ui/common/StreamActiv public abstract fun setContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;)V } -public abstract class io/getstream/video/android/ui/common/StreamCallActivity : androidx/activity/ComponentActivity, io/getstream/video/android/ui/common/ActivityCallOperations { +public abstract class io/getstream/video/android/ui/common/StreamCallActivity : androidx/activity/ComponentActivity, io/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason { public static final field Companion Lio/getstream/video/android/ui/common/StreamCallActivity$Companion; public fun ()V public fun accept (Lio/getstream/video/android/core/Call;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V @@ -107,6 +112,7 @@ public abstract class io/getstream/video/android/ui/common/StreamCallActivity : public fun isCurrentAcceptedCall (Lio/getstream/video/android/core/Call;)Z public fun isVideoCall (Lio/getstream/video/android/core/Call;)Z public fun join (Lio/getstream/video/android/core/Call;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V + public fun leave (Lio/getstream/video/android/core/Call;Lio/getstream/video/android/core/CallLeaveReason;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V public fun leave (Lio/getstream/video/android/core/Call;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V protected fun loadConfigFromIntent (Landroid/content/Intent;)Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration; public fun onBackPressed (Lio/getstream/video/android/core/Call;)V diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/AbstractCallActivity.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/AbstractCallActivity.kt index 845f2b20905..85e392759ae 100644 --- a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/AbstractCallActivity.kt +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/AbstractCallActivity.kt @@ -30,6 +30,8 @@ import android.view.WindowInsetsController import android.view.WindowManager import androidx.activity.ComponentActivity import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason +import io.getstream.video.android.core.SdkCause import io.getstream.video.android.core.call.state.ToggleScreenConfiguration import io.getstream.video.android.core.pip.PictureInPictureConfiguration import io.getstream.video.android.model.StreamCallId @@ -125,7 +127,12 @@ public abstract class AbstractCallActivity : ComponentActivity() { try { enterPictureInPicture() } catch (error: Throwable) { - call.leave() + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.PIP_ERROR, + "Error in Pip: ${error.message}", + ), + ) } } @@ -171,14 +178,18 @@ public abstract class AbstractCallActivity : ComponentActivity() { val isInPiP = isInPictureInPictureMode if (isInPiP) { - call.leave() + call.leave(CallLeaveReason.SdkDriven(SdkCause.PIP_STOPPED, "PIP stopped")) } } override fun onDestroy() { super.onDestroy() - - call.leave() + call.leave( + CallLeaveReason.SdkDriven( + SdkCause.ACTIVITY_DESTROYED, + "${this.localClassName} destroyed", + ), + ) } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperations.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperations.kt index 1eb8c2db341..57a810c8c37 100644 --- a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperations.kt +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperations.kt @@ -46,6 +46,16 @@ public interface ActivityCallOperations { onError: (suspend (Exception) -> Unit)? = null, ) +// @StreamCallActivityDelicateApi +// public fun leave( +// call: Call, +// callLeaveReason: CallLeaveReason, +// onSuccess: (suspend (Call) -> Unit)? = null, +// onError: (suspend (Exception) -> Unit)? = null, +// ) { +// // Do nothing +// } + @StreamCallActivityDelicateApi public fun end( call: Call, diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason.kt new file mode 100644 index 00000000000..7a6c0ad5b25 --- /dev/null +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/ActivityCallOperationsWithCallLeaveReason.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * 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.getstream.video.android.ui.common + +import io.getstream.video.android.core.Call +import io.getstream.video.android.core.CallLeaveReason +import io.getstream.video.android.ui.common.util.StreamCallActivityDelicateApi + +public interface ActivityCallOperationsWithCallLeaveReason : ActivityCallOperations { + + @StreamCallActivityDelicateApi + public fun leave( + call: Call, + callLeaveReason: CallLeaveReason, + onSuccess: (suspend (Call) -> Unit)? = null, + onError: (suspend (Exception) -> Unit)? = null, + ) { + // Do nothing + } +} diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt index 9d7c3f15e4b..34960f08906 100644 --- a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt @@ -47,9 +47,12 @@ import io.getstream.result.onErrorSuspend import io.getstream.result.onSuccessSuspend import io.getstream.video.android.core.Call import io.getstream.video.android.core.CallJoinInterceptor +import io.getstream.video.android.core.CallLeaveReason import io.getstream.video.android.core.DeviceStatus import io.getstream.video.android.core.RealtimeConnection +import io.getstream.video.android.core.SdkCause import io.getstream.video.android.core.StreamVideo +import io.getstream.video.android.core.UserActionCause import io.getstream.video.android.core.call.RtcSession import io.getstream.video.android.core.call.state.AcceptCall import io.getstream.video.android.core.call.state.CallAction @@ -92,7 +95,7 @@ import kotlinx.coroutines.withContext import java.util.Locale @OptIn(StreamCallActivityDelicateApi::class) -public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOperations { +public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOperationsWithCallLeaveReason { // Factory and creation public companion object { // Extra keys @@ -242,6 +245,12 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper val configuration = configurationMap[error.call.id] if (configuration?.closeScreenOnError == true) { logger.e(error) { "Finishing the activity" } + error.call.leave( + CallLeaveReason.SdkDriven( + SdkCause.STREAM_CALL_ACTIVITY_EXCEPTION, + "${error.message}", + ), + ) safeFinish() } } else { @@ -473,7 +482,15 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper participantCountJob = null // We want to leave the ongoing active call - leave(activeCall, onSuccessFinish, onErrorFinish) + leave( + activeCall, + CallLeaveReason.UserAction( + UserActionCause.CANCELLED_BY_SELF, + "Leaving current ongoing call to pick incoming-call with call_cid:$newCallCid", + ), + onSuccessFinish, + onErrorFinish, + ) lifecycleScope.launch(Dispatchers.Default) { delay( getCallTransitionTime(), @@ -764,7 +781,12 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper * @param call the call. */ public open fun onBackPressed(call: Call) { - leave(call, onSuccessFinish, onErrorFinish) + leave( + call, + CallLeaveReason.UserAction(UserActionCause.CANCELLED_BY_SELF, "on back press"), + onSuccessFinish, + onErrorFinish, + ) } // Decision making @@ -1037,7 +1059,12 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper } // Leave regardless of outcome - call.leave() + call.leave( + CallLeaveReason.UserAction( + UserActionCause.REJECTED_BY_SELF, + "Rejected the call", + ), + ) } } @@ -1071,12 +1098,21 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper call: Call, onSuccess: (suspend (Call) -> Unit)?, onError: (suspend (Exception) -> Unit)?, + ) { + leave(call, CallLeaveReason.Custom(""), onSuccess, onError) + } + + override fun leave( + call: Call, + callLeaveReason: CallLeaveReason, + onSuccess: (suspend (Call) -> Unit)?, + onError: (suspend (Exception) -> Unit)?, ) { logger.d { "Leave call, ${call.cid}" } lifecycleScope.launch(Dispatchers.IO) { // Will quietly leave the call, leaving it intact for the other participants. try { - call.leave() + call.leave(callLeaveReason) onSuccess?.invoke(call) } catch (e: Exception) { onError?.invoke(e) @@ -1116,7 +1152,15 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper logger.i { "[onCallAction] #ringing; action: $action, call.cid: ${call.cid}" } when (action) { is LeaveCall -> { - leave(call, onSuccessFinish, onErrorFinish) + leave( + call, + CallLeaveReason.UserAction( + UserActionCause.CANCELLED_BY_SELF, + "cancelling the call", + ), + onSuccessFinish, + onErrorFinish, + ) } is DeclineCall -> { @@ -1162,7 +1206,15 @@ public abstract class StreamCallActivity : ComponentActivity(), ActivityCallOper when (event) { is CallEndedEvent, is CallEndedSfuEvent, is CallSessionEndedEvent, is LocalCallMissedEvent -> { // In any case finish the activity, the call is done for - leave(call, onSuccess = onSuccessFinish, onError = onErrorFinish) + leave( + call, + CallLeaveReason.SdkDriven( + SdkCause.END_CALL, + "received event: ${event.javaClass.name}", + ), + onSuccess = onSuccessFinish, + onError = onErrorFinish, + ) } is ParticipantLeftEvent, is CallSessionParticipantLeftEvent -> {