22

How to use SpeechSynthesisUtterance() and window.speechSynthesis.speak() at chromium browser?

var msg = new SpeechSynthesisUtterance( "Hello I am browser" );
window.speechSynthesis.speak( msg );

yields no output at system speakers.

Issues with the API have bee noted The HTML5 SpeechSynthesis API is rubbish;

var voices = window.speechSynthesis.getVoices();

logs an empty array for voices identifier; and only chrome not chromium purportedly support Web Speech API Specification, the Web Speech API Demonstration sets value of html element at demonstration to utterance voiced when microphone is enabled at page.

At least some of the JavaScript relating to the functionality is apparently

var langs =
[['Afrikaans',       ['af-ZA']],
 ['Bahasa Indonesia',['id-ID']],
 ['Bahasa Melayu',   ['ms-MY']],
 ['Català',          ['ca-ES']],
 ['Čeština',         ['cs-CZ']],
 ['Dansk',           ['da-DK']],
 ['Deutsch',         ['de-DE']],
 ['English',         ['en-AU', 'Australia'],
                     ['en-CA', 'Canada'],
                     ['en-IN', 'India'],
                     ['en-NZ', 'New Zealand'],
                     ['en-ZA', 'South Africa'],
                     ['en-GB', 'United Kingdom'],
                     ['en-US', 'United States']],
 ['Español',         ['es-AR', 'Argentina'],
                     ['es-BO', 'Bolivia'],
                     ['es-CL', 'Chile'],
                     ['es-CO', 'Colombia'],
                     ['es-CR', 'Costa Rica'],
                     ['es-EC', 'Ecuador'],
                     ['es-SV', 'El Salvador'],
                     ['es-ES', 'España'],
                     ['es-US', 'Estados Unidos'],
                     ['es-GT', 'Guatemala'],
                     ['es-HN', 'Honduras'],
                     ['es-MX', 'México'],
                     ['es-NI', 'Nicaragua'],
                     ['es-PA', 'Panamá'],
                     ['es-PY', 'Paraguay'],
                     ['es-PE', 'Perú'],
                     ['es-PR', 'Puerto Rico'],
                     ['es-DO', 'República Dominicana'],
                     ['es-UY', 'Uruguay'],
                     ['es-VE', 'Venezuela']],
 ['Euskara',         ['eu-ES']],
 ['Filipino',        ['fil-PH']],
 ['Français',        ['fr-FR']],
 ['Galego',          ['gl-ES']],
 ['Hrvatski',        ['hr_HR']],
 ['IsiZulu',         ['zu-ZA']],
 ['Íslenska',        ['is-IS']],
 ['Italiano',        ['it-IT', 'Italia'],
                     ['it-CH', 'Svizzera']],
 ['Lietuvių',        ['lt-LT']],
 ['Magyar',          ['hu-HU']],
 ['Nederlands',      ['nl-NL']],
 ['Norsk bokmål',    ['nb-NO']],
 ['Polski',          ['pl-PL']],
 ['Português',       ['pt-BR', 'Brasil'],
                     ['pt-PT', 'Portugal']],
 ['Română',          ['ro-RO']],
 ['Slovenščina',     ['sl-SI']],
 ['Slovenčina',      ['sk-SK']],
 ['Suomi',           ['fi-FI']],
 ['Svenska',         ['sv-SE']],
 ['Tiếng Việt',      ['vi-VN']],
 ['Türkçe',          ['tr-TR']],
 ['Ελληνικά',        ['el-GR']],
 ['български',       ['bg-BG']],
 ['Pусский',         ['ru-RU']],
 ['Српски',          ['sr-RS']],
 ['Українська',      ['uk-UA']],
 ['한국어',            ['ko-KR']],
 ['中文',             ['cmn-Hans-CN', '普通话 (中国大陆)'],
                     ['cmn-Hans-HK', '普通话 (香港)'],
                     ['cmn-Hant-TW', '中文 (台灣)'],
                     ['yue-Hant-HK', '粵語 (香港)']],
 ['日本語',           ['ja-JP']],
 ['हिन्दी',            ['hi-IN']],
 ['ภาษาไทย',         ['th-TH']]];

for (var i = 0; i < langs.length; i++) {
  select_language.options[i] = new Option(langs[i][0], i);
}
select_language.selectedIndex = 7;
updateCountry();
select_dialect.selectedIndex = 6;
showInfo('info_start');

