feat: useVoice
This commit is contained in:
@@ -1,76 +1,20 @@
|
||||
import { useEffect } from 'react';
|
||||
import AgoraRTC from "agora-rtc-sdk-ng";
|
||||
import useConfig from '../../../common/hook/useConfig';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateVoiceStatus } from '../../../app/slices/auth.data';
|
||||
import { useLazyGetAgoraTokenQuery } from '../../../app/services/server';
|
||||
// import { useEffect } from 'react';
|
||||
// import { useDispatch } from 'react-redux';
|
||||
import VoiceManagement from './VoiceManagement';
|
||||
import JoinVoice from './JoinVoice';
|
||||
import { useVoice } from '../../../common/component/Voice';
|
||||
|
||||
type Props = {
|
||||
channel: string,
|
||||
context?: "channel" | "dm",
|
||||
id: number,
|
||||
uid: number,
|
||||
voicing?: boolean;
|
||||
}
|
||||
|
||||
const Dashboard = ({ id, voicing, uid, channel }: Props) => {
|
||||
const dispatch = useDispatch();
|
||||
const [generateToken] = useLazyGetAgoraTokenQuery();
|
||||
const Dashboard = ({ context = "channel", id }: Props) => {
|
||||
const { joinVoice, joined, joining, voiceInfo } = useVoice({ id, context });
|
||||
// const dispatch = useDispatch();
|
||||
|
||||
const { agoraConfig } = useConfig("agora");
|
||||
useEffect(() => {
|
||||
console.log("agora config", agoraConfig);
|
||||
const startConnect = async () => {
|
||||
// Create an instance of the Agora Engine
|
||||
const agoraEngine = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
|
||||
|
||||
// Listen for the "user-published" event to retrieve an AgoraRTCRemoteUser object.
|
||||
agoraEngine.on("user-published", async (user, mediaType) => {
|
||||
// Subscribe to the remote user when the SDK triggers the "user-published" event.
|
||||
await agoraEngine.subscribe(user, mediaType);
|
||||
console.log("subscribe success");
|
||||
|
||||
// Subscribe and play the remote audio track.
|
||||
if (mediaType == "audio") {
|
||||
// channelParameters.remoteUid=user.uid;
|
||||
// // Get the RemoteAudioTrack object from the AgoraRTCRemoteUser object.
|
||||
// channelParameters.remoteAudioTrack = user.audioTrack;
|
||||
// Play the remote audio track.
|
||||
user.audioTrack?.play();
|
||||
console.log("Remote user connected: " + user.uid);
|
||||
|
||||
}
|
||||
|
||||
// Listen for the "user-unpublished" event.
|
||||
agoraEngine.on("user-unpublished", user => {
|
||||
console.log(user.uid + "has left the channel");
|
||||
console.log("Remote user has left the channel");
|
||||
});
|
||||
});
|
||||
// Join a channel.
|
||||
console.log("join data ", agoraConfig);
|
||||
const { isError, data } = await generateToken(id);
|
||||
if (!isError && data) {
|
||||
const { channel_name, app_id, agora_token, uid } = data;
|
||||
await agoraEngine.join(app_id, channel_name, agora_token, uid);
|
||||
console.table(data);
|
||||
// Create a local audio track from the microphone audio.
|
||||
const localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
|
||||
// Publish the local audio track in the channel.
|
||||
await agoraEngine.publish(localAudioTrack);
|
||||
console.log("Publish success!");
|
||||
dispatch(updateVoiceStatus(true));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (!voicing && agoraConfig) {
|
||||
startConnect();
|
||||
}
|
||||
}, [voicing, agoraConfig, uid, channel]);
|
||||
|
||||
return voicing ? <VoiceManagement /> : <JoinVoice />;
|
||||
return <div className='absolute -left-full -translate-x-full -top-1 z-50 shadow rounded p-2 bg-white dark:bg-black'>{joined ? <VoiceManagement info={voiceInfo} /> : <JoinVoice join={joinVoice} joining={joining} />}</div>;
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
@@ -1,10 +1,19 @@
|
||||
import React from 'react';
|
||||
import StyledButton from '../../../common/component/styled/Button';
|
||||
|
||||
type Props = {}
|
||||
type Props = {
|
||||
join: () => void,
|
||||
joining: boolean
|
||||
}
|
||||
|
||||
const JoinVoice = (props: Props) => {
|
||||
const JoinVoice = ({ joining, join }: Props) => {
|
||||
if (joining) return <div>
|
||||
Joining
|
||||
</div>;
|
||||
return (
|
||||
<div>JoinVoice</div>
|
||||
<div>
|
||||
<StyledButton className='mini' onClick={join}>Join</StyledButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
import React from 'react';
|
||||
import { VoiceInfo } from '../../../app/slices/voice';
|
||||
import { useAppSelector } from '../../../app/store';
|
||||
import User from '../../../common/component/User';
|
||||
|
||||
type Props = {}
|
||||
type Props = {
|
||||
info: VoiceInfo | null
|
||||
}
|
||||
|
||||
const VoiceManagement = (props: Props) => {
|
||||
const VoiceManagement = ({ info }: Props) => {
|
||||
const userData = useAppSelector(store => store.users.byId);
|
||||
if (!info) return null;
|
||||
const { context, id, members } = info;
|
||||
return (
|
||||
<div>VoiceManagement</div>
|
||||
<div>
|
||||
<ul>
|
||||
{members.map((uid) => {
|
||||
return <li key={uid}>
|
||||
<User uid={uid} interactive={false} />
|
||||
{/* {userData[uid]?.name} */}
|
||||
</li>;
|
||||
})}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// import React from 'react';
|
||||
import Tippy from '@tippyjs/react';
|
||||
// import Tippy from '@tippyjs/react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAppSelector } from '../../../app/store';
|
||||
import IconHeadphone from '../../../assets/icons/headphone.svg';
|
||||
@@ -7,29 +8,24 @@ import Tooltip from '../../../common/component/Tooltip';
|
||||
import Dashboard from './Dashboard';
|
||||
|
||||
type Props = {
|
||||
context?: "channel" | "dm"
|
||||
id: number,
|
||||
channel: string
|
||||
}
|
||||
|
||||
const VoiceChat = ({ channel, id }: Props) => {
|
||||
const { loginUser, voice } = useAppSelector(store => { return { loginUser: store.authData.user, voice: store.authData.voice }; });
|
||||
const VoiceChat = ({ id, context = "channel" }: Props) => {
|
||||
const [dashboardVisible, setDashboardVisible] = useState(false);
|
||||
const { loginUser } = useAppSelector(store => { return { loginUser: store.authData.user }; });
|
||||
const { t } = useTranslation("chat");
|
||||
const toolClass = `relative cursor-pointer`;
|
||||
const toggleDashboard = () => {
|
||||
setDashboardVisible(prev => !prev);
|
||||
};
|
||||
if (!loginUser) return null;
|
||||
return (
|
||||
<Tooltip tip={t("voice")} placement="left">
|
||||
<Tippy
|
||||
placement="left-start"
|
||||
popperOptions={{ strategy: "fixed" }}
|
||||
offset={[0, 164]}
|
||||
interactive
|
||||
trigger="click"
|
||||
content={<Dashboard id={id} uid={loginUser.uid} channel={channel} voicing={voice} />}
|
||||
>
|
||||
<li className={`${toolClass}`}>
|
||||
<IconHeadphone className="fill-gray-500" />
|
||||
</li>
|
||||
</Tippy>
|
||||
<Tooltip disabled={dashboardVisible} tip={t("voice")} placement="left">
|
||||
<li className={`relative`} >
|
||||
<IconHeadphone className="fill-gray-500" role="button" onClick={toggleDashboard} />
|
||||
{dashboardVisible && <Dashboard id={id} context={context} />}
|
||||
</li>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
|
||||
|
||||
|
||||
const useVoice = (uid: number) => {
|
||||
const [engine, setEngine] = useState(window.VoiceEngine);
|
||||
const { voicing } = useAppSelector(store => {
|
||||
|
||||
return {
|
||||
voicing: store.users.byId[uid].voice ?? false
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
voicing,
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export default useVoice;
|
||||
Reference in New Issue
Block a user