cincheo / jsweet

A Java to JavaScript transpiler.
http://www.jsweet.org
Other
1.45k stars 160 forks source link

jsweet.dom.Globals.navigator missing 'mediaDevices' #444

Open cwoodward opened 6 years ago

cwoodward commented 6 years ago

While attempting to integrate webcam support into my JSweet app I noticed that jsweet.dom.Globals.navigator is missing the mediaDevices field. I'm not sure if it was omitted due to a lack of universal browser support (missing from opera and safari (webkit) https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices ).

I tried accessing the mediaDevices field via jsweet.util.Lang.object(..)

object(navigator).$get("mediaDevices")

but is fails during tsc with:

Error: type 'MediaDevices' cannot be converted to type 'any[]' ...

The javascript code I'm trying to duplicate is minimal:

if ( navigator.mediaDevices && navigator.mediaDevices.getUserMedia ) {
 var constraints = { video: { width: 1280, height: 720, facingMode: 'user' } };
 navigator.mediaDevices.getUserMedia( constraints ).then( function( stream ) {
   // apply the stream to the video element 
   video.src = window.URL.createObjectURL( stream );
   video.play();
  } ).catch( function( error ) {
   console.error( 'Unable to access the camera/webcam.', error );
 } );
} else {
 console.error( 'MediaDevices interface not available.' );
}

What would be the easiest way to achieve this using existing JSweet constructs?

cwoodward commented 6 years ago

I have found a workable solution. It is probably suboptimal and I welcome any suggested improvements.

// access webcam

// define the html video element
HTMLVideoElement video = (HTMLVideoElement) document.getElementById("video");

// define the constraints passed to configure the webcam
def.js.Object constraints = new def.js.Object(){{ $set("video", true); }};
console.log(constraints);
// get the mediaDevices instance
def.js.Object mediaDevices =object(navigator).$get("mediaDevices");
console.log("mediaDevice",mediaDevices);
// get the getUserMedia function
def.js.Function f=object(mediaDevices).$get("getUserMedia");
// call the function with the mediaDevices object context
(( jsweet.lang.PromiseLike) f.call(mediaDevices,constraints)).thenOnfulfilledFunction(new java.util.function.Function() {
            @Override
            public Object apply(Object stream) {
                video.$set("srcObject", stream);
                return null;
            }
        });

Note that if you are running in Chrome a DOMException : only secure origins allowed

will be raised if it is not run from localhost or via https

lgrignon commented 6 years ago

Indeed this is not perfect but ir works. I would write an interface MediaDevices and cast the return of $get("mediaDevices") in order to clarify this. It would be more straightforward and typed. If you use the last version of the es6 core candy, you will also see that the Promise API was enhanced!

lgrignon commented 6 years ago

@cwoodward Is it all good for you? Can we close this?