From 356e7edd58a017ad7be787b79ecc54b26b2b9782 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Wed, 28 Dec 2022 22:50:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A3=B0=E7=BD=91=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E8=87=AA=E7=94=B1=E6=8E=A7=E5=88=B6=E5=AA=92=E4=BD=93=E6=B5=81?= =?UTF-8?q?=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 并优化了自我画面的展示 --- .../src/FloatWindow/Controls.tsx | 43 ++++++++++--------- .../src/FloatWindow/VideoView.tsx | 20 +++++++++ .../src/FloatWindow/Videos.tsx | 10 +---- .../src/FloatWindow/store.ts | 32 ++++++++++++-- .../src/FloatWindow/utils.ts | 15 +++++++ 5 files changed, 87 insertions(+), 33 deletions(-) create mode 100644 server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/utils.ts diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Controls.tsx b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Controls.tsx index 934f74e3..56136f7f 100644 --- a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Controls.tsx +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Controls.tsx @@ -1,45 +1,46 @@ import { IconBtn } from '@capital/component'; -import React, { useState } from 'react'; +import React from 'react'; import { useClient, useMicrophoneAndCameraTracks } from './client'; import { useMeetingStore } from './store'; +import { getClientLocalTrack } from './utils'; export const Controls: React.FC<{ onClose: () => void; }> = React.memo((props) => { const client = useClient(); - const [trackState, setTrackState] = useState({ video: false, audio: false }); const { ready, tracks } = useMicrophoneAndCameraTracks(); + const mediaPerm = useMeetingStore((state) => state.mediaPerm); const mute = async (type: 'audio' | 'video') => { if (type === 'audio') { - if (trackState.audio === true) { - // await tracks[0].setEnabled(false); - await client.unpublish(tracks[0]); + if (mediaPerm.audio === true) { + const track = getClientLocalTrack(client, 'audio'); + if (track) { + await client.unpublish(track); + } } else { - // await tracks[0].setEnabled(true); await client.publish(tracks[0]); } - setTrackState((ps) => { - return { ...ps, audio: !ps.audio }; - }); + + useMeetingStore.getState().setMediaPerm({ audio: !mediaPerm.audio }); } else if (type === 'video') { - if (trackState.video === true) { - // await tracks[1].setEnabled(false); - await client.unpublish(tracks[1]); + if (mediaPerm.video === true) { + const track = getClientLocalTrack(client, 'video'); + if (track) { + await client.unpublish(track); + } } else { - // await tracks[1].setEnabled(true); await client.publish(tracks[1]); } - setTrackState((ps) => { - return { ...ps, video: !ps.video }; - }); + + useMeetingStore.getState().setMediaPerm({ video: !mediaPerm.video }); } }; const leaveChannel = async () => { await client.leave(); client.removeAllListeners(); - useMeetingStore.getState().clearUser(); + useMeetingStore.getState().reset(); // we close the tracks to perform cleanup tracks[0].close(); tracks[1].close(); @@ -49,16 +50,16 @@ export const Controls: React.FC<{ return (
mute('video')} /> mute('audio')} diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/VideoView.tsx b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/VideoView.tsx index fb368b9d..6543e1d7 100644 --- a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/VideoView.tsx +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/VideoView.tsx @@ -2,6 +2,8 @@ import { UserName } from '@capital/component'; import { AgoraVideoPlayer, IAgoraRTCRemoteUser } from 'agora-rtc-react'; import React from 'react'; import styled from 'styled-components'; +import { useClient, useMicrophoneAndCameraTracks } from './client'; +import { useMeetingStore } from './store'; const Root = styled.div` width: 95%; @@ -12,6 +14,7 @@ const Root = styled.div` aspect-ratio: 16/9; justify-self: center; align-self: center; + overflow: hidden; .player { width: 100%; @@ -42,3 +45,20 @@ export const VideoView: React.FC<{ ); }; VideoView.displayName = 'VideoView'; + +export const OwnVideoView: React.FC<{}> = React.memo(() => { + const { ready, tracks } = useMicrophoneAndCameraTracks(); + const client = useClient(); + const mediaPerm = useMeetingStore((state) => state.mediaPerm); + + return ( + + {ready && mediaPerm.video && ( + + )} + + + + ); +}); +OwnVideoView.displayName = 'OwnVideoView'; diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Videos.tsx b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Videos.tsx index 8df06b2f..27f17298 100644 --- a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Videos.tsx +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/Videos.tsx @@ -1,26 +1,20 @@ -import { AgoraVideoPlayer } from 'agora-rtc-react'; import React from 'react'; import styled from 'styled-components'; -import { useMicrophoneAndCameraTracks } from './client'; import { useMeetingStore } from './store'; -import { VideoView } from './VideoView'; +import { OwnVideoView, VideoView } from './VideoView'; const Root = styled.div` height: 70vh; - /* align-self: flex-start; */ display: grid; grid-template-columns: repeat(auto-fit, minmax(440px, 1fr)); `; export const Videos: React.FC = React.memo(() => { const users = useMeetingStore((state) => state.users); - const { ready, tracks } = useMicrophoneAndCameraTracks(); return ( - {/* AgoraVideoPlayer component takes in the video track to render the stream, - you can pass in other props that get passed to the rendered div */} - {ready && } + {users.length > 0 && users.map((user) => { diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/store.ts b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/store.ts index 5b8a279d..5e23194d 100644 --- a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/store.ts +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/store.ts @@ -1,22 +1,34 @@ import type { IAgoraRTCRemoteUser } from 'agora-rtc-react'; import create from 'zustand'; +interface MediaPerm { + video: boolean; + audio: boolean; +} + interface MeetingState { /** * 本次会议用户列表 */ users: IAgoraRTCRemoteUser[]; + /** + * 本地媒体权限 + */ + mediaPerm: MediaPerm; appendUser: (user: IAgoraRTCRemoteUser) => void; removeUser: (user: IAgoraRTCRemoteUser) => void; - clearUser: () => void; /** * 更新用户信息 */ updateUserInfo: (user: IAgoraRTCRemoteUser) => void; + setMediaPerm: (perm: Partial) => void; + + reset: () => void; } export const useMeetingStore = create((set) => ({ users: [], + mediaPerm: { video: false, audio: false }, appendUser: (user: IAgoraRTCRemoteUser) => { set((state) => ({ users: [...state.users, user], @@ -29,9 +41,6 @@ export const useMeetingStore = create((set) => ({ }; }); }, - clearUser: () => { - set({ users: [] }); - }, updateUserInfo: (user: IAgoraRTCRemoteUser) => { set((state) => { const users = [...state.users]; @@ -47,4 +56,19 @@ export const useMeetingStore = create((set) => ({ }; }); }, + setMediaPerm: (perm: Partial) => { + set((state) => ({ + mediaPerm: { + ...state.mediaPerm, + ...perm, + }, + })); + }, + + reset: () => { + set({ + users: [], + mediaPerm: { video: false, audio: false }, + }); + }, })); diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/utils.ts b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/utils.ts new file mode 100644 index 00000000..c98a24f3 --- /dev/null +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/utils.ts @@ -0,0 +1,15 @@ +import type { IAgoraRTCClient, ILocalTrack } from 'agora-rtc-react'; + +/** + * 获取客户端本地轨道 + */ +export function getClientLocalTrack( + client: IAgoraRTCClient, + trackMediaType: 'audio' | 'video' +): ILocalTrack | null { + return ( + client.localTracks.find( + (track) => track.trackMediaType === trackMediaType + ) ?? null + ); +}