0

I am writing a desktop application in Angular 9 using Electron as framework. I would like to add ability to capture video of the entire desktop as well as the audio input.

I have already tried to harness the RecordRTC library, and it does record video with audio, but not of my desktop, but of the web camera.

It is heavily underdocumented for Angular, and Electron's documentation is missing a working example.

There are problems with MediaStreams in Angular, and unfortunatelly the RecordRTC's examples are all written in JS, which is a mess of its own...

I would really appreciate a detailed, working solution. All I want is: 1. Press a button to start recording 2. Record the desktop video with audio 3. Press another button and stop the recording 4. Save the video as file using Electron's openSaveDialog.

I don't want the ability to choose which window do I want to record, and I would like to keep the webcamera turned off.

Thanks!

  • Have you tried [Electron desktopCapturer](https://www.electronjs.org/docs/api/desktop-capturer) and [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)? – DGarvanski May 26 '20 at 13:23
  • Yes. But the give examples are obsolete. The getUserMedia returns the audio input and the webcam, but I don't want webcam access, but rather a screen capturing, which is provided by RecordRTC's getDisplayMedia, which is missing in Electron. I really need a working example for Angular + Electron. – user3071120 May 26 '20 at 19:36
  • It is literally nothing written about how to start, stop the recording, and what to do (and how) with the captured blob data. It is too bad... I searching the net since two days. I've even managed to do the job with RecordRTC in Chrome, with getDIsplayMedia, but off course it doesn't work inside Electron... – user3071120 May 26 '20 at 19:44
  • Here's something that could help more with that: https://stackoverflow.com/questions/36753288/saving-desktopcapturer-to-video-file-in-electron – DGarvanski May 27 '20 at 07:55

1 Answers1

2

This is how i've solved the problem on Angular 9. Using ngx-electron.

declare var MediaRecorder: any; // Before the @Component({ declaration
...
 public recorder;  
  public recordedChunks = [];
  public isRecording = false;
  public recImage = 'assets/cameraOff.png';

...

  startRecording() {
    this.recordedChunks = [];
    this.electronService.desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
      for (const source of sources) {
        if (source.name === 'Teacher') {
          try {
            const stream = await (<any>navigator).mediaDevices.getUserMedia({
              audio: false,
              video: {
                mandatory: {
                  chromeMediaSource: 'desktop',
                  chromeMediaSourceId: source.id,
                  minWidth: 1280,
                  maxWidth: 1280,
                  minHeight: 720,
                  maxHeight: 720
                }
              }
            });
            this.handleStream(stream);
          } catch (e) {
            this.handleError(e);
          }
          return;
        }
      }
    });
  }

  handleStream(stream) {
    this.recorder = new MediaRecorder(stream);

    this.recorder.ondataavailable = event => {
      this.recordedChunks.push(event.data);
    };
    this.recorder.start();
  }

  handleError(e) {
    console.log(e);
  }

  stopRecording() {
    this.recorder.onstop = () => this.save();
    this.recorder.stop();

  }

  save() {
    this.toArrayBuffer(new Blob(this.recordedChunks, { type: 'video/webm' }), (ab) => {
      const buffer = this.toBuffer(ab);
      let moviePath = this.electronService.remote.dialog.showSaveDialogSync({
        properties: ['showOverwriteConfirmation'],
        filters: [{ name: 'WEBM movies', extensions: ['webm'] }],
        defaultPath: this.electronService.remote.app.getPath('home')
      });
      if (moviePath !== '') {
        moviePath += '.webm';
        this.electronService.remote.require('fs').writeFileSync(moviePath, buffer, 'base64');
      }
    });
  }

  toBuffer(ab) {
    const buffer = Buffer.from(ab);
    const arr = new Uint8Array(ab);
    for (let i = 0; i < arr.byteLength; i++) {
      buffer[i] = arr[i];
    }
    return buffer;
  }

  toArrayBuffer(blob, cb) {
    const fileReader = new FileReader();
    fileReader.onload = () => {
      const arrayBuffer = fileReader.result;
      cb(arrayBuffer);
    };
    fileReader.readAsArrayBuffer(blob);
  }

  toggleRecording() {
    if (!this.isRecording) {
      this.isRecording = true;
      this.startRecording();
      this.recImage = 'assets/cameraOn.png';
      return;
    } else {
      this.isRecording = false;
      this.stopRecording();
      this.recImage = 'assets/cameraOff.png';
      return;
    }
  }

It hopefully helps to somebody! It is still not perfect. I could not turn on the audio recording. And it seems, that the recorder is not released after saving. I manage to record a video, then it fails for several times. It is not stable at all...