You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Agora IO调用.close()后摄像头灯未关闭问题求助(Next.js医疗应用)

解决Agora IO视频通话后摄像头灯未关闭的问题

核心问题分析

调用close()后摄像头灯仍保持亮起,本质是轨道实例的引用未被彻底清理,尤其是在Next.js/React的组件生命周期中,若轨道对象被留存于状态或未妥善销毁,会导致浏览器无法释放硬件资源,即便user-unpublished事件触发,硬件占用仍未解除。

正确的资源释放流程

无论通过哪种方式创建轨道,都需要严格遵循以下步骤:

  • 若轨道已发布到频道,必须先调用unpublish()取消发布,再执行close()
  • 调用close()后,立即清空所有对该轨道实例的引用
  • 在组件卸载(如通话结束、页面切换)时,强制触发资源清理逻辑

Next.js组件完整示例代码

以下是基于agora-rtc-react的落地实现,确保摄像头资源被彻底释放:

'use client';
import { useEffect, useRef, useState } from 'react';
import { createMicrophoneAndCameraTracks, useClient } from 'agora-rtc-react';

export default function MedicalVideoCall() {
  const client = useClient();
  const [inCall, setInCall] = useState(false);
  // 用useRef存储轨道实例,避免状态更新引发的实例残留
  const trackRef = useRef({ audio: null, video: null });

  // 启动通话逻辑
  const startCall = async () => {
    try {
      const [audioTrack, videoTrack] = await createMicrophoneAndCameraTracks();
      trackRef.current = { audio: audioTrack, video: videoTrack };
      
      // 发布轨道至频道
      await client.publish([audioTrack, videoTrack]);
      setInCall(true);
    } catch (err) {
      console.error('通话启动失败:', err);
    }
  };

  // 结束通话并清理资源
  const endCall = async () => {
    const { audio, video } = trackRef.current;
    try {
      // 先取消发布轨道
      if (audio) await client.unpublish(audio);
      if (video) await client.unpublish(video);
      
      // 关闭轨道并清空引用
      if (audio) {
        await audio.close();
        trackRef.current.audio = null;
      }
      if (video) {
        await video.close();
        trackRef.current.video = null;
      }
      
      setInCall(false);
    } catch (err) {
      console.error('通话结束失败:', err);
    }
  };

  // 组件卸载时强制清理资源
  useEffect(() => {
    return () => {
      if (inCall) endCall();
    };
  }, [inCall]);

  return (
    <div className="call-container">
      <button onClick={inCall ? endCall : startCall}>
        {inCall ? '结束通话' : '发起视频会诊'}
      </button>
      {/* 渲染本地视频流 */}
      {inCall && trackRef.current.video && (
        <video
          autoPlay
          playsInline
          ref={(el) => el && trackRef.current.video.play(el)}
          className="local-video"
        />
      )}
    </div>
  );
}

额外注意事项

  • 不要用useState存储轨道实例:状态更新会触发组件重渲染,极易导致旧轨道实例未被清理,引发资源泄漏
  • 针对原生agora-rtc-sdk-ng调用,流程完全一致:先执行client.unpublish(track),再调用track.close(),最后清空引用
  • 可通过navigator.mediaDevices.enumerateDevices()在关闭后检查设备状态,确认资源是否释放

内容的提问来源于stack exchange,提问作者Lenin Boccardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:52:20