summaryrefslogtreecommitdiffstats
path: root/dom/media/mediasource/test/test_PlayEvents.html
blob: a390ae247b7f1dc9b4f2937246da9b64a1168dc4 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<!DOCTYPE HTML>
<html>
<head>
  <title>MSE: basic functionality</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="mediasource.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">

SimpleTest.waitForExplicitFinish();

// This test checks that readyState is properly set and the appropriate events are being fired accordingly:
// 1. Load 1.6s of data and ensure that canplay event is fired.
// 2. Load data to have a complete buffered range from 0 to duration and ensure that canplaythrough is fired.
// 3. Seek to an area with no buffered data, and ensure that readyState goes back to HAVE_METADATA
// 4. Load 1.6s of data at the seek position and ensure that canplay is fired and that readyState is now HAVE_FUTURE_DATA
// 5. Start playing video and check that once it reaches a position with no data, readyState goes back to HAVE_CURRENT_DATA and waiting event is fired.
// 6. Add 1.6s of data once video element fired waiting, that canplay is fired once readyState is HAVE_FUTURE_DATA.
// 7. Finally load data to the end and ensure that canplaythrough is fired and that readyState is now HAVE_ENOUGH_DATA

runWithMSE(function(ms, el) {
  el.controls = true;
  once(ms, 'sourceopen').then(function() {
    // Log events for debugging.
    var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
                  "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
                  "waiting", "pause", "durationchange", "seeking", "seeked"];
    function logEvent(e) {
      var v = e.target;
      info("got " + e.type + " event");
    }
    events.forEach(function(e) {
      el.addEventListener(e, logEvent, false);
    });

    ok(true, "Receive a sourceopen event");
    var videosb = ms.addSourceBuffer("video/mp4");
    el.addEventListener("error", function(e) {
      ok(false, "should not fire '" + e + "' event");
    });
    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
    fetchAndLoad(videosb, 'bipbop/bipbop_video', ['init'], '.mp4')
    .then(once.bind(null, el, 'loadedmetadata'))
    .then(function() {
       ok(true, "got loadedmetadata event");
       var promises = [];
       promises.push(once(el, 'loadeddata'));
       promises.push(once(el, 'canplay'));
       promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(1, 3), '.m4s'));
       return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got canplay event");
      // set element duration to 3.203333s. We do so in order to guarantee that
      // the end of the buffered range will be equal to duration, causing
      // canplaythrough to be fired later.
      ms.duration = 3.203333;
      return once(el, 'durationchange');
    })
    .then(function() {
      ok(true, "got durationchange event");
      var promises = [];
      promises.push(once(el, 'canplaythrough'));
      // Load [0.801666, 3.203333]
      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(3, 5), '.m4s'));
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got canplaythrough event");
     // set element duration to 9.203333s, this value is set to coincide with
     // data added later (we now have an empty range from 6s to 9.203333s).
     ms.duration = 9.203333;
     return once(el, 'durationchange');
    })
    .then(function() {
      ok(true, "got durationchange event");
      // An arbitrary value, so we are guaranteed to be in a range with no data.
      el.currentTime = 6;
      videosb.timestampOffset = 6;
      ok(el.seeking, "seeking started");
      return once(el, 'seeking');
    })
    .then(function() {
      ok(true, "got seeking event");
      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
      var promises = [];
      promises.push(once(el, 'seeked'));
      promises.push(once(el, 'canplay'));
      // Load [6+0, 6+1.601666)
      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(1, 3), '.m4s'));
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got seeked and canplay event");
      is(el.currentTime, 6, "seeked to 6s");
      is(el.readyState, el.HAVE_FUTURE_DATA, "readyState is HAVE_FUTURE_DATA");
      var promises = [];
      promises.push(once(el, 'canplaythrough'));
      // Load [6+1.60166, 6+3.203333]
      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(3, 5), '.m4s'));
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got canplaythrough event");
      // set element duration to 19.805s, this value is set to coincide with
      // data added later (we now have an empty range from 15 to 19.805).
      ms.duration = 19.805;
      return once(el, 'durationchange');
    })
    .then(function() {
      ok(true, "got durationchange event");
      el.currentTime = 15;
      videosb.timestampOffset = 15;
      ok(el.seeking, "seeking started");
      return once(el, 'seeking');
    })
    .then(function() {
      ok(true, "got seeking event");
      var promises = [];
      promises.push(once(el, 'seeked'));
      // Load [15+0, 15+1.601666)
      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(1, 3), '.m4s'));
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got seeked event");
      // Load [15+1.60166, 15+3.203333]
      return fetchAndLoad(videosb, 'bipbop/bipbop_video', range(3, 5), '.m4s');
    })
    .then(function() {
      ok(true, "data loaded");
      // Playback we play for a little while then stall.
      var promises = [];
      promises.push(once(el, 'playing'));
      promises.push(once(el, 'waiting'));
      el.play();
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got playing and waiting event");
      // Playback has stalled, readyState is back to HAVE_CURRENT_DATA.
      is(el.readyState, el.HAVE_CURRENT_DATA, "readyState is HAVE_CURRENT_DATA");
      var promises = [];
      promises.push(once(el, 'playing'));
      promises.push(once(el, 'canplay'));
      promises.push(once(el, 'canplaythrough'));
      // Load [15+3.203333, 15+4.805)
      // Our final buffered range will now be [0, 3.203333)[6, 9.203333)[15, 19.805)
      promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(5, 7), '.m4s'));
      return Promise.all(promises);
    })
    .then(function() {
      ok(true, "got playing, canplay and canplaythrough event");
      SimpleTest.finish();
    })
  });
});

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