import React, { useState, useEffect, useRef } from 'react'; import AliRtcEngine, { AliRtcSubscribeState, AliRtcVideoTrack,AliRtcSdkChannelProfile } from 'aliyun-rtc-sdk'; import { ToastContainer, toast } from 'react-toastify'; // 辅助函数 function hex(buffer: ArrayBuffer): string { const hexCodes = []; const view = new DataView(buffer); for (let i = 0; i < view.byteLength; i += 4) { const value = view.getUint32(i); const stringValue = value.toString(16); const padding = '00000000'; const paddedValue = (padding + stringValue).slice(-padding.length); hexCodes.push(paddedValue); } return hexCodes.join(''); } async function generateToken( appId: string, appKey: string, channelId: string, userId: string, timestamp: number ): Promise { const encoder = new TextEncoder(); const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`); const hash = await crypto.subtle.digest('SHA-256', data); return hex(hash); } function showToast(type: 'info' | 'success' | 'error', message: string): void { switch(type) { case 'info': toast.info(message); break; case 'success': toast.success(message); break; case 'error': toast.error(message); break; } } const appId = 'a5842c2a-d94a-43be-81de-1fdb712476e1'; const appKey = 'b71d65f4f84c450f6f058f4ad507bd42'; export const RTCPage = () => { const [channelId, setChannelId] = useState(''); const [userId, setUserId] = useState(''); const [isJoined, setIsJoined] = useState(false); const aliRtcEngine = useRef(null); const remoteVideoElMap = useRef>({}); const remoteVideoContainer = useRef(null); function removeRemoteVideo(userId: string, type: 'camera' | 'screen' = 'camera') { const vid = `${type}_${userId}`; const el = remoteVideoElMap.current[vid]; if (el) { aliRtcEngine.current!.setRemoteViewConfig(null, userId, type === 'camera' ? AliRtcVideoTrack.AliRtcVideoTrackCamera : AliRtcVideoTrack.AliRtcVideoTrackScreen); el.pause(); remoteVideoContainer.current?.removeChild(el); delete remoteVideoElMap.current[vid]; } } function listenEvents() { if (!aliRtcEngine.current) { return; } aliRtcEngine.current.on('remoteUserOnLineNotify', (userId: string, elapsed: number) => { console.log(`用户 ${userId} 加入频道,耗时 ${elapsed} 秒`); showToast('info', `用户 ${userId} 上线`); }); aliRtcEngine.current.on('remoteUserOffLineNotify', (userId, reason) => { console.log(`用户 ${userId} 离开频道,原因码: ${reason}`); showToast('info', `用户 ${userId} 下线`); removeRemoteVideo(userId, 'camera'); removeRemoteVideo(userId, 'screen'); }); aliRtcEngine.current.on('bye', (code) => { console.log(`bye, code=${code}`); showToast('info', `您已离开频道,原因码: ${code}`); }); aliRtcEngine.current.on('videoSubscribeStateChanged', ( userId: string, oldState: AliRtcSubscribeState, newState: AliRtcSubscribeState, interval: number, channelId: string ) => { console.log(`频道 ${channelId} 远端用户 ${userId} 订阅状态由 ${oldState} 变为 ${newState}`); const vid = `camera_${userId}`; if (newState === 3) { const video = document.createElement('video'); video.autoplay = true; video.className = 'w-80 h-45 mr-2 mb-2 bg-black'; remoteVideoElMap.current[vid] = video; remoteVideoContainer.current?.appendChild(video); aliRtcEngine.current!.setRemoteViewConfig(video, userId, AliRtcVideoTrack.AliRtcVideoTrackCamera); } else if (newState === 1) { removeRemoteVideo(userId, 'camera'); } }); aliRtcEngine.current.on('screenShareSubscribeStateChanged', ( userId: string, oldState: AliRtcSubscribeState, newState: AliRtcSubscribeState, interval: number, channelId: string ) => { console.log(`频道 ${channelId} 远端用户 ${userId} 屏幕流的订阅状态由 ${oldState} 变为 ${newState}`); const vid = `screen_${userId}`; if (newState === 3) { const video = document.createElement('video'); video.autoplay = true; video.className = 'w-80 h-45 mr-2 mb-2 bg-black'; remoteVideoElMap.current[vid] = video; remoteVideoContainer.current?.appendChild(video); aliRtcEngine.current!.setRemoteViewConfig(video, userId, AliRtcVideoTrack.AliRtcVideoTrackScreen); } else if (newState === 1) { removeRemoteVideo(userId, 'screen'); } }); } const handleLoginSubmit = async (e: React.FormEvent) => { e.preventDefault(); const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3; if (!channelId || !userId) { showToast('error', '数据不完整'); return; } const engine = AliRtcEngine.getInstance(); aliRtcEngine.current = engine; listenEvents(); try { const token = await generateToken(appId, appKey, channelId, userId, timestamp); aliRtcEngine.current!.setChannelProfile(AliRtcSdkChannelProfile.AliRtcSdkCommunication); await aliRtcEngine.current.joinChannel( { channelId, userId, appId, token, timestamp, }, userId ); showToast('success', '加入频道成功'); setIsJoined(true); aliRtcEngine.current!.setLocalViewConfig('localPreviewer', AliRtcVideoTrack.AliRtcVideoTrackCamera); } catch (error) { console.log('加入频道失败', error); showToast('error', '加入频道失败'); } }; const handleLeaveClick = async () => { Object.keys(remoteVideoElMap.current).forEach(vid => { const arr = vid.split('_'); removeRemoteVideo(arr[1], arr[0] as 'screen' | 'camera'); }); if (aliRtcEngine.current) { await aliRtcEngine.current.stopPreview(); await aliRtcEngine.current.leaveChannel(); aliRtcEngine.current.destroy(); aliRtcEngine.current = null; } setIsJoined(false); showToast('info', '已离开频道'); }; useEffect(() => { AliRtcEngine.setLogLevel(0); }, []); return (

aliyun-rtc-sdk 快速开始

setChannelId(e.target.value)} />
setUserId(e.target.value)} />

本地预览

远端用户

); };