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

excaliburjs / Excalibur / 18842529445

27 Oct 2025 01:24PM UTC coverage: 88.6% (-0.006%) from 88.606%
18842529445

push

github

web-flow
chore(deps-dev): bump tar-fs from 3.1.0 to 3.1.1 (#3521)

Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 3.1.0 to 3.1.1.
- [Commits](https://github.com/mafintosh/tar-fs/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-version: 3.1.1
  dependency-type: indirect
...

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

5254 of 7154 branches covered (73.44%)

14425 of 16281 relevant lines covered (88.6%)

24349.53 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) => {
16✔
29
      if (WebAudio._UNLOCKED || !AudioContextFactory.create()) {
16✔
30
        return resolve(true);
15✔
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;
16✔
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

© 2026 Coveralls, Inc