# Session timers

In some cases, you want to be able to limit the duration of a call. StreamVideo supports this use-case by allowing you to specify the duration of a call on creation. Additionally, it provides you a way to extend the duration during the call, if needed.

## Low-level client capabilities

First, let's see how we can create a call that has a limited duration.

```kotlin
val callSettings = CallSettingsRequest(
    limits = LimitsSettingsRequest(maxDurationSeconds = 300)
)
val call = streamVideo.call(callType = "default", callId = "callId")
call.create(settings = callSettings)
```

This code will create a call, which will have a duration of 300 seconds (5 minutes), as soon as the session is started (a participant joins the call).
You can check the start date of a call with the following code:

```kotlin
val startedAt = call.state.session?.value?.startedAt
```

When the maxDuration of a call is specified, the call session also provides the `timerEndsAt` value, which provides the date when the call will end. When a call is ended, all the participants are removed from the call.

```kotlin
val timerEndsAt = call.state.session?.value?.timerEndsAt
```

## Extending the call duration

You can also extend the duration of a call, both before or during the call. To do that, you should use the `call.update` method:

```kotlin
val extendDuration = 120 // Example extension duration in seconds
val newDuration = (call.state.settings?.value?.limits?.maxDurationSeconds ?: 0) + extendDuration
val newSettings = CallSettingsRequest(
    limits = LimitsSettingsRequest(maxDurationSeconds = newDuration)
)
call.update(settingsOverride = newSettings)
```

When the call duration is extended, the `timerEndsAt` will be updated to reflect that change.

## Example implementation

Let's see how we can put these methods together in a sample session timer implementation.
In this cookbook, we will show a popup that will notify the user that a call will end soon. It will also allow the creator of the call to extend its duration.

Prerequisite for following along is a working StreamVideo integration and the ability to establish calls. To help with that, check our tutorials and getting started docs.

## Session Timer example

For the purpose of this example we'll assume that the application incorporates a view model architecture.
Let's create a new Kotlin file, and call it `SessionTimerViewModel.kt`. We will put the following contents in it:

```kotlin
class SessionTimerViewModel(
    private val call: Call?, // Replace with your `Call` data type
    private val alertInterval: Long, // In milliseconds
    private val extendDuration: Long = 120_000L // Default to 2 minutes in milliseconds
) : ViewModel() {

    var showTimerAlert by mutableStateOf(false)
        private set

    var secondsUntilEnd by mutableStateOf(0L)
        private set

    private var timerEndsAt: OffsetDateTime? = call?.state?.session?.value?.timerEndsAt
        set(value) {
            field = value
            setupTimerIfNeeded()
        }

    private var countdownJob: Job? = null
    private var extendDurationAccumulator = extendDuration

    val showExtendCallDurationButton: Boolean
        get() = call?.state?.ownCapabilities?.value?.contains(OwnCapability.ChangeMaxDuration) == true

    init {
        setupTimerIfNeeded()
        subscribeForSessionUpdates()
    }

    fun extendCallDuration() {
        call?.let {
            viewModelScope.launch {
                try {
                    val newDuration =
                        (it.state.settings.value?.limits?.maxDurationSeconds
                            ?: 0) * 1000 + extendDurationAccumulator
                    extendDurationAccumulator += extendDuration
                    call.update(
                        settingsOverride = CallSettingsRequest(
                            limits = LimitsSettingsRequest(maxDurationSeconds = (newDuration / 1000).toInt())
                        )
                    )
                    showTimerAlert = false
                } catch (e: Exception) {
                    // Handle the error, e.g., log it
                }
            }
        }
    }

    private fun subscribeForSessionUpdates() {
        // Subscribe to session updates
        // Replace with your own logic for session updates
        viewModelScope.launch {
            call?.state?.session?.collect { session ->
                if (session?.timerEndsAt != timerEndsAt) {
                    timerEndsAt = session?.timerEndsAt
                }
            }
        }
    }

    private fun setupTimerIfNeeded() {
        countdownJob?.cancel()
        countdownJob = null
        showTimerAlert = false

        timerEndsAt?.let { endTime ->
            val alertTime = endTime.minusSeconds(alertInterval / 1000)
            val timeUntilAlert = alertTime.toInstant().toEpochMilli() - System.currentTimeMillis()
            if (timeUntilAlert <= 0) {
                showTimerAlert = true
            } else {
                viewModelScope.launch {
                    delay(timeUntilAlert)
                    showTimerAlert = true
                    startCountdown(endTime)
                }
            }
        }
    }

    private fun startCountdown(endTime: OffsetDateTime) {
        countdownJob = viewModelScope.launch {
            while (true) {
                val timeLeft = (endTime.toEpochSecond() * 1000 - System.currentTimeMillis()) / 1000
                if (timeLeft <= 0) {
                    showTimerAlert = false
                    secondsUntilEnd = 0
                    break
                } else {
                    secondsUntilEnd = timeLeft
                }
                delay(1000)
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        countdownJob?.cancel()
    }

    fun dismiss() {
        showTimerAlert = false
    }
}
```

