|
"use client" |
|
|
|
import * as React from "react" |
|
import { cn } from "@/lib/utils" |
|
import { ICameraVideoTrack, ILocalVideoTrack, IMicrophoneAudioTrack } from "agora-rtc-sdk-ng" |
|
import { useAppSelector, useAppDispatch } from "@/common/hooks" |
|
import { isVoiceGenderSupported, VideoSourceType } from "@/common/constant" |
|
import { ITextItem, EMessageType, IChatItem } from "@/types" |
|
import { rtcManager, IUserTracks, IRtcUser } from "@/manager" |
|
import { |
|
setRoomConnected, |
|
addChatItem, |
|
setVoiceType, |
|
setOptions, |
|
} from "@/store/reducers/global" |
|
import AgentVoicePresetSelect from "@/components/Agent/VoicePresetSelect" |
|
import AgentView from "@/components/Agent/View" |
|
import MicrophoneBlock from "@/components/Agent/Microphone" |
|
import CameraBlock from "@/components/Agent/Camera" |
|
import VideoBlock from "@/components/Agent/Camera" |
|
|
|
let hasInit: boolean = false |
|
|
|
export default function RTCCard(props: { className?: string }) { |
|
const { className } = props |
|
|
|
const dispatch = useAppDispatch() |
|
const options = useAppSelector((state) => state.global.options) |
|
const voiceType = useAppSelector((state) => state.global.voiceType) |
|
const selectedGraphId = useAppSelector((state) => state.global.graphName) |
|
const { userId, channel } = options |
|
const [videoTrack, setVideoTrack] = React.useState<ICameraVideoTrack>() |
|
const [audioTrack, setAudioTrack] = React.useState<IMicrophoneAudioTrack>() |
|
const [screenTrack, setScreenTrack] = React.useState<ILocalVideoTrack>() |
|
const [remoteuser, setRemoteUser] = React.useState<IRtcUser>() |
|
const [videoSourceType, setVideoSourceType] = React.useState<VideoSourceType>(VideoSourceType.CAMERA) |
|
|
|
React.useEffect(() => { |
|
if (!options.channel) { |
|
return |
|
} |
|
if (hasInit) { |
|
return |
|
} |
|
|
|
init() |
|
|
|
return () => { |
|
if (hasInit) { |
|
destory() |
|
} |
|
} |
|
}, [options.channel]) |
|
|
|
const init = async () => { |
|
console.log("[rtc] init") |
|
rtcManager.on("localTracksChanged", onLocalTracksChanged) |
|
rtcManager.on("textChanged", onTextChanged) |
|
rtcManager.on("remoteUserChanged", onRemoteUserChanged) |
|
await rtcManager.createCameraTracks() |
|
await rtcManager.createMicrophoneTracks() |
|
await rtcManager.join({ |
|
channel, |
|
userId, |
|
}) |
|
dispatch( |
|
setOptions({ |
|
...options, |
|
appId: rtcManager.appId ?? "", |
|
token: rtcManager.token ?? "", |
|
}), |
|
) |
|
await rtcManager.publish() |
|
dispatch(setRoomConnected(true)) |
|
hasInit = true |
|
} |
|
|
|
const destory = async () => { |
|
console.log("[rtc] destory") |
|
rtcManager.off("textChanged", onTextChanged) |
|
rtcManager.off("localTracksChanged", onLocalTracksChanged) |
|
rtcManager.off("remoteUserChanged", onRemoteUserChanged) |
|
await rtcManager.destroy() |
|
dispatch(setRoomConnected(false)) |
|
hasInit = false |
|
} |
|
|
|
const onRemoteUserChanged = (user: IRtcUser) => { |
|
console.log("[rtc] onRemoteUserChanged", user) |
|
setRemoteUser(user) |
|
} |
|
|
|
const onLocalTracksChanged = (tracks: IUserTracks) => { |
|
console.log("[rtc] onLocalTracksChanged", tracks) |
|
const { videoTrack, audioTrack, screenTrack } = tracks |
|
setVideoTrack(videoTrack) |
|
setScreenTrack(screenTrack) |
|
if (audioTrack) { |
|
setAudioTrack(audioTrack) |
|
} |
|
} |
|
|
|
const onTextChanged = (text: IChatItem) => { |
|
console.log("[rtc] onTextChanged", text) |
|
dispatch( |
|
addChatItem(text), |
|
) |
|
} |
|
|
|
const onVoiceChange = (value: any) => { |
|
dispatch(setVoiceType(value)) |
|
} |
|
|
|
const onVideoSourceTypeChange = async (value: VideoSourceType) => { |
|
await rtcManager.switchVideoSource(value) |
|
setVideoSourceType(value) |
|
} |
|
|
|
return ( |
|
<> |
|
<div className={cn("flex-shrink-0", "overflow-y-auto", className)}> |
|
<div className="flex h-full w-full flex-col"> |
|
{/* -- Agent */} |
|
<div className="w-full"> |
|
<div className="flex w-full items-center justify-between p-2"> |
|
<h2 className="mb-2 text-xl font-semibold">Audio & Video</h2> |
|
{ |
|
isVoiceGenderSupported(selectedGraphId) ? |
|
<AgentVoicePresetSelect /> : |
|
null} |
|
</div> |
|
<AgentView audioTrack={remoteuser?.audioTrack} /> |
|
</div> |
|
|
|
{/* -- You */} |
|
<div className="w-full space-y-2 px-2"> |
|
<MicrophoneBlock audioTrack={audioTrack} /> |
|
<VideoBlock |
|
cameraTrack={videoTrack} |
|
screenTrack={screenTrack} |
|
videoSourceType={videoSourceType} |
|
onVideoSourceChange={onVideoSourceTypeChange} |
|
/> |
|
</div> |
|
</div> |
|
</div> |
|
</> |
|
) |
|
} |
|
|