function updateCountry() {
  for (var i = select_dialect.options.length - 1; i >= 0; i--) {
    select_dialect.remove(i);
  }
  var list = langs[select_language.selectedIndex];
  for (var i = 1; i < list.length; i++) {
    select_dialect.options.add(new Option(list[i][1], list[i][0]));
  }
  select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
}

var create_email = false;
var final_transcript = '';
var recognizing = false;
var ignore_onend;
var start_timestamp;
if (!('webkitSpeechRecognition' in window)) {
  upgrade();
} else {
  start_button.style.display = 'inline-block';
  var recognition = new webkitSpeechRecognition();
  recognition.continuous = true;
  recognition.interimResults = true;

  recognition.onstart = function() {
    recognizing = true;
    showInfo('info_speak_now');
    start_img.src = '/intl/en/chrome/assets/common/images/content/mic-animate.gif';
  };

  recognition.onerror = function(event) {
    if (event.error == 'no-speech') {
      start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
      showInfo('info_no_speech');
      ignore_onend = true;
    }
    if (event.error == 'audio-capture') {
      start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
      showInfo('info_no_microphone');
      ignore_onend = true;
    }
    if (event.error == 'not-allowed') {
      if (event.timeStamp - start_timestamp < 100) {
        showInfo('info_blocked');
      } else {
        showInfo('info_denied');
      }
      ignore_onend = true;
    }
  };

  recognition.onend = function() {
    recognizing = false;
    if (ignore_onend) {
      return;
    }
    start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
    if (!final_transcript) {
      showInfo('info_start');
      return;
    }
    showInfo('');
    if (window.getSelection) {
      window.getSelection().removeAllRanges();
      var range = document.createRange();
      range.selectNode(document.getElementById('final_span'));
      window.getSelection().addRange(range);
    }
    if (create_email) {
      create_email = false;
      createEmail();
    }
  };

  recognition.onresult = function(event) {
    var interim_transcript = '';
    if (typeof(event.results) == 'undefined') {
      recognition.onend = null;
      recognition.stop();
      upgrade();
      return;
    }
    for (var i = event.resultIndex; i < event.results.length; ++i) {
      if (event.results[i].isFinal) {
        final_transcript += event.results[i][0].transcript;
      } else {
        interim_transcript += event.results[i][0].transcript;
      }
    }
    final_transcript = capitalize(final_transcript);
    final_span.innerHTML = linebreak(final_transcript);
    interim_span.innerHTML = linebreak(interim_transcript);
    if (final_transcript || interim_transcript) {
      showButtons('inline-block');
    }
  };
}

function upgrade() {
  start_button.style.visibility = 'hidden';
  showInfo('info_upgrade');
}

var two_line = /\n\n/g;
var one_line = /\n/g;
function linebreak(s) {
  return s.replace(two_line, '<p></p>').replace(one_line, '<br>');
}

var first_char = /\S/;
function capitalize(s) {
  return s.replace(first_char, function(m) { return m.toUpperCase(); });
}

function createEmail() {
  var n = final_transcript.indexOf('\n');
  if (n < 0 || n >= 80) {
    n = 40 + final_transcript.substring(40).indexOf(' ');
  }
  var subject = encodeURI(final_transcript.substring(0, n));
  var body = encodeURI(final_transcript.substring(n + 1));
  window.location.href = 'mailto:?subject=' + subject + '&body=' + body;
}

function copyButton() {
  if (recognizing) {
    recognizing = false;
    recognition.stop();
  }
  copy_button.style.display = 'none';
  copy_info.style.display = 'inline-block';
  showInfo('');
}

function emailButton() {
  if (recognizing) {
    create_email = true;
    recognizing = false;
    recognition.stop();
  } else {
    createEmail();
  }
  email_button.style.display = 'none';
  email_info.style.display = 'inline-block';
  showInfo('');
}

function startButton(event) {
  if (recognizing) {
    recognition.stop();
    return;
  }
  final_transcript = '';
  recognition.lang = select_dialect.value;
  recognition.start();
  ignore_onend = false;
  final_span.innerHTML = '';
  interim_span.innerHTML = '';
  start_img.src = '/intl/en/chrome/assets/common/images/content/mic-slash.gif';
  showInfo('info_allow');
  showButtons('none');
  start_timestamp = event.timeStamp;
}

function showInfo(s) {
  if (s) {
    for (var child = info.firstChild; child; child = child.nextSibling) {
      if (child.style) {
        child.style.display = child.id == s ? 'inline' : 'none';
      }
    }
    info.style.visibility = 'visible';
  } else {
    info.style.visibility = 'hidden';
  }
}

