Android WebRTC:如何识别远程视频流停止并提示接收端?
当然可以!针对你使用的org.webrtc:google-webrtc:1.0.21217版本,我们可以通过WebRTC的回调和状态监听来精准检测远端视频流是否停止,下面给你两种实用的实现方案和代码示例:
方案一:通过帧接收超时判断(覆盖网络中断/主动停止场景)
WebRTC的VideoTrack会通过VideoSink的onFrame方法推送视频帧,我们可以自定义一个VideoSink实现,记录最后一次收到帧的时间,定时检查是否超过设定阈值(比如3秒),以此判断远端流是否停止。
自定义VideoSink实现
import org.webrtc.VideoFrame import org.webrtc.VideoSink import java.util.concurrent.Executors import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit class RemoteVideoStatusSink(private val onVideoStopped: () -> Unit) : VideoSink { private var lastFrameReceivedTime = System.currentTimeMillis() private val scheduler = Executors.newSingleThreadScheduledExecutor() private var checkTask: ScheduledFuture<*>? = null // 超时阈值,可根据业务需求调整 private val STOP_THRESHOLD_MS = 3000L init { // 启动每秒一次的定时检查任务 checkTask = scheduler.scheduleAtFixedRate({ val currentTime = System.currentTimeMillis() if (currentTime - lastFrameReceivedTime > STOP_THRESHOLD_MS) { // 触发视频停止回调 onVideoStopped.invoke() // 停止检查任务,避免重复触发提示 checkTask?.cancel(true) } }, 0, 1, TimeUnit.SECONDS) } override fun onFrame(frame: VideoFrame?) { frame?.let { // 更新最后收到帧的时间戳 lastFrameReceivedTime = System.currentTimeMillis() // 如果之前触发过停止提示,恢复定时检查 if (checkTask?.isCancelled == true) { restartCheckTask() } } } private fun restartCheckTask() { checkTask = scheduler.scheduleAtFixedRate({ val currentTime = System.currentTimeMillis() if (currentTime - lastFrameReceivedTime > STOP_THRESHOLD_MS) { onVideoStopped.invoke() checkTask?.cancel(true) } }, 0, 1, TimeUnit.SECONDS) } // 释放资源(比如通话结束时调用) fun release() { checkTask?.cancel(true) scheduler.shutdown() } }
在PeerConnection回调中使用
// 实现PeerConnection.Observer的onTrack方法 override fun onTrack(transceiver: RtpTransceiver?) { transceiver?.receiver?.track()?.let { track -> if (track is VideoTrack) { val videoStatusSink = RemoteVideoStatusSink { // 切换到UI线程显示提示 runOnUiThread { Toast.makeText(this@YourActivity, "远端视频已停止", Toast.LENGTH_LONG).show() } } track.addSink(videoStatusSink) // 注意:在通话结束或页面销毁时,记得调用videoStatusSink.release()释放资源 } } }
方案二:监听MediaStreamTrack状态变化(针对主动停止场景)
当远端主动停止视频采集(比如关闭摄像头)时,MediaStreamTrack的状态会变为ENDED,我们可以通过注册状态监听器来捕获这个事件。
代码示例
override fun onTrack(transceiver: RtpTransceiver?) { transceiver?.receiver?.track()?.let { track -> if (track is VideoTrack) { // 注册Track状态观察者 track.registerTrackObserver(object : MediaStreamTrack.TrackObserver { override fun onChanged() { val trackState = track.state() runOnUiThread { when (trackState) { MediaStreamTrack.TrackState.ENDED -> { Toast.makeText(this@YourActivity, "远端视频已停止", Toast.LENGTH_LONG).show() } MediaStreamTrack.TrackState.LIVE -> { // 视频恢复,可隐藏提示消息 } else -> {} } } } }) } } }
方案对比
- 方案一:覆盖场景更全面,既能检测远端主动停止,也能检测网络中断导致的帧传输停止;
- 方案二:更轻量化,仅针对远端主动停止采集的场景,依赖Track状态的正确上报。
实际项目中可以结合两种方案,提升检测的准确性和覆盖范围。
内容的提问来源于stack exchange,提问作者hemi_p




