1import { SyntheticPlatformEmitter, CodedError } from 'expo-modules-core'; 2import { VoiceQuality } from './Speech.types'; 3//https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text 4const MAX_SPEECH_INPUT_LENGTH = 32767; 5async function getVoices() { 6 return new Promise((resolve) => { 7 const voices = window.speechSynthesis.getVoices(); 8 if (voices.length > 0) { 9 resolve(voices); 10 return; 11 } 12 // when a page loads it takes some amount of time to populate the voices list 13 // see https://stackoverflow.com/a/52005323/4337317 14 window.speechSynthesis.onvoiceschanged = function () { 15 const voices = window.speechSynthesis.getVoices(); 16 resolve(voices); 17 }; 18 }); 19} 20export default { 21 get name() { 22 return 'ExponentSpeech'; 23 }, 24 async speak(id, text, options) { 25 if (text.length > MAX_SPEECH_INPUT_LENGTH) { 26 throw new CodedError('ERR_SPEECH_INPUT_LENGTH', 'Speech input text is too long! Limit of input length is: ' + MAX_SPEECH_INPUT_LENGTH); 27 } 28 const message = new SpeechSynthesisUtterance(); 29 if (typeof options.rate === 'number') { 30 message.rate = options.rate; 31 } 32 if (typeof options.pitch === 'number') { 33 message.pitch = options.pitch; 34 } 35 if (typeof options.language === 'string') { 36 message.lang = options.language; 37 } 38 if (typeof options.volume === 'number') { 39 message.volume = options.volume; 40 } 41 if ('_voiceIndex' in options && options._voiceIndex != null) { 42 const voices = await getVoices(); 43 message.voice = voices[Math.min(voices.length - 1, Math.max(0, options._voiceIndex))]; 44 } 45 if (typeof options.voice === 'string') { 46 const voices = await getVoices(); 47 message.voice = 48 voices[Math.max(0, voices.findIndex((voice) => voice.voiceURI === options.voice))]; 49 } 50 if (typeof options.onResume === 'function') { 51 message.onresume = options.onResume; 52 } 53 if (typeof options.onMark === 'function') { 54 message.onmark = options.onMark; 55 } 56 if (typeof options.onBoundary === 'function') { 57 message.onboundary = options.onBoundary; 58 } 59 message.onstart = (nativeEvent) => { 60 SyntheticPlatformEmitter.emit('Exponent.speakingStarted', { id, nativeEvent }); 61 }; 62 message.onend = (nativeEvent) => { 63 SyntheticPlatformEmitter.emit('Exponent.speakingDone', { id, nativeEvent }); 64 }; 65 message.onpause = (nativeEvent) => { 66 SyntheticPlatformEmitter.emit('Exponent.speakingStopped', { id, nativeEvent }); 67 }; 68 message.onerror = (nativeEvent) => { 69 SyntheticPlatformEmitter.emit('Exponent.speakingError', { id, nativeEvent }); 70 }; 71 message.text = text; 72 window.speechSynthesis.speak(message); 73 return message; 74 }, 75 async getVoices() { 76 const voices = await getVoices(); 77 return voices.map((voice) => ({ 78 identifier: voice.voiceURI, 79 quality: VoiceQuality.Default, 80 isDefault: voice.default, 81 language: voice.lang, 82 localService: voice.localService, 83 name: voice.name, 84 voiceURI: voice.voiceURI, 85 })); 86 }, 87 async isSpeaking() { 88 return window.speechSynthesis.speaking; 89 }, 90 async stop() { 91 return window.speechSynthesis.cancel(); 92 }, 93 async pause() { 94 return window.speechSynthesis.pause(); 95 }, 96 async resume() { 97 return window.speechSynthesis.resume(); 98 }, 99 maxSpeechInputLength: MAX_SPEECH_INPUT_LENGTH, 100}; 101//# sourceMappingURL=ExponentSpeech.web.js.map