www: reduce to a minimal functionnal demo (microphone is always included)

This commit is contained in:
2023-11-08 12:02:57 +01:00
committed by Mathieu Virbel
parent 4a0ca35a87
commit 1bf0e5946a

View File

@@ -1,4 +1,4 @@
import React, { useRef, useEffect, useState, useMemo } from "react"; import React, { useRef, useEffect, useState } from "react";
import WaveSurfer from "wavesurfer.js"; import WaveSurfer from "wavesurfer.js";
import RecordPlugin from "../../lib/custom-plugins/record"; import RecordPlugin from "../../lib/custom-plugins/record";
@@ -14,7 +14,6 @@ import { AudioWaveform } from "../../api";
import AudioInputsDropdown from "./audioInputsDropdown"; import AudioInputsDropdown from "./audioInputsDropdown";
import { Option } from "react-dropdown"; import { Option } from "react-dropdown";
import { waveSurferStyles } from "../../styles/recorder"; import { waveSurferStyles } from "../../styles/recorder";
import useMp3 from "./useMp3";
type RecorderProps = { type RecorderProps = {
setStream?: React.Dispatch<React.SetStateAction<MediaStream | null>>; setStream?: React.Dispatch<React.SetStateAction<MediaStream | null>>;
@@ -235,6 +234,7 @@ export default function Recorder(props: RecorderProps) {
record.stopRecording(); record.stopRecording();
setIsRecording(false); setIsRecording(false);
setHasRecorded(true); setHasRecorded(true);
setDestinationStream(null);
} else { } else {
const stream = await getCurrentStream(); const stream = await getCurrentStream();
@@ -253,86 +253,71 @@ export default function Recorder(props: RecorderProps) {
const handleRecordTabClick = async () => { const handleRecordTabClick = async () => {
if (!record) return console.log("no record"); if (!record) return console.log("no record");
const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({ const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
video: { video: true,
displaySurface: "window",
},
audio: { audio: {
echoCancellation: true, echoCancellation: true,
noiseSuppression: true, noiseSuppression: true,
sampleRate: 44100, sampleRate: 44100,
suppressLocalAudioPlayback: true,
}, },
surfaceSwitching: "include",
selfBrowserSurface: "exclude",
systemAudio: "include",
}); });
console.log("stream", stream);
console.log(stream.getAudioTracks());
return;
const videoElem = document.getElementById( if (stream.getAudioTracks().length == 0) {
"video-recording", setError(new Error("No audio track found in screen recording."));
) as HTMLVideoElement; return;
videoElem.onloadedmetadata = () => { }
setScreenMediaStream(stream); setScreenMediaStream(stream);
};
videoElem.srcObject = stream;
videoElem.play();
}; };
const audioContext = useMemo(() => { const [destinationStream, setDestinationStream] =
return new AudioContext(); useState<MediaStream | null>(null);
}, []);
const systemAudioGainNode = useMemo(() => {
return audioContext.createGain();
}, []);
const microphoneGainNode = useMemo(() => {
return audioContext.createGain();
}, []);
const audioDestNode = useMemo(() => { const startTabRecording = async () => {
const dest = audioContext.createMediaStreamDestination();
systemAudioGainNode.connect(dest);
microphoneGainNode.connect(dest);
return dest;
}, []);
useEffect(() => {
console.log("useEffect screenMediaStream", screenMediaStream);
console.log("useEffect record", record);
if (!screenMediaStream) return; if (!screenMediaStream) return;
if (!record) return console.log("no record"); if (!record) return;
if (destinationStream !== null) return console.log("already recording");
const videoElem = document.getElementById( console.log("startTabRecording");
"video-recording",
) as HTMLVideoElement;
const videoMS = videoElem.captureStream() as MediaStream;
console.log(videoMS);
console.log(videoMS.getAudioTracks());
if (videoMS.getAudioTracks().length == 0) { // connect mic audio (microphone)
console.log("no audio track"); const micStream = await getCurrentStream();
if (!micStream) {
console.log("no microphone audio");
return; return;
} }
// connect system audio (tab audio) // Create MediaStreamSource nodes for the microphone and tab
const systemAudioSrc = audioContext.createMediaStreamSource(videoMS); const audioContext = new AudioContext();
systemAudioSrc.connect(systemAudioGainNode); const micSource = audioContext.createMediaStreamSource(micStream);
const tabSource = audioContext.createMediaStreamSource(screenMediaStream);
// create a media stream having both system audio and microphone audio // Merge channels
// const ms = new MediaStream(); // XXX If the length is not the same, we do not receive audio in WebRTC.
// videoMS.getVideoTracks().forEach((track) => ms.addTrack(track)); // So for now, merge the channels to have only one stereo source
// audioDestNode.stream const channelMerger = audioContext.createChannelMerger(1);
// .getAudioTracks() micSource.connect(channelMerger, 0, 0);
// .forEach((track) => ms.addTrack(track)); tabSource.connect(channelMerger, 0, 0);
const stream = audioDestNode.stream; // Create a MediaStreamDestination node
if (props.setStream) props.setStream(stream); const destination = audioContext.createMediaStreamDestination();
channelMerger.connect(destination);
// Use the destination's stream for the WebRTC connection
setDestinationStream(destination.stream);
};
useEffect(() => {
if (!record) return;
if (!destinationStream) return;
if (props.setStream) props.setStream(destinationStream);
waveRegions?.clearRegions(); waveRegions?.clearRegions();
if (stream) { if (destinationStream) {
record.startRecording(stream); record.startRecording(destinationStream);
setIsRecording(true); setIsRecording(true);
} }
}, [record, destinationStream]);
useEffect(() => {
startTabRecording();
}, [record, screenMediaStream]); }, [record, screenMediaStream]);
const handlePlayClick = () => { const handlePlayClick = () => {
@@ -415,13 +400,19 @@ export default function Recorder(props: RecorderProps) {
> >
{isRecording ? "Stop" : "Record"} {isRecording ? "Stop" : "Record"}
</button> </button>
<button onClick={handleRecordTabClick}>Record a tab</button> {!isRecording && (
<video <button
className="body-main-video" className={`${
id="video-recording" isRecording
muted ? "bg-red-400 hover:bg-red-500 focus-visible:bg-red-500"
style={{ maxWidth: "200px" }} : "bg-blue-400 hover:bg-blue-500 focus-visible:bg-blue-500"
></video> } text-white ml-2 md:ml:4 md:h-[78px] md:min-w-[100px] text-lg`}
onClick={handleRecordTabClick}
>
Record
<br />a tab
</button>
)}
{props.audioDevices && props.audioDevices?.length > 0 && deviceId && ( {props.audioDevices && props.audioDevices?.length > 0 && deviceId && (
<> <>
<button <button