1

What I'm trying to do:

First question here, sorry for any mistakes.

Basically what I want to do is implement filters for the webcam so that everyone you are in a video conference/call/meeting with can see it if you have webcam on. My first thought was to use CSS filters, which was stupid in hindsight, since it won't be seen by everybody.

Then I did some research(say, googling) and found out about a similar WebExtension, ZomboCam,(whose source I saw with crxviewer) which, basically intercepts the mediaStream, edits it, and sets the edited mediaStream as source of your webcam. I looked at its source, and found out that it Monkey Patches (or is it monkeypatches) the getUserMedia() function. In the source,

var originalMediaDevicesGetUserMedia = navigator.mediaDevices.getUserMedia;
if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia = function getUserMedia(constraints) {
          return new Promise(function (resolve, reject) {
            originalMediaDevicesGetUserMedia.bind(navigator.mediaDevices)(constraints).then(function (stream) {
              return resolve(enhance(stream));
            }).catch(reject);
          });
        };
      }

The enhance() function works on a mediaStream passed to it as parameter.

What I tried:

I did the monkeypatching code in the content script of the WebExtension, if that helps.

I tried monkeypatching like this, in a webpage with a video element to display the webcam. It reached the Video devices found!, but not any further.

change() will be my function to work on mediaStream(any helpful tips for that?), and it doesn't do anything as of now.

const OGgum =  navigator.mediaDevices.getUserMedia;
    if(navigator.mediaDevices.getUserMedia){
        console.log('Video devices found!');
        navigator.mediaDevices.getUserMedia = (constraints) => {
            OGgum(constraints).then((stream)=> {
              console.log('gum Patched');
              video.srcObject = change(stream);
            })
            .catch((error)=>{
              console.log('This Went wrong: '+error);
            })
          }
    }
    const change = (st) => {
      return st;
    }

Now with the disappointment of that not working, I tried monkey patching console.log() in the content script of the webextension to add some text in front of every log, like this:

const OGlog = console.log;
console.log = (params) => {
  OGlog(' PATCHING: '+params);
}

console.log('Testing');

Outputs:

 PATCHING: Testing

which WORKED but ONLY for console.log() INSIDE the content script. How do I make it work for every page? Meaning, suppose I do a console.log(), I expect it to have PATCHING in front.

I supposed if I manage to get console.log() to work, I can probably work on the getUserMedia() myself.

Relevant Reading

What am I missing here? Also if you have alternatives for this task, please share them. Thanks!

sadn1ck
  • 11
  • 1
  • 1

1 Answers1

0

In Firefox you should use wrappedJSObject to access the page context and exportFunction to expose your code into the page context. More info on MDN: Sharing objects with page scripts.

const pWindow = window.wrappedJSObject;
const pMediaDevices = pWindow.navigator.mediaDevices;
const pGUM = pMediaDevices.getUserMedia;
const myGUM = (...args) =>
  pGUM.apply(pMediaDevices, args).then(stream => {
    // .........
    return stream;
  });
pMediaDevices.getUserMedia = exportFunction(myGUM, pWindow);

If you thought it's complicated, in Chrome/Chromium browsers it's even worse.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • Thanks for this but is there any other way? I was trying to make it compatible b/w chrome and firefox, but this will require two different builds. Sorry for the late reply. – sadn1ck Jun 09 '20 at 05:05
  • Simply check the browser and use the "even worse" approach at the bottom of the answer. – wOxxOm Jun 09 '20 at 06:18