You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

检测浏览器对SSML的支持及跨浏览器适配方案

检测SSML支持的可靠方法(无需浏览器嗅探)

不用纠结浏览器类型,我们可以直接检测SpeechSynthesis API对SSML的原生支持,这样更准确也更符合现代前端的最佳实践。下面是两种递进的方案:


方案1:利用原生ssmlSupported属性(优先推荐)

部分现代浏览器(比如安卓Chrome、新版Edge等)会给SpeechSynthesisVoice实例提供ssmlSupported属性,直接告诉你当前语音是否支持SSML解析。

实现代码:

function isSSMLSupported() {
  // 先检查浏览器是否支持SpeechSynthesis API
  if (!window.speechSynthesis) {
    return false;
  }
  
  // 获取所有可用语音
  const voices = window.speechSynthesis.getVoices();
  
  // 如果有至少一个语音支持SSML,就返回true
  return voices.some(voice => voice.ssmlSupported === true);
}

// 使用示例
if (isSSMLSupported()) {
  // 支持SSML,使用带标签的文本
  const utterance = new SpeechSynthesisUtterance('<?xml version="1.0"?><speak>Intro <break time="200ms"/>the rest.</speak>');
  window.speechSynthesis.speak(utterance);
} else {
  // 不支持,使用普通文本
  const utterance = new SpeechSynthesisUtterance('Intro the rest.');
  window.speechSynthesis.speak(utterance);
}

注意点:

  • speechSynthesis.getVoices()在页面加载时可能是空的,因为语音列表是异步加载的。如果遇到这种情况,可以监听voiceschanged事件再执行检测:
let voicesLoaded = false;

window.speechSynthesis.onvoiceschanged = () => {
  voicesLoaded = true;
};

// 调用检测前确保语音已加载
function checkSSMLSupport() {
  if (!voicesLoaded) {
    setTimeout(checkSSMLSupport, 100);
    return;
  }
  return isSSMLSupported();
}

方案2:Fallback测试(针对不支持ssmlSupported的浏览器,比如Linux Chrome)

如果浏览器没有提供ssmlSupported属性,我们可以通过对比SSML文本和普通文本的播放时长来间接判断:包含<break>的SSML文本播放时长应该比普通文本长。

实现代码:

async function testSSMLSupport() {
  if (!window.speechSynthesis) {
    return false;
  }

  // 等待语音加载完成
  await new Promise(resolve => {
    if (window.speechSynthesis.getVoices().length > 0) {
      resolve();
    } else {
      window.speechSynthesis.onvoiceschanged = resolve;
    }
  });

  return new Promise(resolve => {
    // 测试用的SSML文本(带200ms停顿)
    const ssmlText = '<?xml version="1.0"?><speak>Test <break time="200ms"/>pause.</speak>';
    // 对应的普通文本
    const plainText = 'Test pause.';

    let ssmlDuration = 0;
    let plainDuration = 0;
    let testsCompleted = 0;

    // 定义测试单个文本时长的函数
    function testDuration(text, isSSML) {
      const utterance = new SpeechSynthesisUtterance(text);
      utterance.onstart = () => {
        utterance.startTime = Date.now();
      };
      utterance.onend = () => {
        const duration = Date.now() - utterance.startTime;
        if (isSSML) {
          ssmlDuration = duration;
        } else {
          plainDuration = duration;
        }
        testsCompleted++;
        if (testsCompleted === 2) {
          // 如果SSML时长比普通文本长至少150ms(考虑误差),说明支持SSML
          resolve(ssmlDuration > plainDuration + 150);
        }
      };
      // 播放时静音,避免干扰用户
      utterance.volume = 0;
      window.speechSynthesis.speak(utterance);
    }

    // 先测试普通文本,再测试SSML
    testDuration(plainText, false);
    setTimeout(() => testDuration(ssmlText, true), 1000);
  });
}

// 使用示例
testSSMLSupport().then(supported => {
  if (supported) {
    // 支持SSML
    window.speechSynthesis.speak(new SpeechSynthesisUtterance('<?xml version="1.0"?><speak>Intro <break time="200ms"/>the rest.</speak>'));
  } else {
    // 不支持
    window.speechSynthesis.speak(new SpeechSynthesisUtterance('Intro the rest.'));
  }
});

注意点:

  • 这个方法依赖于实际播放时长的对比,可能会有微小误差,所以设置了150ms的阈值(比200ms停顿略小)来过滤偶然情况。
  • 测试时把音量设为0,避免打扰用户体验。

两种方案结合起来用的话,先检查ssmlSupported属性,不支持的话再用fallback测试,这样就能覆盖绝大多数浏览器场景了。

内容的提问来源于stack exchange,提问作者havlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 08:07:50