fix: use onAddTrack instead of onAddStream for remote video

With Unified Plan SDP semantics (which we set in RTCConfiguration),
onAddStream is deprecated and doesn't fire. Remote media tracks
arrive via onAddTrack(RtpReceiver, MediaStream[]) instead.

Changed WebRtcCallSession:
- onRemoteStream callback renamed to onRemoteVideoTrack(VideoTrack)
- onAddTrack now extracts VideoTrack from RtpReceiver.track()
- onAddStream kept as fallback for Plan B compatibility

This was why video never appeared after connecting — the remote
video track was never captured and _remoteVideoTrack stayed null.

https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
Claude
2026-04-02 13:18:57 +00:00
parent ccbaeacbd9
commit 8ee71e94e8
2 changed files with 11 additions and 7 deletions
@@ -38,7 +38,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.webrtc.IceCandidate
import org.webrtc.MediaStream
import org.webrtc.SessionDescription
import org.webrtc.VideoTrack
import java.util.UUID
@@ -274,9 +273,7 @@ class CallController(
callManager.onPeerConnected()
startForegroundService()
},
onRemoteStream = { stream: MediaStream ->
stream.videoTracks?.firstOrNull()?.let { _remoteVideoTrack.value = it }
},
onRemoteVideoTrack = { track -> _remoteVideoTrack.value = track },
onDisconnected = { scope.launch { callManager.hangup() } },
onError = { error -> _errorMessage.value = error },
)
@@ -49,7 +49,7 @@ class WebRtcCallSession(
private val iceServers: List<PeerConnection.IceServer>,
private val onIceCandidate: (IceCandidate) -> Unit,
private val onPeerConnected: () -> Unit,
private val onRemoteStream: (MediaStream) -> Unit,
private val onRemoteVideoTrack: (VideoTrack) -> Unit,
private val onDisconnected: () -> Unit,
private val onError: (String) -> Unit = {},
) {
@@ -123,7 +123,8 @@ class WebRtcCallSession(
override fun onIceGatheringChange(state: PeerConnection.IceGatheringState?) {}
override fun onAddStream(stream: MediaStream?) {
stream?.let { onRemoteStream(it) }
// Fallback for Plan B SDP — Unified Plan uses onAddTrack
stream?.videoTracks?.firstOrNull()?.let { onRemoteVideoTrack(it) }
}
override fun onRemoveStream(stream: MediaStream?) {}
@@ -135,7 +136,13 @@ class WebRtcCallSession(
override fun onAddTrack(
receiver: RtpReceiver?,
streams: Array<out MediaStream>?,
) {}
) {
// Unified Plan: extract video track from receiver
val track = receiver?.track()
if (track is VideoTrack) {
onRemoteVideoTrack(track)
}
}
},
)
}