最近在尝试做一个文字转语音的功能,使用第三方的接口进行文字转语音,接口传入文字,返回音频文件,然后自动播放,这个流程在PC运行正常的,但是到了手机端,发现没有效果,因为手机端的浏览器默认不需要audio自动播放,需要明显的用户操作,比如点击才可以。
为了解决这个问题,方法也很简单,就是在用户之前的点击行为后,先创建几个audio,然后将将创建的audio缓存下来,直接播放再停止,那么这几个缓存的audio就可以突破浏览器自动播放的限制。
代码如下:
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
| export class AudioPlayer { private audioQueue: Array<{ audio: HTMLAudioElement; chunkId: number }> = []; private currentAudio: HTMLAudioElement | null = null; private unlockedAudioQueue: HTMLAudioElement[] = []; private nextChunkId = 0;
private statusChange: (playing: Boolean) => void;
constructor(statusChange: (playing: Boolean) => void) { this.statusChange = statusChange; }
public init() { const count = 10; if (this.unlockedAudioQueue.length < count) { for (let i = this.unlockedAudioQueue.length; i < count; i++) { const audio = new Audio(); audio.play(); audio.pause(); audio.currentTime = 0; this.unlockedAudioQueue.push(audio); } } console.log(this.unlockedAudioQueue); }
public addAudioToQueue(audioUrl: string, chunkId: number) { const newAudio = this.unlockedAudioQueue.shift(); newAudio.src = audioUrl; this.audioQueue.push({ audio: newAudio, chunkId }); this.audioQueue = this.audioQueue.sort((a, b) => a.chunkId - b.chunkId); console.log("addAudioToQueue", this.nextChunkId, chunkId, audioUrl); if (!this.currentAudio) { this.playNext(); } }
public stop() { if (this.currentAudio) { this.currentAudio.pause(); this.currentAudio.src = null; this.currentAudio.currentTime = 0; } this.audioQueue = []; }
private playNext(retryCount = 0) { console.log("playNext", this.audioQueue, this.nextChunkId, retryCount); if (this.audioQueue.length > 0) { if (this.audioQueue[0].chunkId !== this.nextChunkId && retryCount < 3) { setTimeout(() => { this.playNext(retryCount + 1); }, 300); return; } this.statusChange(true); const audioQueueItem = this.audioQueue.shift(); this.currentAudio = audioQueueItem.audio; this.nextChunkId = audioQueueItem.chunkId + 1; if (this.currentAudio) { this.currentAudio.onended = () => { if (this.currentAudio) { this.currentAudio.src = null; this.currentAudio.pause(); this.currentAudio.currentTime = 0; }
this.currentAudio = null; this.playNext(); }; this.currentAudio?.play(); } } else { this.statusChange(false); } } }
|
在用户前置点击的操作中,调用init,缓存10个audio,当真的需要播放音频的时候,再将音频blob传入,chunkId的逻辑是因为,我的需求中,一段长文字返回后一起识别延迟比较明显,所以就并行请求,但是为了播放的正常顺序,加一个id,大家可以根据自己需求来