为什么没有为此MediaStreamTrack触发“结束"事件? [英] Why is the 'ended' event not firing for this 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:
我还有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.oninactive
和inactive
事件已弃用,不再在规范中.
为此,您可以使用类似的已结束事件:
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 toended
). Also available using theonended
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:
getUserMedia
getDisplayMedia
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'soninactive
callback is triggered (in Chrome, seems like Firefox doesn't support this). - All tracks have a
readyState
ofended
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屋!