Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Added
* Added following meeting events: meetingReconnected/audioInputFailed/videoClientSignalingDropped/contentShareSignalingDropped/appStateChanged/appMemoryLow/contentShareStartRequested/contentShareStarted/contentShareStopped/contentShareFailed/voiceFocusEnabled/voiceFocusDisabled/voiceFocusEnableFailed/voiceFocusDisableFailed/videoCaptureSessionInterruptionBegan/videoCaptureSessionInterruptionEnded
* Added following meeting event attributes: meetingReconnectDurationMs/audioInputErrorMessage/signalingDroppedErrorMessage/appState/batteryLevel/batteryState/contentShareErrorMessage/voiceFocusErrorMessage/lowPowerModeEnabled
* Guard video client stop with a mutex

## [0.25.0] - 2025-06-17

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import com.xodee.client.video.VideoSubscriptionConfigurationInternal
import java.security.InvalidParameterException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

class DefaultVideoClientController(
private val context: Context,
Expand Down Expand Up @@ -64,7 +66,7 @@ class DefaultVideoClientController(
private val cameraCaptureSource: DefaultCameraCaptureSource
private var videoSourceAdapter = VideoSourceAdapter()
private var isUsingInternalCaptureSource = false

private val videoClientStopMutex = Mutex()
init {
videoClientStateController.bindLifecycleHandler(this)

Expand Down Expand Up @@ -100,10 +102,16 @@ class DefaultVideoClientController(
// So it doesn't call it spuriously
videoClientObserver.primaryMeetingPromotionObserver = null

videoClientStateController.stop()
videoClientStopMutex.withLock {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were we able to reproduce? Was there a stack? Can we add a comment here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was reproducible with new webrtc version. Added a comment here to explain the crash

// Race conditions in video client stop functions may lead to crashes at pointer deallocation
// if multiple such threads are called at the same time.
videoClientStateController.stop()

eglCore?.release()
eglCore = null
// We put release eglCore under mutex as a race condition may decrease its reference counter
// below 0 and cause crashes if multiple such calls happen together.
eglCore?.release()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we included this in the mutex scope?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only put videoClientStateController.stop() under mutex, multiple eglCore?.release() may be triggered at the same time, this is another race condition that will trigger a crash for eglCore reference counter below 0. Added a comment.

eglCore = null
}
}
}

Expand Down
Loading