summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js
blob: 87186ca838617f5d00e6ab421ff1956083e64b6a (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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/**
 * When media changes its audible state, the sound indicator should be
 * updated as well, which should appear only when web audio is audible.
 */
add_task(async function testUpdateSoundIndicatorWhenMediaPlaybackChanges() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audio.ogg");

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when audio stops playing`);
  await pauseMedia(tab);
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testUpdateSoundIndicatorWhenMediaBecomeSilent() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audioEndedDuringPlaying.webm");

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when audio becomes silent`);
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorWouldWorkForMediaWithoutPreload() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audio.ogg", { preload: "none" });

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when audio stops playing`);
  await pauseMedia(tab);
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorShouldDisappearAfterTabNavigation() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audio.ogg");

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear after navigating tab to blank page`);
  BrowserTestUtils.loadURIString(tab.linkedBrowser, "about:blank");
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorForAudioStream() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaStreamPlaybackDocument(tab);

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when audio stops playing`);
  await pauseMedia(tab);
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testPerformPlayOnMediaLoadingNewSource() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audio.ogg");

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when audio stops playing`);
  await pauseMedia(tab);
  await waitForTabSoundIndicatorDisappears(tab);

  info(`reset media src and play it again should make sound indicator appear`);
  await assignNewSourceForAudio(tab, "audio.ogg");
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorShouldDisappearWhenAbortingMedia() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab();
  await initMediaPlaybackDocument(tab, "audio.ogg");

  info(`sound indicator should appear when audible audio starts playing`);
  await playMedia(tab);
  await waitForTabSoundIndicatorAppears(tab);

  info(`sound indicator should disappear when aborting audio source`);
  await assignNewSourceForAudio(tab, "");
  await waitForTabSoundIndicatorDisappears(tab);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testNoSoundIndicatorForMediaWithoutAudioTrack() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab({ needObserver: true });
  await initMediaPlaybackDocument(tab, "noaudio.webm", { createVideo: true });

  info(`no sound indicator should show for playing media without audio track`);
  await playMedia(tab, { resolveOnTimeupdate: true });
  ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator");

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorWhenChangingMediaMuted() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab({ needObserver: true });
  await initMediaPlaybackDocument(tab, "audio.ogg", { muted: true });

  info(`no sound indicator should show for playing muted media`);
  await playMedia(tab, { resolveOnTimeupdate: true });
  ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator");

  info(`unmuted media should make sound indicator appear`);
  await Promise.all([
    waitForTabSoundIndicatorAppears(tab),
    updateMedia(tab, { muted: false }),
  ]);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

add_task(async function testSoundIndicatorWhenChangingMediaVolume() {
  info("create a tab loading media document");
  const tab = await createBlankForegroundTab({ needObserver: true });
  await initMediaPlaybackDocument(tab, "audio.ogg", { volume: 0.0 });

  info(`no sound indicator should show for playing volume zero media`);
  await playMedia(tab, { resolveOnTimeupdate: true });
  ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator");

  info(`unmuted media by setting volume should make sound indicator appear`);
  await Promise.all([
    waitForTabSoundIndicatorAppears(tab),
    updateMedia(tab, { volume: 1.0 }),
  ]);

  info("remove tab");
  BrowserTestUtils.removeTab(tab);
});

/**
 * Following are helper functions
 */
function initMediaPlaybackDocument(
  tab,
  fileName,
  { preload, createVideo, muted = false, volume = 1.0 } = {}
) {
  return SpecialPowers.spawn(
    tab.linkedBrowser,
    [fileName, preload, createVideo, muted, volume],
    // eslint-disable-next-line no-shadow
    async (fileName, preload, createVideo, muted, volume) => {
      if (createVideo) {
        content.media = content.document.createElement("video");
      } else {
        content.media = content.document.createElement("audio");
      }
      if (preload) {
        content.media.preload = preload;
      }
      content.media.muted = muted;
      content.media.volume = volume;
      content.media.src = fileName;
    }
  );
}

function initMediaStreamPlaybackDocument(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
    content.media = content.document.createElement("audio");
    content.media.srcObject =
      new content.AudioContext().createMediaStreamDestination().stream;
  });
}

function playMedia(tab, { resolveOnTimeupdate } = {}) {
  return SpecialPowers.spawn(
    tab.linkedBrowser,
    [resolveOnTimeupdate],
    // eslint-disable-next-line no-shadow
    async resolveOnTimeupdate => {
      await content.media.play();
      if (resolveOnTimeupdate) {
        await new Promise(r => (content.media.ontimeupdate = r));
      }
    }
  );
}

function pauseMedia(tab) {
  return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
    content.media.pause();
  });
}

function assignNewSourceForAudio(tab, fileName) {
  // eslint-disable-next-line no-shadow
  return SpecialPowers.spawn(tab.linkedBrowser, [fileName], async fileName => {
    content.media.src = "";
    content.media.removeAttribute("src");
    content.media.src = fileName;
  });
}

function updateMedia(tab, { muted, volume } = {}) {
  return SpecialPowers.spawn(
    tab.linkedBrowser,
    [muted, volume],
    // eslint-disable-next-line no-shadow
    (muted, volume) => {
      if (muted != undefined) {
        content.media.muted = muted;
      }
      if (volume != undefined) {
        content.media.volume = volume;
      }
    }
  );
}