Skip to content

Integrate Client Error Event Reporting#1686

Draft
rahul-lohra wants to merge 14 commits into
developfrom
feature/rahullohra/call-event-reporting
Draft

Integrate Client Error Event Reporting#1686
rahul-lohra wants to merge 14 commits into
developfrom
feature/rahullohra/call-event-reporting

Conversation

@rahul-lohra
Copy link
Copy Markdown
Contributor

@rahul-lohra rahul-lohra commented May 21, 2026

Goal

Integrate Client Error Event Reporting

Implementation

Core changes

API Layer Classes

Endpoint

    @POST("/video/call_client_event")
    suspend fun reportClientCallEvent(
        @Body reportClientEventRequest: io.getstream.android.video.generated.models.ReportClientEventRequest
    ): io.getstream.android.video.generated.models.ReportClientEventResponse

Request Body

data class ReportClientEventRequest (
    @Json(name = "events")
    val events: List<ClientEvent> = emptyList()
)

data class ClientEvent (
    callSessionId,
    elapsedTime,
    eventSessionId,
    eventType,
    iceState,
    id, //call_id
    outcome, //success or fail
    peerConnection, // publisher or subscriber
    previouslyConnectedTimestamp,    
    retryCountAttempt,
    retryFailureCode,
    retryFailureReason,
    sdkVersion,
    sfuId,
    stage, //initial or completed
    timestamp,
    type, // call_type
    userAgent,
    userId,
    userSessionId// Get it from CallJoinResponse.call.currentSessionId
    val wasPreviouslyConnected // whether publisher or subscriber was previously connected
)

CallLeaveReason

CallLeaveReason is introduced to tracked specifically why the call is left and send its analytics
which is initially spilt into

  • UserAction
  • Backend
  • RetryExhausted
  • SdkDriven
  • Custom
internal sealed interface CallLeaveReason {
    val message: String?
    val metadata: Map<String, String>

    /** The local user explicitly chose to leave. */
    data class UserAction(UserActionCause...) : CallLeaveReason

    /** The backend ended or rejected the call (CallEndedEvent, SFU termination, etc.). */
    data class Backend(backendCause, backendCode...) : CallLeaveReason

    /** All reconnect attempts were exhausted after a network or SFU failure. */
    data class RetryExhausted( retryCount ,val failureCode....) : CallLeaveReason

    /** A platform/system event (task removal, hold, wearable, interceptor, etc.) caused the leave. */
    data class SdkDriven(cause: SdkCause ..) : CallLeaveReason

    /** SDK consumer supplied an arbitrary reason. */
    data class Custom(..) : CallLeaveReason
}

internal enum class SdkCause {
    TASK_REMOVED, //App was swiped from the recents screen.
    CALL_ON_HOLD, //Telecom system put the call on hold for another call. 
    CLIENT_CLEANUP, //SDK-level cleanup (e.g. logout, StreamVideo instance teardown).
    RING_TIMEOUT, //Outgoing call auto-cancel timeout elapsed with no answer.
    ACCEPTED_ON_OTHER_DEVICE,
    LOCAL_CALL_MISSED_EVENT,
    REJECTED_BY_ALL,
    END_CALL,
}

internal enum class UserActionCause {
    WEARABLE_REJECTED, //User rejected the call from a paired wearable device. 

    /** A [io.getstream.video.android.core.CallJoinInterceptor] aborted the join sequence. */
    CALL_JOIN_ABORT,
    REJECTED_BY_SELF,
    LEAVE_FROM_NOTIFICATION,
}

internal enum class BackendCause {
    LEAVE_TIMEOUT_AFTER_DISCONNECT,
    CALL_ENDED_EVENT,
    CALL_ENDED_SFU_EVENT,
}

Major Internal Change

We introduced a new internal api to include CallLeaveReason in Call Class

    // new internal api
    internal fun leave(reason: CallLeaveReason) {
        internalLeave(reason)
    }

    fun leave(reason: String = "user") {
        internalLeave(CallLeaveReason.Custom(reason))
    }
    
    // Just replaced the argument
    private fun internalLeave(reason: CallLeaveReason) = atomicLeave {
          // existing implementation
     }

Telemetry Logic

ClientEventReporter Overview

Responsibilities

Area Description
Coordinator Join Telemetry Tracks coordinator join initiated/completed lifecycle
WS Join Telemetry Tracks SFU WebSocket join lifecycle
PeerConnection Telemetry Tracks ICE connectivity state transitions
Retry Correlation Correlates reconnect/retry attempts across stages
Telemetry Delivery Supports both in-place and batched event delivery
Abort Handling Aborts and finalizes unfinished telemetry sessions

Core State

Property Purpose
inFlightSessions Active telemetry sessions keyed by event_session_id
joinStageAttemptIdMap Stable attempt id per call used to correlate reconnect/retry flows
callSessionIdMap Stores backend-generated call_session_id per call
batchEvents Pending telemetry events accumulated during batch mode
activePcSessionIds Active PeerConnection telemetry session per PC role
pcEverConnected Tracks whether a PC role has previously reached CONNECTED

Main Reporting APIs

Function Purpose
reportCoordinatorJoinInitiated Starts coordinator join telemetry session
reportCoordinatorJoinCompleted Completes coordinator join telemetry session
reportWsJoinInitiated Starts WS join telemetry session
reportWsJoinCompleted Completes WS join telemetry session
onPeerConnectionIceStateChanged Drives ICE connectivity telemetry state machine
completePeerConnectionSession Finalizes PeerConnection telemetry session
abortAllInFlight Aborts all unfinished telemetry sessions
sendAllPendingEvents Flushes batched telemetry events

Delivery Strategies

Strategy Behavior
IN_PLACE Events are uploaded immediately
BATCH Events are accumulated locally and flushed later

PeerConnection Telemetry Flow

ICE State Behavior
CHECKING Starts a new PeerConnection telemetry session
CONNECTED Completes session with success
FAILED Completes session with failure
ICE Restart Previous session is aborted and replaced with a new one

Internal Design Notes

Topic Details
Session Identity event_session_id uniquely identifies a telemetry session
PC Role Tracking Telemetry is tracked independently per PeerConnection role
Retry Correlation Retry metadata propagates across reconnect stages
Lifecycle Model All stages emit INITIATED → COMPLETED events
Failure Handling Failures include retry count, failure reason, and failure code

🎨 UI Changes

None

Testing

TODO

@rahul-lohra rahul-lohra self-assigned this May 21, 2026
@rahul-lohra rahul-lohra added the pr:internal Internal or infra-only changes label May 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled (or ignored for dependabot PRs).

🎉 Great job! This PR is ready for review.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 12.05 MB 12.08 MB 0.03 MB 🟢
stream-video-android-ui-xml 5.68 MB 5.68 MB 0.00 MB 🟢
stream-video-android-ui-compose 6.28 MB 6.27 MB -0.02 MB 🚀

@rahul-lohra rahul-lohra changed the title Integrate Client Error Event Reporting [AND-1176] Integrate Client Error Event Reporting May 21, 2026
@rahul-lohra rahul-lohra changed the title [AND-1176] Integrate Client Error Event Reporting Integrate Client Error Event Reporting May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:internal Internal or infra-only changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant