React集成Agora语音通话:接收方无法发送音频的问题排查求助
React集成Agora语音通话:接收方无法发送音频的问题排查求助
大家好,我现在在做一个React项目,用Agora实现语音通话功能,自己封装了useVoiceCall这个自定义Hook来管理通话逻辑。现在遇到一个头疼的问题:发起通话的用户麦克风正常,能正常发送音频;但接电话的用户虽然麦克风是激活且未静音状态,却没法把音频发回去。
问题细节
- 两边都成功加入了同一个频道,也能正常听到对方的声音(
audioTrack.play()是正常工作的); - 接收方的麦克风权限已获取,
localTrack存在且isMuted状态为false; - 就是接收方的音频完全传不过去,发起方听不到接收方的声音。
自定义Hook useVoiceCall 代码
import { useState, useCallback, useRef } from "react"; import { AgoraAPP_ID } from "../../constants/data"; import { createAgoraClient, createMicrophoneTrack } from "../utils/rtcUtils"; import api from "../api"; const useVoiceCall = (currentUserId, conversationId) => { const [client, setClient] = useState(null); const [localTrack, setLocalTrack] = useState(null); const [remoteUsers, setRemoteUsers] = useState([]); const remoteUsersRef = useRef({}); const [remoteUid, setRemoteUid] = useState(""); const [isMuted, setIsMuted] = useState(false); const [isCallActive, setIsCallActive] = useState(false); const [incomingCall, setIncomingCall] = useState(false); const [callInfo, setCallInfo] = useState(null); const handleUserPublished = useCallback( async (clientInstance, user, mediaType) => { try { console.log("User published:", user.uid, "Type:", mediaType); await clientInstance.subscribe(user, mediaType); if (mediaType === "audio") { user.audioTrack?.play(); } const uid = user.uid; const updatedUsers = { ...remoteUsersRef.current, [uid]: user }; remoteUsersRef.current = updatedUsers; setRemoteUsers(Object.values(updatedUsers)); setRemoteUid(uid); console.log("uid pub", uid); } catch (error) { console.error("Subscription failed:", error); } }, [] ); const handleUserUnpublished = useCallback((user) => { const uid = user.uid; console.log("uid un pub", uid); delete remoteUsersRef.current[uid]; setRemoteUsers(Object.values(remoteUsersRef.current)); }, []); const createClient = useCallback(() => { const agoraClient = createAgoraClient(); agoraClient.on("user-published", (user, mediaType) => handleUserPublished(agoraClient, user, mediaType) ); agoraClient.on("user-unpublished", handleUserUnpublished); setClient(agoraClient); return agoraClient; }, [handleUserPublished, handleUserUnpublished]); const joinVoiceChannel = useCallback( async ({ token, channel, uid }) => { const agoraClient = createClient(); await agoraClient.join(AgoraAPP_ID, channel, token, uid); console.log("test Join"); const micTrack = await createMicrophoneTrack(); await micTrack.setEnabled(true); await agoraClient.publish([micTrack]); setLocalTrack(micTrack); setIsCallActive(true); }, [createClient] ); const initiateCall = useCallback( async (receiverId) => { const channelName = `private-call.${currentUserId}`; try { const { data } = await api.post("/user/chat/get-call-token", { receiver_id: receiverId, channel_name: channelName, uid: currentUserId, call_type: "voice", conversation_id: conversationId, }); if (data?.data) { await joinVoiceChannel({ token: data.data.token, channel: data.data.channel, uid: data.data.uid, }); setCallInfo(data.data); } } catch (error) { console.error("Error initiating call:", error); } }, [currentUserId, conversationId, joinVoiceChannel] ); const acceptCall = useCallback(async () => { if (!incomingCall) return; const { token, channelName } = callInfo; setIncomingCall(false); await joinVoiceChannel({ token, channel: channelName, uid: currentUserId }); }, [incomingCall, joinVoiceChannel, currentUserId, callInfo]); const rejectCall = useCallback(() => { setIncomingCall(false); setCallInfo(null); }, []); const toggleMute = useCallback(async () => { if (!localTrack) return; await localTrack.setEnabled(isMuted); setIsMuted((prev) => !prev); }, [localTrack, isMuted]); const leaveCall = useCallback(async () => { if (localTrack) { localTrack.stop(); localTrack.close(); } if (client) { await client.leave(); } if (callInfo) { try { await api.post("/user/chat/end-call", { channel_name: `private-call.${currentUserId}`, conversation_id: callInfo.conversation_id, }); } catch (error) { console.error("Failed to notify backend about ending call:", error); } } setClient(null); setLocalTrack(null); setRemoteUsers([]); remoteUsersRef.current = {}; setIsMuted(false); setIsCallActive(false); setRemoteUid(""); setCallInfo(null); }, [client, localTrack, currentUserId, callInfo]); return { initiateCall, acceptCall, rejectCall, leaveCall, toggleMute, isMuted, isCallActive, remoteUsers, incomingCall, setIncomingCall, callInfo, setCallInfo, }; }; export default useVoiceCall;
我的排查思路
- 检查了
joinVoiceChannel方法,发起方和接收方的逻辑都是创建client、加入频道、创建麦克风轨道然后publish,看起来是一致的; - 确认了接收方的
localTrack存在,麦克风权限已获取,isMuted为false; - 日志里能看到双方成功join频道,发起方的
user-published事件能被接收方捕获,但接收方的user-published事件好像没被发起方接收到?
有没有哪位大佬遇到过类似的问题?或者能帮我看看代码里有没有哪里遗漏了?比如Agora客户端的配置、publish的时机、或者uid的处理有没有问题?
内容来源于stack exchange
相关产品推荐
相关产品推荐

