summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mediacapture-streams/MediaStream-removetrack.https.html
blob: 6c9b9b02e3f200219d67637871ab59ca9a821ecd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!doctype html>
<html>
<head>
<title>Removing a track from a MediaStream</title>
<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrackList-remove-void-MediaStreamTrack-track">
<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#event-mediastream-removetrack">
</head>
<body>
<p class="instructions">When prompted, accept to share your audio stream, then your video stream.</p>
<h1 class="instructions">Description</h1>
<p class="instructions">This test checks that removinging a track from a MediaStream works as expected.</p>
<video id="video" height="120" width="160" autoplay muted></video>
<audio id="audio" autoplay muted></audio>
<div id='log'></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src=permission-helper.js></script>
<script>

promise_test(async t => {
  await setMediaPermission();
  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
  const tracks = stream.getTracks();
  t.add_cleanup(() => tracks.forEach(track => track.stop()));
  const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
  tracks.push(...stream2.getTracks());

  stream.onremovetrack = stream2.onremovetrack = t.step_func(() =>
    assert_unreached("onremovetrack is not triggered by script itself"));

  assert_equals(stream.getTracks().length, 2, "mediastream starts with 2 tracks");
  stream.removeTrack(stream.getVideoTracks()[0]);
  assert_equals(stream.getTracks().length, 1, "mediastream has 1 track left");
  stream.removeTrack(stream.getAudioTracks()[0]);
  assert_equals(stream.getTracks().length, 0, "mediastream has no tracks left");
  stream.removeTrack(stream2.getTracks()[0]); // should not throw

  // Allow time to verify no events fire.
  await new Promise(r => t.step_timeout(r, 1));

}, "Tests that a removal from a MediaStream works as expected");

async function doesEventFire(t, target, name, ms = 1) {
  const cookie = {};
  const value = await Promise.race([
    new Promise(r => target.addEventListener(name, r, {once: true})),
    new Promise(r => t.step_timeout(r, ms)).then(() => cookie)
  ]);
  return value !== cookie;
}

const doEventsFire = (t, target1, target2, name, ms = 1) => Promise.all([
  doesEventFire(t, target1, "ended", ms),
  doesEventFire(t, target2, "ended", ms)
]);

promise_test(async t => {
  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
  const tracks = stream.getTracks();

  audio.srcObject = video.srcObject = stream;

  t.add_cleanup(() => {
    for (const track of tracks) {
      track.stop();
    }
    audio.srcObject = video.srcObject = null;
  });

  await Promise.all([
    new Promise(r => audio.onloadedmetadata = r),
    new Promise(r => video.onloadedmetadata = r)
  ]);

  assert_equals(audio.ended, false, "audio element starts out not ended");
  assert_equals(video.ended, false, "video element starts out not ended");

  stream.removeTrack(stream.getVideoTracks()[0]);
  {
    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
    assert_equals(audio.ended, false, "audio element unaffected");
    assert_equals(audioDidEnd, false, "no audio ended event should fire yet");
    assert_equals(video.ended, false, "video element keeps going with audio track");
    assert_equals(videoDidEnd, false, "no video ended event should fire yet");
  }
  stream.removeTrack(stream.getAudioTracks()[0]);
  {
    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
    assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
    assert_equals(audioDidEnd, true, "go audio ended event");
    assert_equals(video.ended, true, "video element ended because no more tracks");
    assert_equals(videoDidEnd, true, "got video ended event");
  }
}, "Test that removal from a MediaStream fires ended on media elements (video first)");

promise_test(async t => {
  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
  const tracks = stream.getTracks();

  audio.srcObject = video.srcObject = stream;

  t.add_cleanup(() => {
    for (const track of tracks) {
      track.stop();
    }
    audio.srcObject = video.srcObject = null;
  });

  await Promise.all([
    new Promise(r => audio.onloadedmetadata = r),
    new Promise(r => video.onloadedmetadata = r)
  ]);

  assert_equals(audio.ended, false, "audio element starts out not ended");
  assert_equals(video.ended, false, "video element starts out not ended");

  stream.removeTrack(stream.getAudioTracks()[0]);
  {
    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
    assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
    assert_equals(audioDidEnd, true, "got audio ended event");
    assert_equals(video.ended, false, "video element keeps going with video track");
    assert_equals(videoDidEnd, false, "no video ended event should fire yet");
  }
  stream.removeTrack(stream.getVideoTracks()[0]);
  {
    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
    assert_equals(audio.ended, true, "audio element remains ended from before");
    assert_equals(audioDidEnd, false, "no second audio ended event should fire");
    assert_equals(video.ended, true, "video element ended because no more tracks");
    assert_equals(videoDidEnd, true, "got video ended event");
  }
}, "Test that removal from a MediaStream fires ended on media elements (audio first)");

</script>
</body>
</html>