var current_style;
function showButtons(style) {
  if (style == current_style) {
    return;
  }
  current_style = style;
  copy_button.style.display = style;
  email_button.style.display = style;
  copy_info.style.display = 'none';
  email_info.style.display = 'none';
}

attributed to authors of the document.

Though not certain how this affects the usage of SpeechSynthesisUtterance() and window.speechSynthesis.speak()?

How to load voices to populate window.speechSynthesis.getVoices()?

How does the linked demonstration document implement the functionality to transcribe voice to text?

What are the workarounds necessary to use the Web Speech API at chromium browser?

Specifically, how to transcribe voice to text and convert text to audio output?

guest271314
  • 1
  • 15
  • 104
  • 177
  • Related [Web speech api not working currently in chromium / electron / nw js?](https://stackoverflow.com/questions/36052774/web-speech-api-not-working-currently-in-chromium-electron-nw-js?rq=1), [generate audio file with W3C Web Speech API](https://stackoverflow.com/questions/38727696/generate-audio-file-with-w3c-web-speech-api?rq=1) – guest271314 Jun 03 '17 at 14:16
  • SpeechSynthesisUtterance and speak() works fine in chromium windows7. getVoices() returns empty array before speak(). But if i try speak() and then getVoices() it returns the voices. Version 61.0.3125.0 (Developer Build) (32-bit) – karthick Jun 09 '17 at 16:29
  • @karthick Currently trying at chromium 58 at *nix 32-bit. Can you create a plnkr https://plnkr.co to demonstrate the pattern that you are describing? – guest271314 Jun 09 '17 at 16:56
  • Here is a codepen https://codepen.io/pen/OgMEgK. voices array will be empty initially. But after speechSyntesis.speak(), it returns the options – karthick Jun 09 '17 at 17:14
  • maybe its OS specific – karthick Jun 09 '17 at 17:25
  • @karthick Yes, that may be the case. An empty array is returned at both calls, here. – guest271314 Jun 09 '17 at 17:25

2 Answers2

8

Install espeak using package manager

$ sudo apt-get install espeak

Launch Chromium with --enable-speech-dispatcher flag

$ chromium-browser --enable-speech-dispatcher
guest271314
  • 1
  • 15
  • 104
  • 177
  • 4
    Does it really work for you? It does not for me and when chromium starts it complains because `--enable-speech-dispatcher Unsupported flag has been used` – Ömer Faruk Almalı Jan 28 '19 at 10:10
  • @ÖmerFarukAlmalı At what versions of Chromium/Chrome and which OS's have you tried Web Speech API? Are `espeak` or `espeak-ng` and `speechd` installed? – guest271314 Jan 30 '19 at 06:13
  • 4
    Latest Chromium (81.4044.129), installed 'espeak' as proposed and started with command line ... not working for me (on Ubuntu 18.04.4, Linux 4.15.0). – Jeach May 04 '20 at 22:07
  • Though I'm a Firefox user, this gave me a hint. Installing `espeak-ng` and `speech-dispacher`, creating and editing the configuration file according to [this discussion](https://bbs.archlinux.org/viewtopic.php?id=243537) and finally rebooting made my Firefox work correctly with `SpeechSynthesis` class. However, still it doesn't work on Chromium. Tested under Arch Linux. – ynn May 29 '20 at 11:18
  • @ynn Perhaps related to [*Chrome - `speechSynthesis.speak()` without user activation is no longer allowed since M71, around December 2018*](https://www.chromestatus.com/feature/5687444770914304)? – ynn May 29 '20 at 14:00
  • 1
    It worked on chromium 90.0.4430.93 (arch), installed ```espeak, espeak-ng, speech-dispatcher```, launched chrome with ```chromium --enable-speech-dispatcher```. First launch will have "unsupported flag, stability will be impacted" message thing but it worked anyway – Kristian May 10 '21 at 02:29
1
  1. I recently tried to wrap my app which uses SpeechSynthesis with NWjs.

Properly works on Mac (mac os has voices by default).

As NWjs uses Chromium as a browser engine this proves that SpeechSynthesis works.

IMHO, the only difference between Chrome and Chromium that Chromium does not have Google voices and therefore will not work on the machine without voices installed.

Yuriy N.
  • 4,936
  • 2
  • 38
  • 31