Skip to content

Fix: HTTP DELETE (signaling.terminate) is cancelled immediately in WebRTCSession.close() on all platforms #36

Description

@PHOEBEHAUNG

[Bug] close() cancels DELETE request before it executes — resource leak on all platforms

Summary

When WebRTCSession.close() is called, the HTTP DELETE request to release the WHIP/WHEP resource is always cancelled before it can execute. This causes server-side resource leaks because the streaming session is never properly terminated.

Affected Platforms

  • Android (WebRTCSession.android.kt)
  • JVM/Desktop (WebRTCSession.jvm.kt)
  • iOS (WebRTCSession.ios.kt)

Library Version

syncai-lib-kmpwebrtc v2.1.0

Root Cause

In close(), the method calls cleanup(terminate = true). Inside cleanup():

  1. scope.launch { signaling.terminate(resourceUrl) } — launches the HTTP DELETE on the session's CoroutineScope
  2. Immediately after, scope.cancel() is called — cancelling the scope and all its children, including the just-launched DELETE coroutine

The DELETE never reaches the server.

Android (L295–314)

private fun cleanup(terminate: Boolean = false) {
    if (terminate && resourceUrl != null) {
        scope.launch {                          // ← launched on scope
            signaling.terminate(resourceUrl!!)
        }
    }
    // ... peer connection cleanup ...
    scope.cancel()                              // ← immediately cancels scope
}

JVM (L261–280)

private fun cleanup(terminate: Boolean = false) {
    if (terminate && resourceUrl != null) {
        scope.launch {                          // ← launched on scope
            signaling.terminate(resourceUrl!!)
        }
    }
    // ... peer connection cleanup ...
    scope.cancel()                              // ← immediately cancels scope
}

iOS (L281–300)

private fun cleanup(terminate: Boolean = false) {
    if (terminate && resourceUrl != null) {
        scope.launch {                          // ← launched on scope
            signaling.terminate(resourceUrl!!)
        }
    }
    // ... peer connection cleanup ...
    scope.cancel()                              // ← immediately cancels scope
}

Expected Behavior

The HTTP DELETE request should complete successfully before the scope is cancelled, ensuring the server-side WHIP/WHEP resource is released.

Suggested Fix

Use an independent CoroutineScope for the DELETE request so it is not cancelled by scope.cancel():

Android / JVM

private fun cleanup(terminate: Boolean = false) {
    if (terminate && resourceUrl != null) {
        CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
            try {
                signaling.terminate(resourceUrl!!)
            } catch (e: Exception) {
                // log error
            }
        }
    }
    // ... peer connection cleanup ...
    scope.cancel()
}

iOS

private fun cleanup(terminate: Boolean = false) {
    if (terminate && resourceUrl != null) {
        CoroutineScope(SupervisorJob() + Dispatchers.Default).launch {
            try {
                signaling.terminate(resourceUrl!!)
            } catch (e: Exception) {
                // log error
            }
        }
    }
    // ... peer connection cleanup ...
    scope.cancel()
}

Impact

  • Server resource leak: WHIP/WHEP sessions accumulate on the media server and are never cleaned up
  • Port exhaustion: Unreleased sessions may hold server ports indefinitely
  • Affects all callers: Any app using WebRTCSession.close() is affected — there is no workaround at the app level

Steps to Reproduce

  1. Establish a WHIP or WHEP session via WebRTCSession
  2. Call close() on the session
  3. Observe server logs — no DELETE request is received for the resource URL

Additional Context

All three platform implementations (android, jvm, ios) share the identical bug pattern. The fix should be applied consistently across all three.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions