muaz-khan / RecordRTC

RecordRTC is WebRTC JavaScript library for audio/video as well as screen activity recording. It supports Chrome, Firefox, Opera, Android, and Microsoft Edge. Platforms: Linux, Mac and Windows.
https://www.webrtc-experiment.com/RecordRTC/
MIT License
6.45k stars 1.75k forks source link

ElectronJS Screen Recording #754

Open samueleastdev opened 2 years ago

samueleastdev commented 2 years ago

Hi,

I am just testing with this to see if I can get it to work nicely with Electron.

If I run this code in an ElectronJS windows it works fine and records audio and video via the webcam.

navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
}).then(async function(stream) {
    let recorder = RecordRTC(stream, {
        type: 'video'
    });
    recorder.startRecording();

    const sleep = m => new Promise(r => setTimeout(r, m));
    await sleep(3000);

    recorder.stopRecording(function() {
        let blob = recorder.getBlob();
        invokeSaveAsDialog(blob);
    });
});

Screenshot 2021-07-06 at 23 32 40

Now if I try and do screen recording from another post I read in the issues here i get a permissions denied error. index.html:44 Uncaught (in promise) DOMException: Permission denied

Running this code

(async () => {
    let mic = await navigator.mediaDevices.getUserMedia({
        audio: true
    });
    let screenPlusMic = await navigator.mediaDevices.getDisplayMedia({
        video: true
    });
    screenPlusMic.addTrack(mic.getTracks()[0]);
    let recorder = new RecordRTCPromisesHandler(screenPlusMic, {
        type: 'video'
    });
    recorder.startRecording();

    const sleep = m => new Promise(r => setTimeout(r, m));
    await sleep(3000);

    await recorder.stopRecording();
    let blob = await recorder.getBlob();
    invokeSaveAsDialog(blob);
})();

He is my full ElectronJS index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>,
    Chromium <span id="chrome-version"></span>,
    and Electron <span id="electron-version"></span>.
    <button id="record">Record</button>
    <!-- recommended -->
    <script src="https://www.WebRTC-Experiment.com/RecordRTC.js"></script>
    <script>

      window.$ = window.jQuery = require("jquery");

      const ipc = require("electron").ipcRenderer;

      (function() {
          $("#record").on("click", function(event) {
              event.preventDefault();

              (async () => {
                  let mic = await navigator.mediaDevices.getUserMedia({
                      audio: true
                  });
                  let screenPlusMic = await navigator.mediaDevices.getDisplayMedia({
                      video: true
                  });
                  screenPlusMic.addTrack(mic.getTracks()[0]);
                  let recorder = new RecordRTCPromisesHandler(screenPlusMic, {
                      type: 'video'
                  });
                  recorder.startRecording();

                  const sleep = m => new Promise(r => setTimeout(r, m));
                  await sleep(3000);

                  await recorder.stopRecording();
                  let blob = await recorder.getBlob();
                  invokeSaveAsDialog(blob);
              })();

              /*
              navigator.mediaDevices.getUserMedia({
                  video: true,
                  audio: true
              }).then(async function(stream) {
                  let recorder = RecordRTC(stream, {
                      type: 'video'
                  });
                  recorder.startRecording();

                  const sleep = m => new Promise(r => setTimeout(r, m));
                  await sleep(3000);

                  recorder.stopRecording(function() {
                      let blob = recorder.getBlob();
                      invokeSaveAsDialog(blob);
                  });
              });*/

          });

      })();
    </script>
  </body>
</html>

Do I need to implement https://www.electronjs.org/docs/api/desktop-capturer to get the permissions.

Can someone point me in the right direction.

Thanks

samueleastdev commented 2 years ago

Ok this works with ElectonJS records the screen and audio its pretty clunky but works.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Record With Audio</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <style>
      .stop {
        position: absolute;
        top: 45px;
        z-index: 9999;
      }
      .start {
        position: absolute;
        top: 0px;
        z-index: 9999;
      }
    </style>
  </head>
  <body>

    <button class="btn btn-primary stop" id="stoprecording">STOP RECORDING</button>
    <button class="btn btn-primary start" id="startrecording">START RECORDING</button>
    <!--<video id="preview-screen" controls autoplay height="720" width="1280"></video>-->

    <!-- recommended -->
    <script src="https://cdn.webrtc-experiment.com/RecordRTC.js"></script>
    <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
    <script src="https://cdn.WebRTC-Experiment.com/getScreenId.js"></script>
    <script>

      window.$ = window.jQuery = require("jquery");

      const {
          desktopCapturer
      } = require('electron');

      desktopCapturer.getSources({ types:['window', 'screen'] })
        .then( sources => {
            console.log(sources);
        });

      const ipc = require("electron").ipcRenderer;

      function captureScreen(cb) {
          getScreenId(function(error, sourceId, screen_constraints) {

            //screen_constraints.video.mandatory.chromeMediaSourceId = "window:3161:0";
            console.log('screen_constraints',screen_constraints);
              navigator.mediaDevices.getUserMedia(screen_constraints).then(cb).catch(function(error) {
                  console.error('getScreenId error', error);
                  alert('Failed to capture your screen. Please check browser console logs for further information.');
              });
          }, true);
      }

      function captureAudio(cb) {
          navigator.mediaDevices.getUserMedia({
              audio: true,
              video: false
          }).then(cb);
      }

      var recorder = '';
      var screenRec = '';
      var micRec = '';

      function OnLoadedMetaData() {
          captureScreen(function(screen) {

              captureAudio(function(mic) {

                  screen.width = window.screen.width;
                  screen.height = window.screen.height;
                  screen.fullcanvas = true;

                  recorder = RecordRTC([screen, mic], {
                      type: 'video',
                      mimeType: 'video/webm'
                  });

                  screenRec = screen;
                  micRec = mic;

                  //Start recording
                  recorder.startRecording();

              });

              addStreamStopListener(screen, function() {
                  btnStopRecording.click();
              });
          });
      }

      var btnStopRecording = document.getElementById('stoprecording');
      btnStopRecording.onclick = function() {
          this.disabled = true;

          recorder.stopRecording(function() {
              var blob = recorder.getBlob();
              screenRec.getTracks().concat(micRec.getTracks()).forEach(function(track) {
                  track.stop();
              });
              invokeSaveAsDialog(blob, 'video.webm');
          });
      };

      var btnStartRecording = document.getElementById('startrecording');
      btnStartRecording.onclick = function() {
          this.disabled = true;

          OnLoadedMetaData();

      };

      function addStreamStopListener(stream, callback) {
          var streamEndedEvent = 'ended';
          if ('oninactive' in stream) {
              streamEndedEvent = 'inactive';
          }
          stream.addEventListener(streamEndedEvent, function() {
              callback();
              callback = function() {};
          }, false);
          stream.getAudioTracks().forEach(function(track) {
              track.addEventListener(streamEndedEvent, function() {
                  callback();
                  callback = function() {};
              }, false);
          });
          stream.getVideoTracks().forEach(function(track) {
              track.addEventListener(streamEndedEvent, function() {
                  callback();
                  callback = function() {};
              }, false);
          });
      }
    </script>
  </body>
</html>

Dont think it could be used properly with Electron for production.