You can directly add the following imports if needed:

```kotlin
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.getstream.android.video.generated.models.CallSettingsRequest
import io.getstream.android.video.generated.models.LimitsSettingsRequest
import io.getstream.android.video.generated.models.OwnCapability
import io.getstream.video.android.core.Call
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.threeten.bp.OffsetDateTime
```

In the Jetpack Compose view shown during a call, we'll use the `SessionTimerViewModel` to display the session timer popup and a countdown timer.
The `showTimerAlert` state will determine when the popup should be visible, and the `secondsUntilEnd` will be used to show the remaining time.

Here's how you can use the `SessionTimerViewModel` in your composable:

```kotlin
@Composable
fun YourCallScreen(
    viewModel: SessionTimerViewModel,
) {
    // Observe the state from the ViewModel
    // Main Call Screen UI
    Box(modifier = Modifier.fillMaxSize()) {
        // Other call UI components go here

        if (viewModel.showTimerAlert) {
            TimerPopup(
                viewModel = viewModel,
                secondsUntilEnd = viewModel.secondsUntilEnd,
                onDismiss = { viewModel.dismiss() }
            )
        }
    }
}

@Composable
fun TimerPopup(
    viewModel: SessionTimerViewModel,
    secondsUntilEnd: Long,
    onDismiss: () -> Unit
) = Popup(onDismissRequest = onDismiss) {
    // Popup dialog to show the timer and options
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Black.copy(alpha = 0.5f))
            .clickable(onClick = onDismiss)
    ) {
        Column(
            modifier = Modifier
                .align(Alignment.Center)
                .background(Color.White, shape = RoundedCornerShape(8.dp))
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Call will end in", style = MaterialTheme.typography.h6)
            Text(
                text = formatSecondsToTime(secondsUntilEnd),
                style = MaterialTheme.typography.h4,
                color = Color.Red
            )
            Spacer(modifier = Modifier.height(16.dp))
            if (viewModel.showExtendCallDurationButton) {
                Button(onClick = {
                    viewModel.extendCallDuration()
                }) {
                    Text("Extend Call")
                }
            }
            Spacer(modifier = Modifier.height(8.dp))
            TextButton(onClick = onDismiss) {
                Text("Dismiss")
            }
        }
    }
}

fun formatSecondsToTime(seconds: Long): String {
    val minutes = seconds / 60
    val remainingSeconds = seconds % 60
    return String.format("%02d:%02d", minutes, remainingSeconds)
}
```

If you like you can use the following imports:

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
```

With that, you can have a working implementation of a session timer.


---

This page was last updated at 2026-03-13T13:17:54.008Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/android/ui-cookbook/session-timers/](https://getstream.io/video/docs/android/ui-cookbook/session-timers/).