From 98af14969a7ff9f826e1bf015b5d88688eb81576 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Fri, 6 Jan 2023 00:04:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8C=82=E6=96=AD?= =?UTF-8?q?=E9=80=9A=E8=AF=9D=E5=90=8E=E4=BB=8D=E7=84=B6=E4=BC=9A=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=AD=A3=E5=9C=A8=E4=BD=BF=E7=94=A8=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4/=E9=BA=A6=E5=85=8B=E9=A3=8E=E5=B0=8F=E7=BA=A2?= =?UTF-8?q?=E7=82=B9=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/web/src/components/IconBtn.tsx | 3 +- .../src/FloatWindow/Controls.tsx | 64 +++++++++++-------- .../src/FloatWindow/VideoView.tsx | 14 ++-- .../src/FloatWindow/client.ts | 9 +-- .../src/FloatWindow/utils.ts | 17 ++++- 5 files changed, 67 insertions(+), 40 deletions(-) diff --git a/client/web/src/components/IconBtn.tsx b/client/web/src/components/IconBtn.tsx index ea3640b3..17daa7f7 100644 --- a/client/web/src/components/IconBtn.tsx +++ b/client/web/src/components/IconBtn.tsx @@ -53,7 +53,8 @@ export const IconBtn: React.FC = React.memo( /> ); - if (isValidStr(title)) { + if (isValidStr(title) && !props.disabled) { + // 这里判断 props.disabled 是因为在禁用场景下显示title会有className无法带到Button组件上导致样式错误的问题(背景色溢出形状) return {btnEl}; } else { return btnEl; 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 72897f91..86e826b4 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,6 +1,11 @@ +import { useAsyncFn } from '@capital/common'; import { IconBtn } from '@capital/component'; import React from 'react'; -import { useClient, useMicrophoneAndCameraTracks } from './client'; +import { + useClient, + createMicrophoneAudioTrack, + createCameraVideoTrack, +} from './client'; import { useMeetingStore } from './store'; import { getClientLocalTrack } from './utils'; @@ -8,42 +13,47 @@ export const Controls: React.FC<{ onClose: () => void; }> = React.memo((props) => { const client = useClient(); - const { ready, tracks } = useMicrophoneAndCameraTracks(); const mediaPerm = useMeetingStore((state) => state.mediaPerm); - const mute = async (type: 'audio' | 'video') => { - if (type === 'audio') { - if (mediaPerm.audio === true) { - const track = getClientLocalTrack(client, 'audio'); - if (track) { - await client.unpublish(track); + const [{ loading }, mute] = useAsyncFn( + async (type: 'audio' | 'video') => { + if (type === 'audio') { + if (mediaPerm.audio === true) { + const track = getClientLocalTrack(client, 'audio'); + if (track) { + await client.unpublish(track); + } + } else { + const track = await createMicrophoneAudioTrack(); + await client.publish(track); } - } else { - await client.publish(tracks[0]); - } - useMeetingStore.getState().setMediaPerm({ audio: !mediaPerm.audio }); - } else if (type === 'video') { - if (mediaPerm.video === true) { - const track = getClientLocalTrack(client, 'video'); - if (track) { - await client.unpublish(track); + useMeetingStore.getState().setMediaPerm({ audio: !mediaPerm.audio }); + } else if (type === 'video') { + if (mediaPerm.video === true) { + const track = getClientLocalTrack(client, 'video'); + if (track) { + await client.unpublish(track); + } + } else { + const track = await createCameraVideoTrack(); + await client.publish(track); } - } else { - await client.publish(tracks[1]); - } - useMeetingStore.getState().setMediaPerm({ video: !mediaPerm.video }); - } - }; + useMeetingStore.getState().setMediaPerm({ video: !mediaPerm.video }); + } + }, + [client, mediaPerm] + ); const leaveChannel = async () => { await client.leave(); client.removeAllListeners(); useMeetingStore.getState().reset(); // we close the tracks to perform cleanup - tracks[0].close(); - tracks[1].close(); + client.localTracks.forEach((track) => { + track.close(); + }); props.onClose(); }; @@ -53,7 +63,7 @@ export const Controls: React.FC<{ icon={mediaPerm.video ? 'mdi:video' : 'mdi:video-off'} title={mediaPerm.video ? '关闭摄像头' : '开启摄像头'} active={mediaPerm.video} - disabled={!ready} + disabled={loading} size="large" onClick={() => mute('video')} /> @@ -62,7 +72,7 @@ export const Controls: React.FC<{ icon={mediaPerm.audio ? 'mdi:microphone' : 'mdi:microphone-off'} title={mediaPerm.audio ? '关闭麦克风' : '开启麦克风'} active={mediaPerm.audio} - disabled={!ready} + disabled={loading} size="large" onClick={() => 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 858e5a23..60549c53 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,8 +2,9 @@ import { UserAvatar, 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 { useClient } from './client'; import { useMeetingStore } from './store'; +import { getClientLocalTrack } from './utils'; const Root = styled.div<{ active?: boolean; @@ -59,15 +60,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); const active = useVolumeActive(String(client.uid)); + if (!client.uid) { + return null; + } + + const videoTrack = getClientLocalTrack(client, 'video'); + return ( - {ready && mediaPerm.video ? ( - + {mediaPerm.video ? ( + ) : ( )} diff --git a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/client.ts b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/client.ts index fe2a3a45..d37552bb 100644 --- a/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/client.ts +++ b/server/plugins/com.msgbyte.agora/web/plugins/com.msgbyte.agora/src/FloatWindow/client.ts @@ -1,8 +1,4 @@ -import { - ClientConfig, - createClient, - createMicrophoneAndCameraTracks, -} from 'agora-rtc-react'; +import AgoraRTC, { ClientConfig, createClient } from 'agora-rtc-react'; const config: ClientConfig = { mode: 'rtc', @@ -10,4 +6,5 @@ const config: ClientConfig = { }; export const useClient = createClient(config); -export const useMicrophoneAndCameraTracks = createMicrophoneAndCameraTracks(); +export const createCameraVideoTrack = AgoraRTC.createCameraVideoTrack; +export const createMicrophoneAudioTrack = AgoraRTC.createMicrophoneAudioTrack; 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 index c98a24f3..7abe8bbb 100644 --- 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 @@ -1,11 +1,24 @@ -import type { IAgoraRTCClient, ILocalTrack } from 'agora-rtc-react'; +import type { + IAgoraRTCClient, + ILocalAudioTrack, + ILocalTrack, + ILocalVideoTrack, +} from 'agora-rtc-react'; /** * 获取客户端本地轨道 */ export function getClientLocalTrack( client: IAgoraRTCClient, - trackMediaType: 'audio' | 'video' + trackMediaType: 'video' +): ILocalVideoTrack | null; +export function getClientLocalTrack( + client: IAgoraRTCClient, + trackMediaType: 'audio' +): ILocalAudioTrack | null; +export function getClientLocalTrack( + client: IAgoraRTCClient, + trackMediaType: string ): ILocalTrack | null { return ( client.localTracks.find(