声网官网地址:
https://doc.shengwang.cn/doc/rtc/javascript/basic-features/audio-quick-start
react实现一对多实时对讲如下:
import React, { useState, useEffect, useCallback, useRef } from "react";
import AgoraRTC from "agora-rtc-sdk-ng";
import styles from './index.less';
import { Spin } from 'antd';const Dog = ({ location, dispatch, employeeInfo, loading }) => {const [rtc, setRtc] = useState({localAudioTrack: null,clients: [],clientChannelMap: new Map()});const rtcRef = useRef(rtc); // 使用 useRef 来保持对 rtc 状态的引用useEffect(() => {rtcRef.current = rtc; // 更新 rtcRef 的 current 属性}, [rtc]);const tokens = {// "10086": "007eJxTYKh0eKT1SYHX/se0JS67Gy7Y7d6tLfDPTvJbXkBayLc1FwIVGEwMLFKMjI2TDUwt00wsk1IS0wwtLY2NDE0s0yxTDU2MqueEpgnwMTAserOplpEBAkF8VgZDAwMLMwYGAGpGHmc=",// "10087": "007eJxTYHhmVP9jrrjGtakFxVN9TYVMi6ZVWa1bmXkriG+Bp+Tm+hMKDCYGFilGxsbJBqaWaSaWSSmJaYaWlsZGhiaWaZaphiZG1+eGpgnwMTD05wr8ZGSAQBCflcHQwMDCnIEBAALWHL0="};const options = {appId: "377f57d142f946b9bd93356f728e543c",uid: null,};const startBasicCall = useCallback(async (channel) => {const agoraClient = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });agoraClient.on("user-published", async (user, mediaType) => {await agoraClient.subscribe(user, mediaType);console.log(`Subscribe success to channel ${channel}`);if (mediaType === "audio") {const remoteAudioTrack = user.audioTrack;remoteAudioTrack.play();}});agoraClient.on("user-unpublished", async (user) => {await agoraClient.unsubscribe(user);});const token = tokens[channel] || null;await agoraClient.join(options.appId, channel, token, options.uid);console.log(`Joined channel ${channel}`);return { agoraClient, channel };}, []);const handleDogSelect = async (dogId, sn) => {setBtnLoading(true);if (selectedDogs.includes(dogId)) {await handleLeave(sn); // Leave the channel if the dog is being deselectedconst newSelectedDogs = selectedDogs.filter(id => id !== dogId);setSelectedDogs(newSelectedDogs);if (newSelectedDogs.length === 0 && rtcRef.current.localAudioTrack) {rtcRef.current.localAudioTrack.close();setRtc(prevRtc => ({ ...prevRtc, localAudioTrack: null }));}} else {const { agoraClient, channel } = await startBasicCall(sn); // Join the channelsetRtc(prevRtc => {const newClientChannelMap = new Map(prevRtc.clientChannelMap);newClientChannelMap.set(agoraClient, channel);return { ...prevRtc, clients: [...prevRtc.clients, agoraClient], clientChannelMap: newClientChannelMap };});setSelectedDogs([...selectedDogs, dogId]);// Publish the local audio track if not already publishedif (!rtcRef.current.localAudioTrack) {const localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();setRtc(prevRtc => ({ ...prevRtc, localAudioTrack }));await Promise.all(rtcRef.current.clients.concat(agoraClient).map(async (client) => {await client.publish([localAudioTrack]);console.log(`Publish local audio track to channel ${client.channelName}`);setBtnLoading(false);}));} else {await agoraClient.publish([rtcRef.current.localAudioTrack]);console.log(`Publish existing local audio track to channel ${channel}`);setBtnLoading(false);}}};const handleLeave = async (channel) => {const clientEntry = Array.from(rtcRef.current.clientChannelMap.entries()).find(([client, ch]) => ch === channel);const client = clientEntry ? clientEntry[0] : undefined;if (client) {await client.leave();console.log(`Left channel ${channel}`);client.removeAllListeners();setRtc(prevRtc => {const newClientChannelMap = new Map(prevRtc.clientChannelMap);newClientChannelMap.delete(client);return {...prevRtc,clients: prevRtc.clients.filter(c => c !== client),clientChannelMap: newClientChannelMap};});setBtnLoading(false);}};const [selectedDogs, setSelectedDogs] = useState([]);const [btnLoading, setBtnLoading] = useState(false); // 防止用户多次过快点击,造成声网sdk出问题useEffect(() => {if (selectedDogs.length === 0 && rtcRef.current.localAudioTrack) {rtcRef.current.localAudioTrack.close();setRtc(prevRtc => ({ ...prevRtc, localAudioTrack: null }));}}, [selectedDogs]);useEffect(() => {return () => {// 组件卸载时执行的清理操作if (rtcRef.current.localAudioTrack) {rtcRef.current.localAudioTrack.close();}rtcRef.current.clients.forEach(client => {client.leave();client.removeAllListeners();});};}, []);const dogList = [{ id: 1, name: "按钮1", sn: "10086" },{ id: 2, name: "按钮2", sn: "10087" },{ id: 3, name: "按钮3", sn: "10088" },{ id: 4, name: "按钮4", sn: "10089" },{ id: 5, name: "按钮5", sn: "10090" }];return (<div><Spin tip="加载中..." spinning={btnLoading}><div className={styles.tab01Bottom}><div className={styles.talkContent}>{dogList.map((item) => (<divkey={item.id}className={`${styles.customButton} ${selectedDogs.includes(item.id) ? styles.selected : ''}`}onClick={() => handleDogSelect(item.id, item.sn)}>{item.name}</div>))}</div></div></Spin></div>);
};export default Dog;