-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathindex.js
125 lines (101 loc) · 3.06 KB
/
index.js
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
/*! unmute-ios-audio. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = unmuteIosAudio
const USER_ACTIVATION_EVENTS = [
'auxclick',
'click',
'contextmenu',
'dblclick',
'keydown',
'keyup',
'mousedown',
'mouseup',
'touchend'
]
function unmuteIosAudio () {
const AudioContext = window.webkitAudioContext
// To detect iOS, check for touch device and confirm Safari-only
// webkitAudioContext is present.
const isIos = navigator.maxTouchPoints > 0 && AudioContext != null
if (!isIos) return
// state can be 'blocked', 'pending', 'allowed'
let htmlAudioState = 'blocked'
let webAudioState = 'blocked'
let audio
let context
let source
const sampleRate = (new AudioContext()).sampleRate
const silentAudioFile = createSilentAudioFile(sampleRate)
USER_ACTIVATION_EVENTS.forEach(eventName => {
window.addEventListener(
eventName, handleUserActivation, { capture: true, passive: true }
)
})
// Return a seven samples long 8 bit mono WAVE file
function createSilentAudioFile (sampleRate) {
const arrayBuffer = new ArrayBuffer(10)
const dataView = new DataView(arrayBuffer)
dataView.setUint32(0, sampleRate, true)
dataView.setUint32(4, sampleRate, true)
dataView.setUint16(8, 1, true)
const missingCharacters =
window.btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)))
.slice(0, 13)
return `data:audio/wav;base64,UklGRisAAABXQVZFZm10IBAAAAABAAEA${missingCharacters}AgAZGF0YQcAAACAgICAgICAAAA=`
}
function handleUserActivation (e) {
if (htmlAudioState === 'blocked') {
htmlAudioState = 'pending'
createHtmlAudio()
}
if (webAudioState === 'blocked') {
webAudioState = 'pending'
createWebAudio()
}
}
function createHtmlAudio () {
audio = document.createElement('audio')
audio.setAttribute('x-webkit-airplay', 'deny') // Disable the iOS control center media widget
audio.preload = 'auto'
audio.loop = true
audio.src = silentAudioFile
audio.load()
audio.play().then(
() => {
htmlAudioState = 'allowed'
maybeCleanup()
},
() => {
htmlAudioState = 'blocked'
audio.pause()
audio.removeAttribute('src')
audio.load()
audio = null
}
)
}
function createWebAudio () {
context = new AudioContext()
source = context.createBufferSource()
source.buffer = context.createBuffer(1, 1, 22050) // .045 msec of silence
source.connect(context.destination)
source.start()
if (context.state === 'running') {
webAudioState = 'allowed'
maybeCleanup()
} else {
webAudioState = 'blocked'
source.disconnect(context.destination)
source = null
context.close()
context = null
}
}
function maybeCleanup () {
if (htmlAudioState !== 'allowed' || webAudioState !== 'allowed') return
USER_ACTIVATION_EVENTS.forEach(eventName => {
window.removeEventListener(
eventName, handleUserActivation, { capture: true, passive: true }
)
})
}
}