Re: [mediacapture-main] Restore the active/inactive events on MediaStream (#370)

This issue may be old, but nowadays it's "easy" to determine when a `MediaStream` has completely ended by using this "hack":

```js
function addTrackListener(stream, track) {
  track.addEventListener('ended', () => {
      const allTracksEnd = stream.getTrackById(track.id) && stream.getTracks().every(trackX => trackX.readyState === 'ended');
      if (stream.ended && !allTracksEnd) return;
      stream.ended = true;
      stream.dispatchEvent(new Event('ended'));
  });
}


stream.addEventListener('addtrack', (event) => {
  addTrackListener(stream, event.track);
});

stream.getTracks().forEach(track => {
    addTrackListener(stream, track);
});
```
However, this could be done natively when all tracks have ended, perhaps?

The code above takes into account that each track needs to be attached to the `MediaStream`, and that the `readyState` is 'ended'. This simple verification of the 'ended' event in the `MediaStreamTrack` helps to avoid false positives for a `MediaStream` being 'ended' if the original MediaStreamTracks are removed using `MediaStream.removeTrack` and then stopped. Additionally, setting `stream.ended` to true helps avoid duplicate 'ended' events for each track.

The issue arises when you obtain a `MediaStream` and then add a `MediaStreamTrack` using `addTrack`. This is when it becomes necessary to attach listeners to the new `MediaStreamTrack`. So, a comprehensive "polyfill" could be:


```js
class MediaStreamPolyfill extends MediaStream {

  constructor(mediaStreamTracks) {
    super(mediaStreamTracks);
    this.getTracks().forEach(this.constructor.attachListeners.bind(this));
  }

  addTrack(track) {
    super.addTrack(track);
    this.constructor.attachListeners.call(this, track);
  }
  
  removeTrack(track) {
    super.removeTrack(track);
    this.constructor.attachListeners.call(this, track);
  }

  static attachListeners(track) {
    track.addEventListener('ended', () => {
        const allTracksEnd = this.getTrackById(track.id) && this.getTracks().every(trackX => trackX.readyState === 'ended');
        if (this.ended && !allTracksEnd) return;
        this.ended = true;
        this.dispatchEvent(new CustomEvent('ended'));
    });
  }

}
```
Although it is a hack, it is not bulletproof for all use cases; however, it is very useful in various situations.

-- 
GitHub Notification of comment by matiaslopezd
Please view or discuss this issue at https://github.com/w3c/mediacapture-main/issues/370#issuecomment-1493448156 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Sunday, 2 April 2023 21:50:32 UTC