0%

ios上telegram miniapp中声音播放延迟

需求

在开发tg miniapp的时候,有一个场景如下:

1
2
1.点击播放声音
2.连续点击,需要重复地从头再次播放。(比如声音是‘噔-噔-咚’,快速连续点击就响起‘噔-噔-噔’)

代码实现

这边给元素绑定了点击事件,当用户触发点击事件,就将音频的当前进度设置为0,并且播放。

1
2
audio.currentTime=0;
audio.play();

适配情况

这个代码在pc的chrome和android的浏览器中都可以正常实现需求。

但是ios中,会出现声音的延迟(比如声音是‘噔-噔-咚’,快速连续点击就响起‘——噔-噔-咚’,稍慢连续点击就响起‘–噔–噔–噔’)

解决方案

调用howler库

相关源码如下(源于howler库)

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
// Call this method on touch start to create and play a buffer,
// then check if the audio actually played to determine if
// audio has now been unlocked on iOS, Android, etc.
var unlock = function(e) {
// Create a pool of unlocked HTML5 Audio objects that can
// be used for playing sounds without user interaction. HTML5
// Audio objects must be individually unlocked, as opposed
// to the WebAudio API which only needs a single activation.
// This must occur before WebAudio setup or the source.onended
// event will not fire.
while (self._html5AudioPool.length < self.html5PoolSize) {
try {
var audioNode = new Audio();

// Mark this Audio object as unlocked to ensure it can get returned
// to the unlocked pool when released.
audioNode._unlocked = true;

// Add the audio node to the pool.
self._releaseHtml5Audio(audioNode);
} catch (e) {
self.noAudio = true;
break;
}
}

// Loop through any assigned audio nodes and unlock them.
for (var i=0; i<self._howls.length; i++) {
if (!self._howls[i]._webAudio) {
// Get all of the sounds in this Howl group.
var ids = self._howls[i]._getSoundIds();

// Loop through all sounds and unlock the audio nodes.
for (var j=0; j<ids.length; j++) {
var sound = self._howls[i]._soundById(ids[j]);

if (sound && sound._node && !sound._node._unlocked) {
sound._node._unlocked = true;
sound._node.load();
}
}
}
}

// Fix Android can not play in suspend state.
self._autoResume();

// Create an empty buffer.
var source = self.ctx.createBufferSource();
source.buffer = self._scratchBuffer;
source.connect(self.ctx.destination);

// Play the empty buffer.
if (typeof source.start === 'undefined') {
source.noteOn(0);
} else {
source.start(0);
}

// Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55.
if (typeof self.ctx.resume === 'function') {
self.ctx.resume();
}

// Setup a timeout to check that we are unlocked on the next event loop.
source.onended = function() {
source.disconnect(0);

// Update the unlocked state and prevent this check from happening again.
self._audioUnlocked = true;

// Remove the touch start listener.
document.removeEventListener('touchstart', unlock, true);
document.removeEventListener('touchend', unlock, true);
document.removeEventListener('click', unlock, true);
document.removeEventListener('keydown', unlock, true);

// Let all sounds know that audio has been unlocked.
for (var i=0; i<self._howls.length; i++) {
self._howls[i]._emit('unlock');
}
};
};