diff --git a/src/app/slices/voice.ts b/src/app/slices/voice.ts
index 2e00a420..f5acd23c 100644
--- a/src/app/slices/voice.ts
+++ b/src/app/slices/voice.ts
@@ -13,6 +13,7 @@ export type VoicingInfo = {
muted?: boolean,
deafen?: boolean,
video?: boolean,
+ shareScreen?: boolean,
joining?: boolean,
connectionState?: ConnectionState
} & VoiceBasicInfo
@@ -21,7 +22,8 @@ export type VoicingMemberInfo = {
speakingVolume?: number,
muted?: boolean,
deafen?: boolean,
- video?: boolean
+ video?: boolean,
+ shareScreen?: boolean
}
export type VoicingMembers = {
diff --git a/src/common/component/Voice.tsx b/src/common/component/Voice.tsx
index 1039b016..0a0cabf4 100644
--- a/src/common/component/Voice.tsx
+++ b/src/common/component/Voice.tsx
@@ -7,6 +7,7 @@ import { addVoiceMember, removeVoiceMember, updateConnectionState, updateDeafenS
import { useAppSelector } from '../../app/store';
import AudioJoin from '../../assets/join.wav';
import { playAgoraVideo } from '../utils';
+import { ShareScreenTrack } from '../../types/global';
AgoraRTC.setLogLevel(process.env.NODE_ENV === 'development' ? 0 : 4);
window.VOICE_TRACK_MAP = window.VOICE_TRACK_MAP ?? {};
window.VIDEO_TRACK_MAP = window.VIDEO_TRACK_MAP ?? {};
@@ -214,6 +215,60 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
}));
}
};
+ const stopShareScreen = async () => {
+ const localVideoTrack = window.VIDEO_TRACK_MAP[loginUid] as ShareScreenTrack;
+ if (localVideoTrack) {
+ await window.VOICE_CLIENT?.unpublish(localVideoTrack);
+ if ("close" in localVideoTrack) {
+ localVideoTrack.close();
+ } else {
+ localVideoTrack[0].close();
+ }
+ // localVideoTrack.close();
+ window.VIDEO_TRACK_MAP[loginUid] = null;
+ // 关闭视频后,需要把视频的高度设置回去
+ const playerEle = document.querySelector(`#CAMERA_${loginUid}`) as HTMLElement;
+ playerEle.classList.remove("h-[120px]");
+ dispatch(updateVoicingInfo({
+ video: false,
+ shareScreen: false,
+ id,
+ context,
+ }));
+ }
+ };
+ const startShareScreen = async () => {
+ try {
+ const localVideoTrack = await AgoraRTC.createScreenVideoTrack({
+ // 配置屏幕共享编码参数,详情请查看 API 文档。
+ encoderConfig: "1080p_1",
+ // 设置视频传输优化策略为清晰优先或流畅优先。
+ optimizationMode: "detail",
+ });
+
+ // 取消正在进行的视频
+ await closeCamera();
+ await window.VOICE_CLIENT?.publish(localVideoTrack);
+ dispatch(updateVoicingInfo({
+ video: false,
+ shareScreen: true,
+ id,
+ context,
+ }));
+ // 放到全局变量里
+ window.VIDEO_TRACK_MAP[loginUid] = localVideoTrack;
+ playAgoraVideo(loginUid);
+ // 监听屏幕共享结束事件
+ if ("close" in localVideoTrack) {
+ localVideoTrack.getMediaStreamTrack().onended = () => {
+ stopShareScreen();
+ };
+ }
+ } catch (error) {
+ console.log("start share screen error", error);
+
+ }
+ };
const leave = async () => {
const localAudioTrack = window.VOICE_TRACK_MAP[loginUid] as IMicrophoneAudioTrack;
@@ -285,7 +340,9 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
joined: !!voicingInfo,
joinVoice,
openCamera,
- closeCamera
+ closeCamera,
+ startShareScreen,
+ stopShareScreen,
};
};
export { useVoice };
diff --git a/src/common/utils.tsx b/src/common/utils.tsx
index 046f5648..303f82a3 100644
--- a/src/common/utils.tsx
+++ b/src/common/utils.tsx
@@ -1,6 +1,6 @@
import dayjs from "dayjs";
import BASE_URL, { FILE_IMAGE_SIZE, ContentTypes, KEY_TOKEN, KEY_REFRESH_TOKEN, KEY_EXPIRE } from "../app/config";
-import { ICameraVideoTrack } from "agora-rtc-sdk-ng";
+import { ICameraVideoTrack, ILocalAudioTrack, ILocalVideoTrack } from "agora-rtc-sdk-ng";
import IconPdf from "../assets/icons/file.pdf.svg";
import IconAudio from "../assets/icons/file.audio.svg";
import IconVideo from "../assets/icons/file.video.svg";
@@ -381,7 +381,13 @@ export const playAgoraVideo = (uid: number, videoTrack?: ICameraVideoTrack | nul
if (videoTrack) {
videoTrack.play(playerEle);
} else {
- window.VIDEO_TRACK_MAP[uid]?.play(playerEle);
+ if (!window.VIDEO_TRACK_MAP[uid]) return;
+ if ("play" in (window.VIDEO_TRACK_MAP[uid] ?? {})) {
+ window.VIDEO_TRACK_MAP[uid]?.play(playerEle);
+ } else {
+ const tracks = window.VIDEO_TRACK_MAP[uid] as [ILocalVideoTrack, ILocalAudioTrack];
+ tracks[0].play(playerEle);
+ }
}
}
};
\ No newline at end of file
diff --git a/src/routes/chat/RTCWidget.tsx b/src/routes/chat/RTCWidget.tsx
index d847ae26..7da11dac 100644
--- a/src/routes/chat/RTCWidget.tsx
+++ b/src/routes/chat/RTCWidget.tsx
@@ -22,7 +22,7 @@ type Props = {
const RTCWidget = ({ id, context = "channel" }: Props) => {
const { t } = useTranslation("chat");
- const { leave, voicingInfo, setMute, setDeafen, joining = true, openCamera, closeCamera } = useVoice({ context, id });
+ const { leave, voicingInfo, setMute, setDeafen, joining = true, openCamera, closeCamera, startShareScreen, stopShareScreen } = useVoice({ context, id });
const { loginUser, channelData, userData } = useAppSelector(store => {
return {
userData: store.users.byId,
@@ -54,8 +54,8 @@ const RTCWidget = ({ id, context = "channel" }: Props) => {
Video
-