背景
chrome@v130 中的 chrome extension 在调用 chrome.offscreen.createDocument
执行 js 文件 new SpeechSynthesisUtterance
朗诵不生效问题
该问题只在 130 版本中出现,以此记录。
解决方法如下
// offscreen.js
chrome.runtime.onMessage.addListener(msg => {
if ('playOffscreenRing' in msg) playAudio(msg.playOffscreenRing);
});
// ring 如果为文本字符串时,为播放 tts
// 如果为 chrome-extension 开头代表着播放音频
function playAudio(ring) {
if(ring.startsWith('chrome-extension')){
const audio = new Audio(ring);
audio.play();
}else{
readTTS(ring)
}
}
function readTTS(str) {
//
//
// 这里要先初始化一次,什么都不朗读
//
//
window.speechSynthesis.speak(new SpeechSynthesisUtterance(''));
chrome.runtime.sendMessage({
type: "FROM_OFFSCREEN",
data: `朗读 ${str}`
})
try{
return new Promise((resolve) => {
const utterance = new SpeechSynthesisUtterance(str);
utterance.lang = "zh-CN";
utterance.volume = 1;
utterance.rate = 1;
window.speechSynthesis.cancel();
if (window.speechSynthesis.speaking) {
setTimeout(() => {
window.speechSynthesis.speak(utterance);
resolve();
}, 100);
} else {
window.speechSynthesis.speak(utterance);
resolve();
}
});
}catch (e){
chrome.runtime.sendMessage({
type: "FROM_OFFSCREEN",
data: `朗读错误 ${e.toString()}`
})
}
}
// background.js
const needDoublePlay = await setupOffscreenDocument("offscreen/index.html");
//
//
// 这里是解决的关键,如果 offscreen 文件是第一次创建,那么就播放两次,这样就能解决第一次播放没声音问题
//
//
if (needDoublePlay) {
await chrome.runtime.sendMessage({
playOffscreenRing: source,
});
await new Promise((resolve) => setTimeout(resolve, 1500));
}
await chrome.runtime.sendMessage({
playOffscreenRing: source,
});
async function setupOffscreenDocument(path: string) {
const offscreenUrl = chrome.runtime.getURL(path);
const existingContexts = await chrome.runtime.getContexts({
contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],
documentUrls: [offscreenUrl],
});
if (existingContexts.length > 0) {
return false;
}
// create offscreen document
if (creating) {
await creating;
} else {
creating = chrome.offscreen.createDocument({
url: path,
reasons: [chrome.offscreen.Reason.AUDIO_PLAYBACK],
justification: "play an audio",
});
await creating;
creating = null;
return true;
}
}