为什么没有为此MediaStreamTrack触发“结束"事件? [英] Why is the 'ended' event not firing for this MediaStreamTrack?

查看:758
本文介绍了为什么没有为此MediaStreamTrack触发“结束"事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道MediaStreamTrack的结尾.根据 MDN ,事件是

在曲目的播放结束时发送(当值readyState更改为ended时发送). 也可以通过onended事件处理程序属性使用.

所以我应该能够设置我的回调,例如:

const [track] = stream.getVideoTracks();
track.addEventListener('ended', () => console.log('track ended'));
track.onended = () => console.log('track onended');

我希望一旦我通过以下方式停止跟踪,就会调用它们:

tracks.forEach(track => track.stop());
// for good measure? See
// https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/stop#Stopping_a_video_stream
videoElem.srcObject = null;

我遇到的问题是未调用回调.我构建了以下 JSFiddle ,其中以3种不同方式创建了3个MediaStream:

  1. getUserMedia
  2. getDisplayMedia
  3. getCaptureStream (画布元素)

我还有3个按钮,用于停止各个MediaStream的所有曲目.行为如下:

  • 所有3个流均为inactive,并触发了MediaStream的oninactive回调(在Chrome浏览器中,似乎Firefox不支持此功能).
  • 所有曲目在停止后的readyState均为ended.
  • 如果我通过Chrome的UI停止屏幕流(2. getDisplayMedia),则会调用跟踪结束的回调.

我知道您必须当心多个来源正在使用的曲目,但是这里不应该是这样吗?我缺少明显的东西吗?

由于多个音轨可能使用同一音源(例如,如果两个选项卡正在使用设备的麦克风),则音源本身并不一定会立即停止.而是从轨道取消关联,并且停止跟踪对象.一旦没有媒体轨道在使用该源,则实际上该源可能会完全停止.

解决方案

为什么未为此MediaStreamTrack触发结束"事件?

因为已结束明确地是 <当您调用 track.stop()自己.仅在轨道由于其他原因而结束时才会触发.根据规格:

在...时触发

MediaStreamTrack对象的源将不再提供任何数据,这可能是因为用户撤消了权限,或者是因为源设备已被弹出,或者是由于远程对等端永久停止了发送数据.

这是设计使然.当时的想法是,当您自己停止事件时,您不需要事件.要解决此问题,请执行以下操作:

track.stop();
track.dispatchEvent(new Event("ended"));

MediaStream的oninactive回调被触发(在Chrome中,似乎Firefox不支持此回调.)

stream.oninactiveinactive事件已弃用,不再在规范中.

为此,您可以使用类似的已结束事件:

video.srcObject = stream;
await new Promise(resolve => video.onloadedmetadata = resolve);
video.addEventListener("ended", () => console.log("inactive!")); 

可惜,这似乎无法在Chrome浏览器中使用,但它在Firefox中可以使用./p>

I'd like to be informed about a MediaStreamTrack's end. According to MDN an ended event is

Sent when playback of the track ends (when the value readyState changes to ended). Also available using the onended event handler property.

So I should be able to setup my callback(s) like:

const [track] = stream.getVideoTracks();
track.addEventListener('ended', () => console.log('track ended'));
track.onended = () => console.log('track onended');

and I expect those to be invoked, once I stop the track via:

tracks.forEach(track => track.stop());
// for good measure? See
// https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/stop#Stopping_a_video_stream
videoElem.srcObject = null;

The problem I'm having is that the callbacks are not invoked. I built the following JSFiddle, where 3 MediaStreams are created in 3 different ways:

  1. getUserMedia
  2. getDisplayMedia
  3. getCaptureStream (canvas element)

I also have 3 buttons which stop all tracks for the respective MediaStream. The behaviour is as follows:

  • All 3 streams are inactive, the MediaStream's oninactive callback is triggered (in Chrome, seems like Firefox doesn't support this).
  • All tracks have a readyState of ended after being stopped.
  • If I stop the screen stream (2. getDisplayMedia) via Chrome's UI, the track ended callback(s) are invoked.

I know that you have to watch out for the track being used by multiple sources, but that shouldn't be the case here, right? Am I missing something obvious?

Since multiple tracks may use the same source (for example, if two tabs are using the device's microphone), the source itself isn't necessarily immediately stopped. It is instead disassociated from the track and the track object is stopped. Once no media tracks are using the source, the source may actually be completely stopped.

解决方案

Why is the 'ended' event not firing for this MediaStreamTrack?

Because ended is explicitly not fired when you call track.stop() yourself. It only fires when a track ends for other reasons. From the spec:

Fired when...

The MediaStreamTrack object's source will no longer provide any data, either because the user revoked the permissions, or because the source device has been ejected, or because the remote peer permanently stopped sending data.

This is by design. The thinking was you don't need an event when you stop it yourself. To work around it do:

track.stop();
track.dispatchEvent(new Event("ended"));

MediaStream's oninactive callback is triggered (in Chrome, seems like Firefox doesn't support this).

stream.oninactive and the inactive event are deprecated, and no longer in the spec.

As a workaround for that, you can use the similar ended event on a media element:

video.srcObject = stream;
await new Promise(resolve => video.onloadedmetadata = resolve);
video.addEventListener("ended", () => console.log("inactive!")); 

Alas, that does not appear to work in Chrome yet, but it works in Firefox.

这篇关于为什么没有为此MediaStreamTrack触发“结束"事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