1

Summary of problem: A Javascript solution to record screen works on desktop versions of browsers (chrome, edge, firefox), but not on mobile browsers (chrome, safari).

Following this great example I was able to build a prototype that works just fine on desktop browsers (tested on Chrome, Edge, Firefox).

However when testing on mobile browser (chrome/safari on ios), there is an error:

TypeError: undefined is not a function (near '...navigator.mediaDevices.getDisplayMedia...')

Below is the HTML code for on-screen buttons:

        <input id="btnStartRecording" class="btn btn-lg btn-primary col-4" onclick="startRecord()" value="Start Recording" type="button">
        <input id="btnStopRecording" class="btn btn-lg btn-primary col-4 invisible" onclick="stopScreen()" value="Stop Recording" type="button">
        <a id="btnDownloadRecording" href="#" class="btn btn-lg btn-primary col-4 text-white invisible">Download Video</a>

Below is a hidden video element to hold the recording, and script to record:

    <div>
        <video controls="true" style="display: none" id="videoResult" src=""></video>
    </div>
    <script> // client side recording script https://javascript.plainenglish.io/vanilla-javascript-based-screen-recorder-29fff1cc7b00
        let completeBlob = null
        let recorder = null
        let chunks = [];
        let stream = null
        async function startRecord() {
            chunks = []; // need to reset chucks each time recording is started

            try {

                stream = await navigator.mediaDevices.getDisplayMedia({
                    video: {
                        mediaSource: 'screen'
                    },
                })

                recorder = new MediaRecorder(stream);
                recorder.ondataavailable = (e) => chunks.push(e.data);
                recorder.start();
                recorder.onstop = onstop

                $("#btnStartRecording").addClass("invisible");
                $("#btnStopRecording").removeClass("invisible");
                $("#btnDownloadRecording").addClass("invisible");

            } catch (error) {

                navigator.getUserMedia = navigator.getUserMedia ||
                    navigator.webkitGetUserMedia ||
                    navigator.mozGetUserMedia || navigator.msGetUserMedia; 

                if (navigator.getUserMedia) {
                    navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },
                        function (streamobj) {

                            recorder = new MediaRecorder(streamobj);
                            recorder.ondataavailable = (e) => chunks.push(e.data);
                            recorder.start();
                            recorder.onstop = onstop

                            $("#btnStartRecording").addClass("invisible");
                            $("#btnStopRecording").removeClass("invisible");
                            $("#btnDownloadRecording").addClass("invisible");

                            //var video = document.querySelector('video');
                            //video.srcObject = stream;
                            //video.onloadedmetadata = function (e) {
                            //    video.play();
                            //};
                        },
                        function (err) {
                            window.alert("#1 " + err)
                        }
                    );
                }
                else {
                    window.alert("#2 " + error)
                }
            }
        }


        async function stopScreen() {
            recorder.stop();
            //document.getElementById("stopBtn").style.display = "none";
            $("#btnStartRecording").removeClass("invisible");
            $("#btnStopRecording").addClass("invisible");
            stream.getTracks().forEach(function (track) {
                track.stop();
            });
        }

        function onstop() {
            console.log("onstop");
            completeBlob = new Blob(chunks, {
                type: chunks[0].type
            });
            $("#btnDownloadRecording").removeClass("invisible");
            let downloadButton = document.getElementById('btnDownloadRecording');
            let video = document.getElementById('videoResult');
            //video.style.display = 'block'
            video.src = URL.createObjectURL(completeBlob);
            //downloadButton.style.display = 'unset'
            downloadButton.href = URL.createObjectURL(completeBlob);
            downloadButton.download = Date.now() + '.mp4';
        }
    </script>

Being not familiar with the APIs I used some SO threads such as this as reference to handle when "navigator.mediaDevices.getDisplayMedia" failed, which is the code in the "catch" part. But obviously it still does not work on mobile. Once accessed, the window.alert("#2 " + error) line was executed, which implies if (navigator.getUserMedia) evaluates to false.

Further digging found this SO discussion which says only Safari works but I tested it on Safari and it failed with the same error message.

Any help is appreciated!

Cal
  • 747
  • 1
  • 13
  • 30

0 Answers0