• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 20436984996

22 Dec 2025 03:55PM UTC coverage: 88.632%. Remained the same
20436984996

push

github

web-flow
chore(deps): bump express from 4.21.2 to 4.22.1 in /site (#3610)

Bumps [express](https://github.com/expressjs/express) from 4.21.2 to 4.22.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

5328 of 7279 branches covered (73.2%)

14735 of 16625 relevant lines covered (88.63%)

24691.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/src/engine/Util/WebAudio.ts
1
import { AudioContextFactory } from '../Resources/Sound/AudioContext';
2
import { Logger } from './Log';
3

4
export interface LegacyWebAudioSource {
5
  playbackState: string;
6
  PLAYING_STATE: 'playing';
7
  FINISHED_STATE: 'finished';
8
}
9

10
/**
11
 * Patch for detecting legacy web audio in browsers
12
 * @internal
13
 * @param source
14
 */
15
function isLegacyWebAudioSource(source: any): source is LegacyWebAudioSource {
16
  return !!source.playbackState;
1✔
17
}
18

19
export class WebAudio {
248✔
20
  private static _UNLOCKED: boolean = false;
21

22
  /**
23
   * Play an empty sound to unlock Safari WebAudio context. Call this function
24
   * right after a user interaction event.
25
   * @source https://paulbakaus.com/tutorials/html5/web-audio-on-ios/
26
   */
27
  static unlock(): Promise<boolean> {
28
    const promise = new Promise<boolean>((resolve, reject) => {
17✔
29
      if (WebAudio._UNLOCKED || !AudioContextFactory.create()) {
17✔
30
        return resolve(true);
16✔
31
      }
32
      const unlockTimeoutTimer = setTimeout(() => {
1✔
33
        Logger.getInstance().warn('Excalibur was unable to unlock the audio context, audio probably will not play in this browser.');
×
34
        resolve(false);
×
35
      }, 200);
36

37
      const audioContext = AudioContextFactory.create();
1✔
38
      audioContext.resume().then(
1✔
39
        () => {
40
          // create empty buffer and play it
41
          const buffer = audioContext.createBuffer(1, 1, 22050);
1✔
42
          const source = audioContext.createBufferSource();
1✔
43
          let ended = false;
1✔
44

45
          source.buffer = buffer;
1✔
46
          source.connect(audioContext.destination);
1✔
47
          source.onended = () => (ended = true);
1✔
48

49
          source.start(0);
1✔
50

51
          // by checking the play state after some time, we know if we're really unlocked
52
          setTimeout(() => {
1✔
53
            if (isLegacyWebAudioSource(source)) {
1!
54
              if (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE) {
×
55
                WebAudio._UNLOCKED = true;
×
56
              }
57
            } else {
58
              if (audioContext.currentTime > 0 || ended) {
1!
59
                WebAudio._UNLOCKED = true;
×
60
              }
61
            }
62
          }, 0);
63

64
          clearTimeout(unlockTimeoutTimer);
1✔
65
          resolve(true);
1✔
66
        },
67
        () => {
68
          reject();
×
69
        }
70
      );
71
    });
72

73
    return promise;
17✔
74
  }
75

76
  static isUnlocked() {
77
    return this._UNLOCKED;
×
78
  }
79
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc