Search code examples
javascriptcanvasmediastreammediastreamtrack

Extra property of CanvasCaptureMediaStreamTrack


I have a canvas that I want to have it's stream and send it to another user by webrtc. I can get the stream of it and show that in video tag.

var canvas = document.createElement("CANVAS");
var stream = canvas.captureStream(25);
var track = stream.getVideoTracks()[0];
console.log(track);

As you can see in track Object there is a property named canvas. It causes an Error in my code because I use a library that need a MediaStreamTrack not MediaStreamTrack that contains a canvas property. Is there a way to get rid of that canvas property?

I've already tried delete the property but it didn't work. And also I used this below code but still doesn't work.

var canvas = document.createElement("CANVAS");
var stream = canvas.captureStream(25);
var track = stream.getVideoTracks()[0];

var {canvas, ...rest} = track;

console.log(canvas);
console.log(rest);

I think the CanvasCaptureMediaStreamTrack is a readOnly variable. What can I do?


Solution

  • It would probably be good to update your library, because if it fails because of that added property, it will fail again some time in the future when new properties will be added to this interface.

    You can overwrite this property and set it to undefined, using Object.defineProperty:

    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const stream = canvas.captureStream(25);
    const track = stream.getVideoTracks()[0];
    Object.defineProperty( track, "canvas", { value: undefined } );
    
    console.log( track.canvas, "canvas" in track ); // undefined true

    You can delete this property on the CanvasCaptureMediaStreamTrack prototype (and thus remove it from all instances):

    if( window.CanvasCaptureMediaStreamTrack ) {
      delete CanvasCaptureMediaStreamTrack.prototype.canvas
    }
    else { // Firefox has this property on `stream`
      delete CanvasCaptureMediaStream.prototype.canvas;
    }
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const stream = canvas.captureStream(25);
    const track = stream.getVideoTracks()[0];
    
    console.log( track.canvas, "canvas" in track ); // undefined false

    You could even pass a Proxy instead,

    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const stream = canvas.captureStream(25);
    const track = stream.getVideoTracks()[0];
    const prox = new Proxy( track, {
      get( target, key ) {
        if( key === "canvas" ) {
          return undefined;
        }
        return target[ key ];
      }
    });
    console.log( prox.canvas, "canvas" in prox, prox.kind ); // undefined false video

    But really, that you have to resort on this is just very bad smell. For one I highly doubt that your library will work with current Firefox which still uses a deprecated CanvasCaptureMediaStream interface instead of the CanvasCaptureMediaStreamTrack one.

    And if you really need to convert a CanvasCaptureMediaStreamTrack to a bare MediaStreamTrack, then you can make the browser work twice as needed:

    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const stream = canvas.captureStream(25);
    // we need to draw something on the canvas
    // for the <video> to start reading our MediaStream
    ctx.fillRect(10,10,10,10);
    
    const video = document.createElement("video");
    video.muted = true;
    video.srcObject = stream;
    video.play().then(() => {
      const video_stream = video.captureStream ? video.captureStream() :
        video.mozCaptureStream();
      const track = video_stream.getVideoTracks()[0]
      console.log( track.toString(), track ); // [object MediaStreamTrack], {...}
    }).catch(console.error);