yangjie #45
|
|
@ -42,6 +42,7 @@ const Meeting: React.FC = () => {
|
||||||
const singInRef = useRef<any>();
|
const singInRef = useRef<any>();
|
||||||
const userNameRef = useRef<any>();
|
const userNameRef = useRef<any>();
|
||||||
const [isClicked, setIsClicked] = useState(false);
|
const [isClicked, setIsClicked] = useState(false);
|
||||||
|
const [isClickedMediaSteam, setIsClickedMediaSteam] = useState(false);
|
||||||
const [statusList, setStatusList] = useState({
|
const [statusList, setStatusList] = useState({
|
||||||
userList: false,
|
userList: false,
|
||||||
userChatList: false,
|
userChatList: false,
|
||||||
|
|
@ -433,7 +434,7 @@ const Meeting: React.FC = () => {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const setting = await JSON.parse(storage.getItem('setting') as string);
|
const setting = await JSON.parse(storage.getItem('setting') as string);
|
||||||
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
||||||
if (stateInfo && setting.isRecordingTips) {
|
if (stateInfo && setting.isRecordingTips && location.href.indexOf('/meeting') !== -1) {
|
||||||
setRecorder((data: any) => {
|
setRecorder((data: any) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
setIsScreenCapture(bool => {
|
setIsScreenCapture(bool => {
|
||||||
|
|
@ -918,6 +919,18 @@ const Meeting: React.FC = () => {
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [isClicked]);
|
}, [isClicked]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
|
||||||
|
if (isClickedMediaSteam) {
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
setIsClickedMediaSteam(false)
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isClickedMediaSteam]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const elements = document.querySelectorAll('.intersectionObserver-view');
|
const elements = document.querySelectorAll('.intersectionObserver-view');
|
||||||
if (elements.length && currentVideoId) {
|
if (elements.length && currentVideoId) {
|
||||||
|
|
@ -1521,52 +1534,57 @@ const Meeting: React.FC = () => {
|
||||||
case '录制':
|
case '录制':
|
||||||
const setting = await JSON.parse(storage.getItem('setting') as string);
|
const setting = await JSON.parse(storage.getItem('setting') as string);
|
||||||
try {
|
try {
|
||||||
await fs.access(setting.recordingFilesPath, fs.constants.F_OK);
|
if (!isClickedMediaSteam) {
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '录制中';
|
setIsClickedMediaSteam(true)
|
||||||
footerListTemplate[itemIndex][rowIndex].active = true;
|
await fs.access(setting.recordingFilesPath, fs.constants.F_OK);
|
||||||
setFooterList(footerListTemplate);
|
footerListTemplate[itemIndex][rowIndex].title = '录制中';
|
||||||
window.electron.getSources().then(async (sources: any) => {
|
footerListTemplate[itemIndex][rowIndex].active = true;
|
||||||
const screenId = sources[0].id;
|
setFooterList(footerListTemplate);
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({
|
window.electron.getSources().then(async (sources: any) => {
|
||||||
audio: {
|
const screenId = sources[0].id;
|
||||||
mandatory: {
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
chromeMediaSource: 'desktop',
|
audio: {
|
||||||
chromeMediaSourceId: screenId,
|
mandatory: {
|
||||||
}
|
chromeMediaSource: 'desktop',
|
||||||
} as any,
|
chromeMediaSourceId: screenId,
|
||||||
video: {
|
}
|
||||||
mandatory: {
|
} as any,
|
||||||
chromeMediaSource: 'desktop',
|
video: {
|
||||||
chromeMediaSourceId: screenId,
|
mandatory: {
|
||||||
}
|
chromeMediaSource: 'desktop',
|
||||||
} as any
|
chromeMediaSourceId: screenId,
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
});
|
||||||
|
// 获取所有音频输入设备
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
const audioInputDevices = devices.filter(device => device.kind === 'audioinput' &&
|
||||||
|
device.deviceId !== 'default' &&
|
||||||
|
device.deviceId !== 'communications');
|
||||||
|
// 使用Web Audio API来捕获系统声音和麦克风声音,将它们合并到同一个MediaStream中。
|
||||||
|
const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)();
|
||||||
|
const systemSoundSource = audioCtx.createMediaStreamSource(stream);
|
||||||
|
const systemSoundDestination = audioCtx.createMediaStreamDestination();
|
||||||
|
systemSoundSource.connect(systemSoundDestination);
|
||||||
|
// 录制所有音频输入设备
|
||||||
|
audioInputDevices.forEach(async device => {
|
||||||
|
const micStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: device.deviceId } } });
|
||||||
|
setMediaStream((res: any) => [...res, micStream]);
|
||||||
|
const micSoundSource = audioCtx.createMediaStreamSource(micStream);
|
||||||
|
micSoundSource.connect(systemSoundDestination);
|
||||||
|
})
|
||||||
|
// 合并音频流与视频流
|
||||||
|
const combinedSource = new MediaStream([...stream.getVideoTracks(), ...systemSoundDestination.stream.getAudioTracks()]);
|
||||||
|
// 开始录制
|
||||||
|
const mediaRecorder = new MediaRecorder(combinedSource, {
|
||||||
|
mimeType: 'video/webm;codecs=vp9,opus',
|
||||||
|
videoBitsPerSecond: 1.5e6,
|
||||||
|
});
|
||||||
|
setRecorder(mediaRecorder);
|
||||||
});
|
});
|
||||||
// 获取所有音频输入设备
|
} else {
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
message.error('录制太频繁了,请稍后重试!');
|
||||||
const audioInputDevices = devices.filter(device => device.kind === 'audioinput' &&
|
}
|
||||||
device.deviceId !== 'default' &&
|
|
||||||
device.deviceId !== 'communications');
|
|
||||||
// 使用Web Audio API来捕获系统声音和麦克风声音,将它们合并到同一个MediaStream中。
|
|
||||||
const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)();
|
|
||||||
const systemSoundSource = audioCtx.createMediaStreamSource(stream);
|
|
||||||
const systemSoundDestination = audioCtx.createMediaStreamDestination();
|
|
||||||
systemSoundSource.connect(systemSoundDestination);
|
|
||||||
// 录制所有音频输入设备
|
|
||||||
audioInputDevices.forEach(async device => {
|
|
||||||
const micStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: device.deviceId } } });
|
|
||||||
setMediaStream((res: any) => [...res, micStream]);
|
|
||||||
const micSoundSource = audioCtx.createMediaStreamSource(micStream);
|
|
||||||
micSoundSource.connect(systemSoundDestination);
|
|
||||||
})
|
|
||||||
// 合并音频流与视频流
|
|
||||||
const combinedSource = new MediaStream([...stream.getVideoTracks(), ...systemSoundDestination.stream.getAudioTracks()]);
|
|
||||||
// 开始录制
|
|
||||||
const mediaRecorder = new MediaRecorder(combinedSource, {
|
|
||||||
mimeType: 'video/webm;codecs=vp9,opus',
|
|
||||||
videoBitsPerSecond: 1.5e6,
|
|
||||||
});
|
|
||||||
setRecorder(mediaRecorder);
|
|
||||||
});
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.code === 'ENOENT') {
|
if (error.code === 'ENOENT') {
|
||||||
message.error({
|
message.error({
|
||||||
|
|
@ -1582,10 +1600,14 @@ const Meeting: React.FC = () => {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '录制中':
|
case '录制中':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '录制'
|
if (isClickedMediaSteam) {
|
||||||
footerListTemplate[itemIndex][rowIndex].active = false
|
message.error('录制时长不足3秒,请稍后重试!');
|
||||||
setFooterList(footerListTemplate)
|
} else {
|
||||||
stopRecorderMedia()
|
footerListTemplate[itemIndex][rowIndex].title = '录制'
|
||||||
|
footerListTemplate[itemIndex][rowIndex].active = false
|
||||||
|
setFooterList(footerListTemplate)
|
||||||
|
stopRecorderMedia()
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '共享文件':
|
case '共享文件':
|
||||||
sharedFilesModelRef.current.getData()
|
sharedFilesModelRef.current.getData()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue