summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacontrol/tests/browser/browser_media_control_position_state.js
blob: f32ce26063335ab1a523c07b5486c302f0af4c7d (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
const PAGE_URL =
  "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_non_autoplay.html";
const IFRAME_URL =
  "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_iframe_media.html";

const testVideoId = "video";

add_task(async function setupTestingPref() {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["media.mediacontrol.testingevents.enabled", true],
      ["dom.media.mediasession.enabled", true],
    ],
  });
});

/**
 * This test is used to check if we can receive correct position state change,
 * when we set the position state to the media session.
 */
add_task(async function testSetPositionState() {
  info(`open media page`);
  const tab = await createLoadedTabWrapper(PAGE_URL);

  info(`start media`);
  await playMedia(tab, testVideoId);

  info(`set duration only`);
  await setPositionState(tab, {
    duration: 60,
  });

  info(`set duration and playback rate`);
  await setPositionState(tab, {
    duration: 50,
    playbackRate: 2.0,
  });

  info(`set duration, playback rate and position`);
  await setPositionState(tab, {
    duration: 40,
    playbackRate: 3.0,
    position: 10,
  });

  info(`remove tab`);
  await tab.close();
});

add_task(async function testSetPositionStateFromInactiveMediaSession() {
  info(`open media page`);
  const tab = await createLoadedTabWrapper(PAGE_URL);

  info(`start media`);
  await playMedia(tab, testVideoId);

  info(
    `add an event listener to measure how many times the position state changes`
  );
  let positionChangedNum = 0;
  const controller = tab.linkedBrowser.browsingContext.mediaController;
  controller.onpositionstatechange = () => positionChangedNum++;

  info(`set position state on the main page which has an active media session`);
  await setPositionState(tab, {
    duration: 60,
  });

  info(`set position state on the iframe which has an inactive media session`);
  await setPositionStateOnInactiveMediaSession(tab);

  info(`set position state on the main page again`);
  await setPositionState(tab, {
    duration: 60,
  });
  is(
    positionChangedNum,
    2,
    `We should only receive two times of position change, because ` +
      `the second one which performs on inactive media session is effectless`
  );

  info(`remove tab`);
  await tab.close();
});

/**
 * The following are helper functions.
 */
async function setPositionState(tab, positionState) {
  const controller = tab.linkedBrowser.browsingContext.mediaController;
  const positionStateChanged = new Promise(r => {
    controller.addEventListener(
      "positionstatechange",
      event => {
        const { duration, playbackRate, position } = positionState;
        // duration is mandatory.
        is(
          event.duration,
          duration,
          `expected duration ${event.duration} is equal to ${duration}`
        );

        // Playback rate is optional, if it's not present, default should be 1.0
        if (playbackRate) {
          is(
            event.playbackRate,
            playbackRate,
            `expected playbackRate ${event.playbackRate} is equal to ${playbackRate}`
          );
        } else {
          is(event.playbackRate, 1.0, `expected default playbackRate is 1.0`);
        }

        // Position state is optional, if it's not present, default should be 0.0
        if (position) {
          is(
            event.position,
            position,
            `expected position ${event.position} is equal to ${position}`
          );
        } else {
          is(event.position, 0.0, `expected default position is 0.0`);
        }
        r();
      },
      { once: true }
    );
  });
  await SpecialPowers.spawn(
    tab.linkedBrowser,
    [positionState],
    positionState => {
      content.navigator.mediaSession.setPositionState(positionState);
    }
  );
  await positionStateChanged;
}

async function setPositionStateOnInactiveMediaSession(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [IFRAME_URL], async url => {
    info(`create iframe and wait until it finishes loading`);
    const iframe = content.document.getElementById("iframe");
    iframe.src = url;
    await new Promise(r => (iframe.onload = r));

    info(`trigger media in iframe entering into fullscreen`);
    iframe.contentWindow.postMessage("setPositionState", "*");
  });
}