Elvis Murseli
Elvis Murseli

Reputation: 17

Audio tracks not stopping after stopping the audio inputs - Chrome extension

I have a screen recorder in the extension where I use the microphone user, everything is working fine with the screen recorder but I have a small thing, after clicking on the Stop Recording button in the extension or the Stop Share chrome button it says that the microphone is still in use, and I can't seem to debug it myself. I checked different ways here in stackoverflow but none seems to work so I decided to post a question.

Here's the logic and code (this is all in the contentScript.js).

First when we open the extension it lists different audio types:

async function listAudioInputSources () {
    try {
        currentAudioStream = await navigator.mediaDevices.getUserMedia({audio: true});
        window.streamReference = currentAudioStream;
        const devices = await navigator.mediaDevices.enumerateDevices();
        audioInputs = devices.filter(device => device.kind === 'audioinput').map(device => ({
            deviceId: device.deviceId,
            label: device.label,
            volumeLevels: Array(10).fill(false)
        }));
        
        if(audioInputs.length > 0) {
            audioInputs.forEach(input => setupAudioContext(input.deviceId));
        }

        audioError = false

        chrome.runtime.sendMessage({
            action: 'audio-sources-updated',
            audios: audioInputs,
            micMsg: audioError
        });
    } catch (error) {
        console.error('Error accessing audio devices:', error);
        audioError = true
        chrome.runtime.sendMessage({ action: "audio-sources-updated", micMsg: audioError });
    }
}

After we click in one of the audios we call this function which sets that audio:

async function switchAudioInput(deviceId) {
    if (selectedAudioInput === deviceId) return;

    selectedAudioInput = deviceId;

    Object.values(audioStreams).forEach(stream => {
        stream.getTracks().forEach(track => track.stop());
    });

    Object.values(audioContexts).forEach(context => context.close());

    audioContexts = {};
    analyzerNodes = {};
    audioStreams = {};

    setupAudioContext(deviceId)
}
async function setupAudioContext (deviceId) {
    try {
        currentAudioStream = await navigator.mediaDevices.getUserMedia({
            audio: {
                deviceId: { exact: deviceId },
                noiseSuppression: false,
                echoCancellation: false,
            }
        });
        initializeAudioContext(deviceId, currentAudioStream);
    } catch (error) {
        console.log(error)
    }
}

And then we start recording (in the below function we also have the onstop event where are the steps that we do when the screensharing stops):

async function startScreenRecording() {
    try {
        const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: {frameRate: { max: 10 }, width: { max: 1280 }, height: { max: 720 }}});

        const audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });

        mediaStream = new MediaStream([
            ...screenStream.getTracks(),
            ...audioStream.getTracks()
        ]);

        startTimer()

        mediaRecorder = new MediaRecorder(mediaStream, { mimeType: "video/mp4" });
        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                recordedChunks.push(event.data);
            }
        };

        let ended = false

        const videoStream = screenStream.getVideoTracks()[0];
        videoStream.addEventListener('ended', () => {
            ended = true
            mediaRecorder.stop();
            chrome.storage.local.set({ state: 'prerecording' })
        });

        mediaRecorder.onstop = () => {
            document.title = title
            clearInterval(timer)
            recordTime = 0

            const blob = new Blob(recordedChunks, { type: "video/mp4" });
            if (!isReset) {
                if (!ended) chrome.runtime.sendMessage({ action: "opening-video" });

                setTimeout(async () => {
                    const openVideoBackr = window.open(`${baseURL}/record?ext`, '_blank')

                    window.addEventListener('message', function handleMessage(event) {
                        if (event.source === openVideoBackr && event.data === 'ready') {
                            openVideoBackr.postMessage({ blob }, baseURL);
                            window.removeEventListener('message', handleMessage);
                        }
                    });
        
                    const checkWindowReady = setInterval(() => {
                        if (openVideoBackr) {
                            openVideoBackr.postMessage({ blob }, baseURL);
                        }
                    }, 100);
                    
                    setTimeout(() => {
                        clearInterval(checkWindowReady);
                    }, 5000);
                }, !ended ? 700 : 100)
            }
            recordedChunks = [];
            isReset = false
            ended = false
        };

        mediaRecorder.start();
    } catch (error) {
        console.error("Error starting screen recording:", error);
    }
}

when we click in the stop recording button in the extension we first call this func:

function stopScreenRecording() {
    if (mediaRecorder && mediaRecorder.state !== "inactive") {
        mediaRecorder.stop();
        if (mediaStream) {
            mediaStream.getTracks().forEach(track => track.stop());
            mediaStream = null;
        }
    }
}

I tried different ways of stopping the audio tracks but didnt seem to work. I thought one thing might be that we are opening a new tab and redirecting the user to a new tab at the same time we stop recording or something. I tried to mess around with that but couldn't figure it out.

That's besically more or less all the main steps but if you need more information I'd be glad to provide it.

Thank you for your help!

Upvotes: 0

Views: 18

Answers (0)

Related Questions