-
-
Notifications
You must be signed in to change notification settings - Fork 188
/
WebAudio.ts
79 lines (68 loc) · 2.3 KB
/
WebAudio.ts
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
import { AudioContextFactory } from '../Resources/Sound/AudioContext';
import { Logger } from './Log';
export interface LegacyWebAudioSource {
playbackState: string;
PLAYING_STATE: 'playing';
FINISHED_STATE: 'finished';
}
/**
* Patch for detecting legacy web audio in browsers
* @internal
* @param source
*/
function isLegacyWebAudioSource(source: any): source is LegacyWebAudioSource {
return !!source.playbackState;
}
export class WebAudio {
private static _UNLOCKED: boolean = false;
/**
* Play an empty sound to unlock Safari WebAudio context. Call this function
* right after a user interaction event.
* @source https://paulbakaus.com/tutorials/html5/web-audio-on-ios/
*/
static unlock(): Promise<boolean> {
const promise = new Promise<boolean>((resolve, reject) => {
if (WebAudio._UNLOCKED || !AudioContextFactory.create()) {
return resolve(true);
}
const unlockTimeoutTimer = setTimeout(() => {
Logger.getInstance().warn('Excalibur was unable to unlock the audio context, audio probably will not play in this browser.');
resolve(false);
}, 200);
const audioContext = AudioContextFactory.create();
audioContext.resume().then(
() => {
// create empty buffer and play it
const buffer = audioContext.createBuffer(1, 1, 22050);
const source = audioContext.createBufferSource();
let ended = false;
source.buffer = buffer;
source.connect(audioContext.destination);
source.onended = () => (ended = true);
source.start(0);
// by checking the play state after some time, we know if we're really unlocked
setTimeout(() => {
if (isLegacyWebAudioSource(source)) {
if (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE) {
WebAudio._UNLOCKED = true;
}
} else {
if (audioContext.currentTime > 0 || ended) {
WebAudio._UNLOCKED = true;
}
}
}, 0);
clearTimeout(unlockTimeoutTimer);
resolve(true);
},
() => {
reject();
}
);
});
return promise;
}
static isUnlocked() {
return this._UNLOCKED;
}
}