Diary

@ssig33

06 Feb 2020 Thu 12:06

消費者庁のサイトが speechSynthesis を使って読み上げ機能を提供しているが壊れている

現代のブラウザには speechSynthesis という API があってそれなりの性能の読み上げをすぐ実装できて便利なのだが、あまり活用例はないという状態だった。

ところが昨日偶然消費者庁がやっている特商法の解説サイトがこれを活用しているのを発見した。しかし盛大に壊れている。どう壊れているかは以下をご確認頂きたい。

で、なんでこんなことになっているのかとソースコードを見てみた。ぶっ壊れの理由は以下のような実装になっているからである(一部省略して核心部だけ示している)。

var voiceNum = 0;       
if(navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
    voiceNum = 0;
    console.log('win firefox');
}else if(navigator.appVersion.indexOf('Edge') != -1) {
    voiceNum = 0;
    console.log('win Edge');
}else if(navigator.appVersion.indexOf('Chrome') != -1) {
    voiceNum = 11;
    voiceRate = 1.1;
    console.log('win Chrome');
}else{
    voiceNum = 0;
    console.log('win');
}

var utterance = new SpeechSynthesisUtterance();
utterance.lang = 'ja-JP';
utterance.rate = voiceRate;
utterance.voice = speechSynthesis.getVoices()[voiceNum];

このコードは、 speechSynthesis.getVoices() の値が常に一定であることに依存している。しかし MDNの解説を見る限りそれは保証されていないようだし(そもそも This is an experimental technology とある)、実際僕の環境は実装者の意図とは違う値がかえってきているようだ。

ちょっと確認した限りでは、

  • Windows 10 の Chrome と Edge ではダメ
  • Mac の Chrome は大丈夫
  • Mac の Firefox もダメ

というかんじであった。

ではどうすればよかったのか?というと以下のようにすべきである

speechSynthesis.getVoices().find(v => v.lang === 'ja-JP')

で、 Windows 10 の Chrome でこれに置き換えてみたら以下のようになった。

感想

  • experimental と書かれている機能を使う場合、継続的にちゃんと動いているかの確認が必要と思う
  • speechSynthesis は(ちゃんと使えば)想像以上によく動く。積極的に導入していく価値がある