我遇到了 azure 通信服务远程参与者无法加入的问题...
道歉:复制整个文件以防止混淆
这是我的代码
import React,{createContext, useCallback, useContext, useEffect, useState} from 'react';
import {CallClient, LocalVideoStream} from "@azure/communication-calling";
import { AzureCommunicationUserCredential } from "@azure/communication-common";
import { SessionContext } from './sessionContext';
export const CallingContext = createContext();
const CallingContextProvider = (props) => {
const {sessionID,currentUser,info,groupID} = useContext(SessionContext)
const joinAutomaticallyStorage = window.localStorage.getItem("joinAutomatically")
const [joinAutomatically, setJoinAutomatically] = useState(false);
const [cameraList, setCameraList] = useState([]);
const [micList, setMicList] = useState([]);
const [speakerList, setSpeakerList] = useState([]);
const [currentCamera, setCurrentCamera] = useState('');
const [currentMic, setCurrentMic] = useState('');
const [cameraEnabled, setCameraEnabled] = useState(true);
const [micEnabled, setMicEnabled] = useState(false);
const [loadingDevices, setLoadingDevices] = useState(true);
const [permissionsError, setPermissionsError] = useState(false);
const [callState, setCallState] = useState('');
const [callAgent, setCallAgent] = useState();
const [deviceManager, setDeviceManager] = useState();
const [localVideoStreams, setLocalVideoStreams] = useState([]);
const [remoteParticipants, setRemoteParticipants] = useState([]);
const [call, setCall] = useState();
const toggleVideo = async() => {
if (!cameraEnabled && call) {
const lvs = new LocalVideoStream(currentCamera);
await call.startVideo(lvs);
setCameraEnabled(true);
} else if (cameraEnabled && call) {
try {
await call.stopVideo(call.localVideoStreams[0]);
setCameraEnabled(false);
} catch (error) {
console.log(error);
}
}
};
const toggleMicrophone = async ()=> {
try {
if (micEnabled && call) {
await call.mute();
setMicEnabled(!micEnabled);
} else if (!micEnabled && call) {
await call.unmute();
setMicEnabled(!micEnabled);
} else {
setMicEnabled(!micEnabled);
}
} catch (error) {
console.log(error);
}
};
const joinCall = () => {
if(callAgent){
try {
const call = callAgent.join({groupID},
{
videoOptions: {localVideoStreams: cameraEnabled ? [new LocalVideoStream(currentCamera)]: [],},
audioOptions: {muted: !micEnabled}
}
);
call.on("localVideoStreamsUpdated", localVideoStreamsUpdated);
call.on('remoteParticipantsUpdated', remoteParticipantsUpdated);
setCall(call)
//SAVING TO LOCAL STORAGE CAUSES CRASHING (NEEDS FIXING)
return window.localStorage.setItem("joinAutomatically",joinAutomatically)
} catch (error) {
console.log(error);
return
}
}
return
}
const localVideoStreamsUpdated = useCallback((streams) => {
console.log(streams);
setLocalVideoStreams(streams.added);
},[])
const remoteParticipantsUpdated = useCallback((incomingRemoteParticipants) => {
console.log("incomingRemoteParticipants");
for (const participant of incomingRemoteParticipants.added) {
participant.on("videoStreamsUpdated", (event) => {
console.log("videoStreamsUpdate", event);
});
participant.on("displayNameChanged", () => {
console.log("displayNameChanged",participant);
setRemoteParticipants((remoteParticipants) => {
const index = remoteParticipants.indexOf(participant);
return [
...remoteParticipants.slice(0, index),
participant,
...remoteParticipants.slice(index + 1)
]
});
});
participant.on("participantStateChanged", () => {
switch (participant.state) {
case "Connected":
setRemoteParticipants((remoteParticipants) => [...remoteParticipants,participant]);
break;
case "Disconnected":
setRemoteParticipants((remoteParticipants) => {
const index = remoteParticipants.indexOf(participant);
return remoteParticipants.slice(0, index).concat(remoteParticipants.slice(index + 1));
});
break;
default:
break;
}
});
participant.on("isSpeakingChanged", () => {
console.log("isSpeakingChanged",participant);
setRemoteParticipants((remoteParticipants) => {
const index = remoteParticipants.indexOf(participant);
return [
...remoteParticipants.slice(0, index),
participant,
...remoteParticipants.slice(index + 1)
]
});
});
participant.on("isMutedChanged", () => {
console.log("isMutedChanged",participant);
setRemoteParticipants((remoteParticipants) => {
const index = remoteParticipants.indexOf(participant);
return [
...remoteParticipants.slice(0, index),
participant,
...remoteParticipants.slice(index + 1)
]
});
});
}
},[]);
useEffect(()=>{
if(info.isVideo){
setCameraEnabled(true)
}else{
setCameraEnabled(false)
}
},[info.isVideo])
useEffect(() => {
(async()=>{
let callAgent
let deviceManager;
try {
const tokenCredential = new AzureCommunicationUserCredential(currentUser.token);
const callClient = new CallClient();
callAgent = await callClient.createCallAgent(tokenCredential,{displayName:currentUser.username});
deviceManager = await callClient.getDeviceManager();
const result = await deviceManager.askDevicePermission(true, true);
if(!result.audio && !result.video){
setPermissionsError(true)
return
}
const mics = deviceManager.getMicrophoneList()
const cams = deviceManager.getCameraList()
if(!mics.length || !cams.length){
setPermissionsError(true)
return
}
const speakers = deviceManager.getSpeakerList()
setSpeakerList(speakers)
setMicList(mics);
setCurrentMic(mics[0])
setCameraList(cams);
setCurrentCamera(cams[0])
deviceManager.setMicrophone(mics[0])
setDeviceManager(deviceManager);
setLoadingDevices(false)
setCallAgent(callAgent);
if(joinAutomaticallyStorage === "true"){
const call = callAgent.join({groupID},
{
videoOptions: {localVideoStreams: cameraEnabled ? [new LocalVideoStream(cams[0])]: [],},
audioOptions: {muted: !micEnabled}
}
);
call.on("localVideoStreamsUpdated", localVideoStreamsUpdated);
call.on('remoteParticipantsUpdated', remoteParticipantsUpdated);
setCall(call)
}
} catch {
if (callAgent) {
callAgent.dispose();
}
}
})()
const cleanup=()=>{
if (callAgent) {
callAgent.dispose();
return
}
}
window.addEventListener('beforeunload', cleanup);
return()=>{
window.removeEventListener('beforeunload', cleanup);
cleanup()
}
// eslint-disable-next-line
}, [currentUser.token,currentUser.username,info.isVideo,callAgent,joinAutomaticallyStorage,groupID]);
useEffect(() => {
if(cameraEnabled){
setCurrentCamera(cameraList[0])
}
if(micEnabled){
setCurrentMic(micList[0])
}
}, [micEnabled,cameraEnabled,cameraList,micList]);
useEffect(()=>{
if(!callAgent) return;
callAgent.on('callsUpdated', (e => {
e.added.forEach(addedCall => {
addedCall.on('callStateChanged', () => {setCallState(addedCall.state)});
});
e.removed.forEach(removedCall => {
console.log(removedCall);
});
}));
return()=> {
if (callAgent) {
callAgent.off('callsUpdated',()=>{})
callAgent.dispose();
return
}
}
},[callAgent])
useEffect(()=>{
if(!call) return;
return ()=>{
call.off('callStateChanged', () => {setCallState(call.state)});
call.off("localVideoStreamsUpdated", localVideoStreamsUpdated);
call.off('remoteParticipantsUpdated', remoteParticipantsUpdated);
}
},[call,remoteParticipantsUpdated,localVideoStreamsUpdated])
return (
<CallingContext.Provider value={{
sessionID,cameraList,micList,callAgent,isVideo:info.isVideo,
deviceManager,speakerList,setCurrentCamera,setCurrentMic,cameraEnabled,
setCameraEnabled,micEnabled, setMicEnabled,currentCamera,currentMic,loadingDevices,permissionsError,
joinCall,callState,joinAutomatically, setJoinAutomatically,
username:currentUser.username,
toggleVideo,toggleMicrophone,
localVideoStreams,remoteParticipants
}}>
{props.children}
</CallingContext.Provider>
);
};
export default CallingContextProvider;
本地视频流正常。在 remoteParticipantsUpdated
上根本不触发。我认为是代码的排列方式导致的,但没有得到写入顺序。
这是一个 Context Provider 环绕调用页面并保存重要状态