six-dimension-aigc/src/lib/useCommon.ts

260 lines
6.6 KiB
TypeScript

/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
import { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import VERTC, { MediaType } from '@volcengine/rtc';
import { Modal } from '@arco-design/web-react';
import Utils from '@/utils/utils';
import RtcClient from '@/lib/RtcClient';
import {
clearCurrentMsg,
clearHistoryMsg,
localJoinRoom,
localLeaveRoom,
updateAIGCState,
updateLocalUser,
} from '@/store/slices/room';
import useRtcListeners from '@/lib/listenerHooks';
import { RootState } from '@/store';
import {
updateMediaInputs,
updateSelectedDevice,
setDevicePermissions,
} from '@/store/slices/device';
import logger from '@/utils/logger';
import aigcConfig, { AI_MODEL } from '@/config';
export interface FormProps {
username: string;
roomId: string;
publishAudio: boolean;
}
export const useVisionMode = () => {
const room = useSelector((state: RootState) => state.room);
return [AI_MODEL.VISION].includes(room.aiConfig?.Config?.LLMConfig.ModelName);
};
export const useGetDevicePermission = () => {
const [permission, setPermission] = useState<{
audio: boolean;
}>();
const dispatch = useDispatch();
useEffect(() => {
(async () => {
const permission = await RtcClient.checkPermission();
dispatch(setDevicePermissions(permission));
setPermission(permission);
})();
}, [dispatch]);
return permission;
};
export const useJoin = (): [
boolean,
(formValues: FormProps, fromRefresh: boolean) => Promise<void | boolean>
] => {
const devicePermissions = useSelector((state: RootState) => state.device.devicePermissions);
const room = useSelector((state: RootState) => state.room);
const dispatch = useDispatch();
const [joining, setJoining] = useState(false);
const listeners = useRtcListeners();
const handleAIGCModeStart = async () => {
if (room.isAIGCEnable) {
await RtcClient.stopAudioBot();
dispatch(clearCurrentMsg());
await RtcClient.startAudioBot();
} else {
await RtcClient.startAudioBot();
}
dispatch(updateAIGCState({ isAIGCEnable: true }));
};
async function disPatchJoin(formValues: FormProps): Promise<boolean | undefined> {
if (joining) {
return;
}
const isSupported = await VERTC.isSupported();
if (!isSupported) {
Modal.error({
title: '不支持 RTC',
content: '您的浏览器可能不支持 RTC 功能,请尝试更换浏览器或升级浏览器后再重试。',
});
return;
}
setJoining(true);
const { username, roomId } = formValues;
const isVisionMode = aigcConfig.Model === AI_MODEL.VISION;
const token = aigcConfig.BaseConfig.Token;
/** 1. Create RTC Engine */
await RtcClient.createEngine({
appId: aigcConfig.BaseConfig.AppId,
roomId,
uid: username,
} as any);
/** 2.1 Set events callbacks */
RtcClient.addEventListeners(listeners);
/** 2.2 RTC starting to join room */
await RtcClient.joinRoom(token!, username);
console.log(' ------ userJoinRoom\n', `roomId: ${roomId}\n`, `uid: ${username}`);
/** 3. Set users' devices info */
const mediaDevices = await RtcClient.getDevices({
audio: true,
video: isVisionMode,
});
if (devicePermissions.audio) {
try {
await RtcClient.startAudioCapture();
// RtcClient.setAudioVolume(30);
} catch (e) {
logger.debug('No permission for mic');
}
}
if (devicePermissions.video && isVisionMode) {
try {
await RtcClient.startVideoCapture();
} catch (e) {
logger.debug('No permission for camera');
}
}
dispatch(
localJoinRoom({
roomId,
user: {
username,
userId: username,
publishAudio: true,
publishVideo: devicePermissions.video && isVisionMode,
},
})
);
dispatch(
updateSelectedDevice({
selectedMicrophone: mediaDevices.audioInputs[0]?.deviceId,
selectedCamera: mediaDevices.videoInputs[0]?.deviceId,
})
);
dispatch(updateMediaInputs(mediaDevices));
setJoining(false);
Utils.setSessionInfo({
username,
roomId,
publishAudio: true,
});
handleAIGCModeStart();
}
return [joining, disPatchJoin];
};
export const useLeave = () => {
const dispatch = useDispatch();
return async function () {
dispatch(localLeaveRoom());
dispatch(updateAIGCState({ isAIGCEnable: false }));
await Promise.all([RtcClient.stopAudioCapture]);
RtcClient.leaveRoom();
dispatch(clearHistoryMsg());
dispatch(clearCurrentMsg());
};
};
export const useDeviceState = () => {
const dispatch = useDispatch();
const room = useSelector((state: RootState) => state.room);
const localUser = room.localUser;
const isAudioPublished = localUser.publishAudio;
const isVideoPublished = localUser.publishVideo;
const queryDevices = async (type: MediaType) => {
const mediaDevices = await RtcClient.getDevices({
audio: type === MediaType.AUDIO,
video: type === MediaType.VIDEO,
});
if (type === MediaType.AUDIO) {
dispatch(
updateMediaInputs({
audioInputs: mediaDevices.audioInputs,
})
);
dispatch(
updateSelectedDevice({
selectedMicrophone: mediaDevices.audioInputs[0]?.deviceId,
})
);
} else {
dispatch(
updateMediaInputs({
videoInputs: mediaDevices.videoInputs,
})
);
dispatch(
updateSelectedDevice({
selectedCamera: mediaDevices.videoInputs[0]?.deviceId,
})
);
}
return mediaDevices;
};
const switchMic = (publish = true) => {
if (publish) {
!isAudioPublished
? RtcClient.publishStream(MediaType.AUDIO)
: RtcClient.unpublishStream(MediaType.AUDIO);
}
queryDevices(MediaType.AUDIO);
!isAudioPublished ? RtcClient.startAudioCapture() : RtcClient.stopAudioCapture();
dispatch(
updateLocalUser({
publishAudio: !localUser.publishAudio,
})
);
};
const switchCamera = (publish = true) => {
if (publish) {
!isVideoPublished
? RtcClient.publishStream(MediaType.VIDEO)
: RtcClient.unpublishStream(MediaType.VIDEO);
}
queryDevices(MediaType.VIDEO);
!localUser.publishVideo ? RtcClient.startVideoCapture() : RtcClient.stopVideoCapture();
dispatch(
updateLocalUser({
publishVideo: !localUser.publishVideo,
})
);
};
return {
isAudioPublished,
isVideoPublished,
switchMic,
switchCamera,
};
};