refactor: calling
This commit is contained in:
+12
-3
@@ -38,6 +38,7 @@ export type VoiceInfo = {
|
||||
interface State {
|
||||
callingFrom: number,
|
||||
callingTo: number,
|
||||
calling: boolean,
|
||||
voicing: VoicingInfo | null,
|
||||
voicingMembers: VoicingMembers,
|
||||
list: VoiceInfo[]
|
||||
@@ -48,6 +49,7 @@ interface State {
|
||||
// members: []
|
||||
// };
|
||||
const initialState: State = {
|
||||
calling: false,
|
||||
callingFrom: 0,
|
||||
callingTo: 0,
|
||||
voicing: null,
|
||||
@@ -64,10 +66,16 @@ const voiceSlice = createSlice({
|
||||
name: "voice",
|
||||
initialState,
|
||||
reducers: {
|
||||
updateCalling(state, { payload }: PayloadAction<{ from: number, to?: number }>) {
|
||||
const { from, to = 0 } = payload;
|
||||
updateCallInfo(state, { payload }: PayloadAction<{ from: number, to?: number, calling?: boolean }>) {
|
||||
const { from, to = 0, calling } = payload;
|
||||
state.callingFrom = from;
|
||||
state.callingTo = to;
|
||||
if (typeof calling === "boolean") {
|
||||
state.calling = calling;
|
||||
}
|
||||
},
|
||||
updateCalling(state, { payload }: PayloadAction<boolean>) {
|
||||
state.calling = payload;
|
||||
},
|
||||
updateVoicingInfo(state, { payload }: PayloadAction<VoicingInfo | null>) {
|
||||
if (payload) {
|
||||
@@ -182,6 +190,7 @@ const voiceSlice = createSlice({
|
||||
});
|
||||
}
|
||||
state.voicing = null;
|
||||
state.calling = false;
|
||||
state.voicingMembers = {
|
||||
ids: [],
|
||||
byId: {}
|
||||
@@ -190,5 +199,5 @@ const voiceSlice = createSlice({
|
||||
}
|
||||
});
|
||||
|
||||
export const { updateCalling, updatePin, updateConnectionState, addVoiceMember, removeVoiceMember, upsertVoiceList, updateVoicingInfo, updateVoicingNetworkQuality, updateVoicingMember } = voiceSlice.actions;
|
||||
export const { updateCalling, updateCallInfo, updatePin, updateConnectionState, addVoiceMember, removeVoiceMember, upsertVoiceList, updateVoicingInfo, updateVoicingNetworkQuality, updateVoicingMember } = voiceSlice.actions;
|
||||
export default voiceSlice.reducer;
|
||||
|
||||
@@ -26,9 +26,10 @@ const DMCalling = ({ from, to = 0 }: Props) => {
|
||||
const dispatch = useDispatch();
|
||||
const { leave, joinVoice, joining } = useVoice({ id: to, context: "dm" });
|
||||
const containerRef = useRef(null);
|
||||
const { voicingInfo, voicingMembers, fromUser, toUser, loginUser } = useAppSelector(store => {
|
||||
const { calling, voicingMembers, fromUser, toUser, loginUser } = useAppSelector(store => {
|
||||
return {
|
||||
voicingInfo: store.voice.voicing ?? {},
|
||||
calling: store.voice.calling,
|
||||
// voicingInfo: store.voice.voicing ?? {},
|
||||
voicingMembers: store.voice.voicingMembers,
|
||||
fromUser: store.users.byId[from],
|
||||
toUser: store.users.byId[to],
|
||||
@@ -48,7 +49,8 @@ const DMCalling = ({ from, to = 0 }: Props) => {
|
||||
if (sendByMe || voicingMembers.ids.length == 2) {
|
||||
leave();
|
||||
}
|
||||
dispatch(updateCalling({ from: 0, to: 0 }));
|
||||
// 拒绝
|
||||
dispatch(updateCalling(false));
|
||||
};
|
||||
const handleAnswer = () => {
|
||||
joinVoice();
|
||||
@@ -58,7 +60,7 @@ const DMCalling = ({ from, to = 0 }: Props) => {
|
||||
const connected = voicingMembers.ids.length == 2;
|
||||
console.log("dm calling", !fromUser, !toUser, connected);
|
||||
const atChatPath = sendByMe ? pathname == `/chat/dm/${to}` : pathname == `/chat/dm/${from}`;
|
||||
if (!fromUser || !toUser || connected || atChatPath) return null;
|
||||
if (!fromUser || !toUser || connected || atChatPath || !calling) return null;
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="fixed top-0 left-0 w-full h-screen z-[999] pointer-events-none flex items-center justify-end pr-10">
|
||||
|
||||
@@ -2,7 +2,7 @@ import AgoraRTC from 'agora-rtc-sdk-ng';
|
||||
import { memo, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useGetAgoraChannelsQuery, useGetAgoraStatusQuery, useLazyGetAgoraUsersByChannelQuery } from '../../app/services/server';
|
||||
import { addVoiceMember, removeVoiceMember, updateCalling, updateConnectionState, updateVoicingMember, updateVoicingNetworkQuality } from '../../app/slices/voice';
|
||||
import { addVoiceMember, removeVoiceMember, updateCallInfo, updateConnectionState, updateVoicingMember, updateVoicingNetworkQuality } from '../../app/slices/voice';
|
||||
import { useAppSelector } from '../../app/store';
|
||||
import { playAgoraVideo } from '../../utils';
|
||||
import useVoice from './useVoice';
|
||||
@@ -86,7 +86,7 @@ const Voice = () => {
|
||||
window.VIDEO_TRACK_MAP[+user.uid] = null;
|
||||
if (voicingInfo && voicingInfo.context == "dm") {
|
||||
// 有人离开,就断开
|
||||
dispatch(updateCalling({ from: 0 }));
|
||||
dispatch(updateCallInfo({ from: 0 }));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -161,6 +161,7 @@ const Voice = () => {
|
||||
|
||||
};
|
||||
}, [voicingInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
// 有人呼叫我
|
||||
const callMeList = voiceList.filter(item => item.context == "dm" && item.id == loginUid);
|
||||
@@ -168,14 +169,18 @@ const Voice = () => {
|
||||
const [firstCall] = callMeList;
|
||||
const { memberCount, channelName, id } = firstCall;
|
||||
if (memberCount == 1) {
|
||||
// 呼叫的人在频道里
|
||||
getUsersByChannel(channelName).then(resp => {
|
||||
const [uid] = resp.data ?? [];
|
||||
if (uid) {
|
||||
dispatch(updateCalling({ from: uid, to: id }));
|
||||
dispatch(updateCallInfo({ from: uid, to: id }));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// dispatch(updateCallInfo({ from: 0, to: 0, calling: false }));
|
||||
// }
|
||||
}, [voiceList, loginUid]);
|
||||
// return <DMCalling uid={1} sendByMe={calling !== loginUid} />;
|
||||
if (from !== 0) return <DMCalling from={from} to={to} />;
|
||||
|
||||
@@ -52,7 +52,11 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
|
||||
// Publish the local audio track in the channel.
|
||||
await window.VOICE_CLIENT.publish(localAudioTrack);
|
||||
// play the join audio
|
||||
audioJoin.play();
|
||||
try {
|
||||
await audioJoin.play();
|
||||
} catch (error) {
|
||||
console.warn("play join sound failed!", error);
|
||||
}
|
||||
console.log("Publish success!,joined the channel");
|
||||
dispatch(updateVoicingInfo({
|
||||
deafen: false,
|
||||
|
||||
@@ -30,6 +30,7 @@ import { useRenewMutation } from "@/app/services/auth";
|
||||
import { getLocalAuthData } from "@/utils";
|
||||
import { removeUserSession } from "@/app/slices/message.user";
|
||||
import { clearChannelMessage, removeChannelSession } from "@/app/slices/message.channel";
|
||||
import { updateCallInfo } from "@/app/slices/voice";
|
||||
|
||||
const getQueryString = (params: { [key: string]: string }) => {
|
||||
const sp = new URLSearchParams();
|
||||
@@ -151,6 +152,11 @@ export default function useStreaming() {
|
||||
dispatch(clearChannelMessage(gid));
|
||||
break;
|
||||
}
|
||||
case "user_calling": {
|
||||
const { target, uid } = data;
|
||||
dispatch(updateCallInfo({ from: uid, to: target, calling: true }));
|
||||
break;
|
||||
}
|
||||
case "pinned_chats": {
|
||||
const { chats } = data;
|
||||
dispatch(upsertPinChats({ pins: chats, override: true }));
|
||||
|
||||
@@ -13,7 +13,7 @@ import IconMic from '@/assets/icons/mic.on.svg';
|
||||
import IconCamera from '@/assets/icons/camera.svg';
|
||||
import IconCameraOff from '@/assets/icons/camera.off.svg';
|
||||
import IconScreen from '@/assets/icons/share.screen.svg';
|
||||
import { VoicingInfo, updateCalling } from "@/app/slices/voice";
|
||||
import { VoicingInfo, updateCallInfo } from "@/app/slices/voice";
|
||||
import { useVoice } from "@/components/Voice";
|
||||
import { playAgoraVideo } from "@/utils";
|
||||
import Avatar from "@/components/Avatar";
|
||||
@@ -32,13 +32,13 @@ type BlockProps = {
|
||||
to: VoicingMember
|
||||
}
|
||||
const VoicingBlocks = ({ sendByMe, connected, from, to }: BlockProps) => {
|
||||
|
||||
const blocks = [from, to].map(({ id, speaking, name, avatar, video }, idx) => {
|
||||
const showWaiting = idx == 1 && !connected && sendByMe;
|
||||
const showWaiting = idx == 1 && !connected && !sendByMe;
|
||||
const showToWaiting = idx == 1 && !connected && sendByMe;
|
||||
return <div key={id} className={clsx("relative flex-center", video ? "w-80 h-60 overflow-hidden rounded" : "")}>
|
||||
<div className={clsx("w-20 h-20 flex shrink-0 relative transition-opacity", showWaiting && "animate-pulse")}>
|
||||
<div className={clsx("w-20 h-20 flex shrink-0 relative transition-opacity", showToWaiting && "animate-pulse", showWaiting && "opacity-40")}>
|
||||
{speaking && <div className={clsx("z-10 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0 rounded-full bg-green-500 animate-speaking", "w-[86px] h-[86px]")}></div>}
|
||||
{showWaiting && <div className={clsx("z-10 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gray-400", "w-[88px] h-[88px]")}></div>}
|
||||
{showToWaiting && <div className={clsx("z-10 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gray-400", "w-[88px] h-[88px]")}></div>}
|
||||
<Avatar
|
||||
width={80}
|
||||
height={80}
|
||||
@@ -88,7 +88,7 @@ const DMVoice = ({ uid }: Props) => {
|
||||
if (sendByMe || voicingMembers.ids.length == 2) {
|
||||
leave();
|
||||
}
|
||||
dispatch(updateCalling({ from: 0, to: 0 }));
|
||||
dispatch(updateCallInfo({ from: 0, to: 0 }));
|
||||
};
|
||||
const handleAnswer = () => {
|
||||
joinVoice();
|
||||
@@ -117,11 +117,11 @@ const DMVoice = ({ uid }: Props) => {
|
||||
}} />
|
||||
</div>
|
||||
<div className={clsx("flex gap-3", connected ? "h-full items-end" : "")}>
|
||||
<Tooltip tip={"Disconnect"} placement="top">
|
||||
{(sendByMe || connected) && <Tooltip tip={"Disconnect"} placement="top">
|
||||
<button onClick={handleCancel} className='flex-center bg-red-600 hover:bg-red-700 py-2 px-3 rounded-lg'>
|
||||
<IconCallOff className="w-6 h-6" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Tooltip>}
|
||||
{!sendByMe && !connected &&
|
||||
<Tooltip tip={"Answer"} placement="top">
|
||||
<button disabled={joining} onClick={handleAnswer} className='flex-center bg-green-600 hover:bg-green-700 py-2 px-3 rounded-lg'>
|
||||
|
||||
@@ -10,7 +10,7 @@ import Tooltip from '../../../components/Tooltip';
|
||||
import { useVoice } from '../../../components/Voice';
|
||||
import { useGetAgoraStatusQuery } from '../../../app/services/server';
|
||||
import { ChatContext } from '../../../types/common';
|
||||
import { updateCalling } from '../../../app/slices/voice';
|
||||
import { updateCallInfo } from '../../../app/slices/voice';
|
||||
|
||||
type Props = {
|
||||
context?: ChatContext
|
||||
@@ -50,7 +50,7 @@ const VoiceChat = ({ id, context = "channel" }: Props) => {
|
||||
dispatch(context == "channel" ? updateChannelVisibleAside(data) : updateDMVisibleAside(data));
|
||||
// 实时显示calling box
|
||||
if (!joinedAtThisContext && context == "dm") {
|
||||
dispatch(updateCalling({ from: loginUser?.uid ?? 0, to: id }));
|
||||
dispatch(updateCallInfo({ from: loginUser?.uid ?? 0, to: id, calling: true }));
|
||||
}
|
||||
};
|
||||
if (!loginUser || !enabled) return null;
|
||||
|
||||
+7
-1
@@ -211,6 +211,11 @@ interface GroupClearEvent {
|
||||
type: "group_message_cleared";
|
||||
gid: number;
|
||||
}
|
||||
interface UserCallEvent {
|
||||
type: "user_calling";
|
||||
target: number;
|
||||
uid: number
|
||||
}
|
||||
|
||||
export type ServerEvent =
|
||||
| ReadyEvent
|
||||
@@ -231,4 +236,5 @@ export type ServerEvent =
|
||||
| PinnedMessageUpdatedEvent
|
||||
| HeartbeatEvent
|
||||
| GroupClearEvent
|
||||
| PinnedChatsEvent;
|
||||
| PinnedChatsEvent
|
||||
| UserCallEvent;
|
||||
|
||||
Reference in New Issue
Block a user