expo-speech 9.2.1 → 10.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,11 +10,34 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
- ## 9.2.1 — 2021-07-28
13
+ ## 10.0.3 — 2021-10-21
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 10.0.2 — 2021-10-15
18
+
19
+ _This version does not introduce any user-facing changes._
20
+
21
+ ## 10.0.1 — 2021-10-01
22
+
23
+ _This version does not introduce any user-facing changes._
24
+
25
+ ## 10.0.0 — 2021-09-28
26
+
27
+ ### 🛠 Breaking changes
28
+
29
+ - Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
14
30
 
15
31
  ### 🐛 Bug fixes
16
32
 
17
33
  - Fix setting speaking listener for projects with `react-native@>0.64.0`. ([#13654](https://github.com/expo/expo/pull/13654) by [@dsokal](https://github.com/dsokal))
34
+ - Fix empty voices list on web and allow to change voice when using `speak`. ([#4516](https://github.com/expo/expo/pull/14516) by [@Federkun](https://github.com/Federkun))
35
+ - Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
36
+
37
+ ### 💡 Others
38
+
39
+ - Migrated from `@unimodules/core` to `expo-modules-core`. ([#13757](https://github.com/expo/expo/pull/13757) by [@tsapeta](https://github.com/tsapeta))
40
+ - Rewritten Android code to Kotlin. ([#14008](https://github.com/expo/expo/pull/14008) by [@barthap](https://github.com/barthap))
18
41
 
19
42
  ## 9.2.0 — 2021-06-16
20
43
 
@@ -25,6 +48,7 @@
25
48
  ### 💡 Others
26
49
 
27
50
  - Build Android code using Java 8 to fix Android instrumented test build error. ([#12939](https://github.com/expo/expo/pull/12939) by [@kudo](https://github.com/kudo))
51
+ - Export missing `WebVoice` type. ([#13257](https://github.com/expo/expo/pull/13257) by [@Simek](https://github.com/Simek))
28
52
 
29
53
  ## 9.1.0 — 2021-03-10
30
54
 
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '9.2.1'
6
+ version = '10.0.3'
7
7
 
8
8
  buildscript {
9
9
  // Simple helper that allows the root project to override versions declared by this library.
@@ -57,23 +57,18 @@ android {
57
57
  minSdkVersion safeExtGet("minSdkVersion", 21)
58
58
  targetSdkVersion safeExtGet("targetSdkVersion", 30)
59
59
  versionCode 18
60
- versionName "9.2.1"
60
+ versionName "10.0.3"
61
61
  }
62
62
  lintOptions {
63
63
  abortOnError false
64
64
  }
65
- }
66
-
67
- if (new File(rootProject.projectDir.parentFile, 'package.json').exists()) {
68
- apply from: project(":unimodules-core").file("../unimodules-core.gradle")
69
- } else {
70
- throw new GradleException(
71
- "'unimodules-core.gradle' was not found in the usual React Native dependency location. " +
72
- "This package can only be used in such projects. Are you sure you've installed the dependencies properly?")
65
+ kotlinOptions {
66
+ jvmTarget = JavaVersion.VERSION_1_8
67
+ }
73
68
  }
74
69
 
75
70
  dependencies {
76
- unimodule "unimodules-core"
71
+ implementation project(':expo-modules-core')
77
72
 
78
73
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
79
74
  }
@@ -0,0 +1,34 @@
1
+ package expo.modules.speech
2
+
3
+ import java.util.*
4
+
5
+ // Lazy load the ISO codes into a Map then transform the codes to match other localization patterns in Expo
6
+ object LanguageUtils {
7
+ private val countryISOCodes: Map<String, Locale> by lazy {
8
+ Locale.getISOCountries().map { country ->
9
+ val locale = Locale("", country)
10
+ locale.getISO3Country().toUpperCase(locale) to locale
11
+ }.toMap()
12
+ }
13
+ private val languageISOCodes: Map<String, Locale> by lazy {
14
+ Locale.getISOLanguages().map { language ->
15
+ val locale = Locale(language)
16
+ locale.getISO3Language() to locale
17
+ }.toMap()
18
+ }
19
+
20
+ // NOTE: These helpers are null-unsafe and should be called ONLY with codes
21
+ // returned by Locale.getISO3Country() and Locale.getISO3Language() respectively
22
+ private fun transformCountryISO(code: String) = countryISOCodes[code]!!.country
23
+ private fun transformLanguageISO(code: String) = languageISOCodes[code]!!.language
24
+
25
+ fun getISOCode(locale: Locale): String {
26
+ var language = transformLanguageISO(locale.getISO3Language())
27
+ val country = locale.getISO3Country()
28
+ if (country != "") {
29
+ val countryCode = transformCountryISO(country)
30
+ language += "-$countryCode"
31
+ }
32
+ return language
33
+ }
34
+ }
@@ -0,0 +1,191 @@
1
+ package expo.modules.speech
2
+
3
+ import android.content.Context
4
+ import android.os.Bundle
5
+ import android.speech.tts.TextToSpeech
6
+ import android.speech.tts.UtteranceProgressListener
7
+ import android.speech.tts.Voice
8
+ import expo.modules.core.ExportedModule
9
+ import expo.modules.core.ModuleRegistry
10
+ import expo.modules.core.ModuleRegistryDelegate
11
+ import expo.modules.core.Promise
12
+ import expo.modules.core.interfaces.ExpoMethod
13
+ import expo.modules.core.interfaces.LifecycleEventListener
14
+ import expo.modules.core.interfaces.services.EventEmitter
15
+ import expo.modules.core.interfaces.services.UIManager
16
+ import java.util.*
17
+
18
+ class SpeechModule(
19
+ context: Context,
20
+ private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
21
+ ) : ExportedModule(context), LifecycleEventListener {
22
+
23
+ private inline fun <reified T> moduleRegistry() =
24
+ moduleRegistryDelegate.getFromModuleRegistry<T>()
25
+
26
+ private val uiManager: UIManager by moduleRegistry()
27
+ private val delayedUtterances: Queue<Utterance> = ArrayDeque()
28
+
29
+ // Module basic definitions
30
+ override fun getName() = "ExponentSpeech"
31
+ override fun getConstants() = mapOf(
32
+ "maxSpeechInputLength" to TextToSpeech.getMaxSpeechInputLength()
33
+ )
34
+
35
+ // Module methods
36
+
37
+ @ExpoMethod
38
+ fun isSpeaking(promise: Promise) = promise.resolve(textToSpeech.isSpeaking)
39
+
40
+ @ExpoMethod
41
+ fun getVoices(promise: Promise) {
42
+ var nativeVoices: List<Voice> = emptyList()
43
+ try {
44
+ nativeVoices = textToSpeech.voices.toList()
45
+ } catch (e: Exception) {}
46
+
47
+ val voices = nativeVoices.map {
48
+ val quality = if (it.quality > Voice.QUALITY_NORMAL) {
49
+ "Enhanced"
50
+ } else {
51
+ "Default"
52
+ }
53
+
54
+ Bundle().apply {
55
+ putString("identifier", it.name)
56
+ putString("name", it.name)
57
+ putString("quality", quality)
58
+ putString("language", LanguageUtils.getISOCode(it.locale))
59
+ }
60
+ }
61
+
62
+ promise.resolve(voices)
63
+ }
64
+
65
+ @ExpoMethod
66
+ fun stop(promise: Promise) {
67
+ textToSpeech.stop()
68
+ promise.resolve(null)
69
+ }
70
+
71
+ @ExpoMethod
72
+ fun speak(id: String, text: String, options: Map<String, Any>?, promise: Promise) {
73
+ val speechOptions = SpeechOptions.optionsFromMap(options, promise) ?: return
74
+
75
+ if (text.length > TextToSpeech.getMaxSpeechInputLength()) {
76
+ promise.reject(
77
+ "ERR_SPEECH_INPUT_LENGTH",
78
+ "Speech input text is too long! Limit of input length is: " + TextToSpeech.getMaxSpeechInputLength()
79
+ )
80
+ return
81
+ }
82
+
83
+ if (isTextToSpeechReady) {
84
+ speakOut(id, text, speechOptions)
85
+ } else {
86
+ delayedUtterances.add(Utterance(id, text, speechOptions))
87
+
88
+ // init TTS, speaking will be available only after onInit
89
+ textToSpeech
90
+ }
91
+ promise.resolve(null)
92
+ }
93
+
94
+ private fun speakOut(id: String, text: String, options: SpeechOptions) {
95
+ options.pitch?.let(textToSpeech::setPitch)
96
+ options.rate?.let(textToSpeech::setSpeechRate)
97
+
98
+ textToSpeech.language = options.language?.let {
99
+ val locale = Locale(it)
100
+ val languageAvailable = textToSpeech.isLanguageAvailable(locale)
101
+
102
+ return@let if (
103
+ languageAvailable != TextToSpeech.LANG_MISSING_DATA &&
104
+ languageAvailable != TextToSpeech.LANG_NOT_SUPPORTED
105
+ ) {
106
+ locale
107
+ } else {
108
+ Locale.getDefault()
109
+ }
110
+ } ?: Locale.getDefault()
111
+
112
+ options.voice?.let { voiceName ->
113
+ textToSpeech.voices
114
+ .firstOrNull { it.name == voiceName }
115
+ ?.let(textToSpeech::setVoice)
116
+ }
117
+
118
+ textToSpeech.speak(
119
+ text,
120
+ TextToSpeech.QUEUE_ADD,
121
+ null,
122
+ id
123
+ )
124
+ }
125
+
126
+ // TextToSpeech object related code
127
+
128
+ private val isTextToSpeechReady
129
+ get() = _ttsReady
130
+
131
+ private val textToSpeech: TextToSpeech by lazy {
132
+ val newTtsInstance = TextToSpeech(context) { status: Int ->
133
+ if (status == TextToSpeech.SUCCESS) {
134
+ // synchronize because in some cases this runs on another thread and _textToSpeech is null
135
+ synchronized(this@SpeechModule) {
136
+ _ttsReady = true
137
+ _textToSpeech!!.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
138
+ private val emitter by moduleRegistry<EventEmitter>()
139
+
140
+ override fun onStart(utteranceId: String) {
141
+ emitter.emit("Exponent.speakingStarted", idToMap(utteranceId))
142
+ }
143
+
144
+ override fun onDone(utteranceId: String) {
145
+ emitter.emit("Exponent.speakingDone", idToMap(utteranceId))
146
+ }
147
+
148
+ override fun onStop(utteranceId: String, interrupted: Boolean) {
149
+ emitter.emit("Exponent.speakingStopped", idToMap(utteranceId))
150
+ }
151
+
152
+ override fun onError(utteranceId: String) {
153
+ emitter.emit("Exponent.speakingError", idToMap(utteranceId))
154
+ }
155
+ })
156
+ for ((id, text, options) in delayedUtterances) {
157
+ speakOut(id, text, options)
158
+ }
159
+ }
160
+ }
161
+ }
162
+ _textToSpeech = newTtsInstance
163
+ newTtsInstance
164
+ }
165
+
166
+ // Lifecycle methods
167
+ override fun onCreate(moduleRegistry: ModuleRegistry) {
168
+ moduleRegistryDelegate.onCreate(moduleRegistry)
169
+ uiManager.registerLifecycleEventListener(this)
170
+ }
171
+ override fun onHostPause() {}
172
+ override fun onHostResume() {}
173
+ override fun onHostDestroy() {
174
+ textToSpeech.shutdown()
175
+ }
176
+
177
+ // Helpers
178
+ private fun idToMap(id: String) = Bundle().apply {
179
+ putString("id", id)
180
+ }
181
+
182
+ private data class Utterance(
183
+ val id: String,
184
+ val text: String,
185
+ val options: SpeechOptions
186
+ )
187
+
188
+ // do not refer to these - they're only needed when initializing `textToSpeech`
189
+ private var _textToSpeech: TextToSpeech? = null
190
+ private var _ttsReady = false
191
+ }
@@ -0,0 +1,58 @@
1
+ package expo.modules.speech
2
+
3
+ import expo.modules.core.Promise
4
+ import java.util.*
5
+
6
+ data class SpeechOptions(
7
+ val language: String?,
8
+ val pitch: Float?,
9
+ val rate: Float?,
10
+ val voice: String?
11
+ ) {
12
+ companion object {
13
+ fun optionsFromMap(options: Map<String, Any?>?, promise: Promise): SpeechOptions? {
14
+
15
+ if (options == null) {
16
+ return SpeechOptions(null, null, null, null)
17
+ }
18
+
19
+ val language = options["language"]?.let {
20
+ if (it is String) {
21
+ return@let it
22
+ }
23
+
24
+ promise.reject("ERR_INVALID_OPTION", "Language must be a string")
25
+ return null
26
+ }
27
+
28
+ val pitch = options["pitch"]?.let {
29
+ if (it is Number) {
30
+ return@let it.toFloat()
31
+ }
32
+
33
+ promise.reject("ERR_INVALID_OPTION", "Pitch must be a number")
34
+ return null
35
+ }
36
+
37
+ val rate = options["rate"]?.let {
38
+ if (it is Number) {
39
+ return@let it.toFloat()
40
+ }
41
+
42
+ promise.reject("ERR_INVALID_OPTION", "Rate must be a number")
43
+ return null
44
+ }
45
+
46
+ val voice = options["voice"]?.let {
47
+ if (it is String) {
48
+ return@let it
49
+ }
50
+
51
+ promise.reject("ERR_INVALID_OPTION", "Voice name must be a string")
52
+ return null
53
+ }
54
+
55
+ return SpeechOptions(language, pitch, rate, voice)
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,8 @@
1
+ package expo.modules.speech
2
+
3
+ import android.content.Context
4
+ import expo.modules.core.BasePackage
5
+
6
+ class SpeechPackage : BasePackage() {
7
+ override fun createExportedModules(context: Context) = listOf(SpeechModule(context))
8
+ }
@@ -1,2 +1,2 @@
1
- declare const _default: import("@unimodules/core").ProxyNativeModule;
1
+ declare const _default: import("expo-modules-core").ProxyNativeModule;
2
2
  export default _default;
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from '@unimodules/core';
1
+ import { NativeModulesProxy } from 'expo-modules-core';
2
2
  export default NativeModulesProxy.ExponentSpeech;
3
3
  //# sourceMappingURL=ExponentSpeech.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExponentSpeech.js","sourceRoot":"","sources":["../src/Speech/ExponentSpeech.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,eAAe,kBAAkB,CAAC,cAAc,CAAC","sourcesContent":["import { NativeModulesProxy } from '@unimodules/core';\nexport default NativeModulesProxy.ExponentSpeech;\n"]}
1
+ {"version":3,"file":"ExponentSpeech.js","sourceRoot":"","sources":["../src/Speech/ExponentSpeech.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,eAAe,kBAAkB,CAAC,cAAc,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\nexport default NativeModulesProxy.ExponentSpeech;\n"]}
@@ -2,7 +2,7 @@ import { SpeechOptions, WebVoice } from './Speech.types';
2
2
  declare const _default: {
3
3
  readonly name: string;
4
4
  speak(id: string, text: string, options: SpeechOptions): Promise<SpeechSynthesisUtterance>;
5
- getVoices(): WebVoice[];
5
+ getVoices(): Promise<WebVoice[]>;
6
6
  isSpeaking(): Promise<boolean>;
7
7
  stop(): Promise<void>;
8
8
  pause(): Promise<void>;
@@ -1,7 +1,22 @@
1
- import { SyntheticPlatformEmitter, CodedError } from '@unimodules/core';
1
+ import { SyntheticPlatformEmitter, CodedError } from 'expo-modules-core';
2
2
  import { VoiceQuality } from './Speech.types';
3
3
  //https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text
4
4
  const MAX_SPEECH_INPUT_LENGTH = 32767;
5
+ async 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
+ }
5
20
  export default {
6
21
  get name() {
7
22
  return 'ExponentSpeech';
@@ -24,9 +39,14 @@ export default {
24
39
  message.volume = options.volume;
25
40
  }
26
41
  if ('_voiceIndex' in options && options._voiceIndex != null) {
27
- const voices = window.speechSynthesis.getVoices();
42
+ const voices = await getVoices();
28
43
  message.voice = voices[Math.min(voices.length - 1, Math.max(0, options._voiceIndex))];
29
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
+ }
30
50
  if (typeof options.onResume === 'function') {
31
51
  message.onresume = options.onResume;
32
52
  }
@@ -52,9 +72,9 @@ export default {
52
72
  window.speechSynthesis.speak(message);
53
73
  return message;
54
74
  },
55
- getVoices() {
56
- const voices = window.speechSynthesis.getVoices();
57
- return voices.map(voice => ({
75
+ async getVoices() {
76
+ const voices = await getVoices();
77
+ return voices.map((voice) => ({
58
78
  identifier: voice.voiceURI,
59
79
  quality: VoiceQuality.Default,
60
80
  isDefault: voice.default,
@@ -1 +1 @@
1
- {"version":3,"file":"ExponentSpeech.web.js","sourceRoot":"","sources":["../src/Speech/ExponentSpeech.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { SyntheticPlatformEmitter, CodedError } from '@unimodules/core';\n\nimport { SpeechOptions, WebVoice, VoiceQuality } from './Speech.types';\n\n//https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text\nconst MAX_SPEECH_INPUT_LENGTH = 32767;\n\nexport default {\n get name(): string {\n return 'ExponentSpeech';\n },\n async speak(id: string, text: string, options: SpeechOptions): Promise<SpeechSynthesisUtterance> {\n if (text.length > MAX_SPEECH_INPUT_LENGTH) {\n throw new CodedError(\n 'ERR_SPEECH_INPUT_LENGTH',\n 'Speech input text is too long! Limit of input length is: ' + MAX_SPEECH_INPUT_LENGTH\n );\n }\n\n const message = new SpeechSynthesisUtterance();\n\n if (typeof options.rate === 'number') {\n message.rate = options.rate;\n }\n if (typeof options.pitch === 'number') {\n message.pitch = options.pitch;\n }\n if (typeof options.language === 'string') {\n message.lang = options.language;\n }\n if (typeof options.volume === 'number') {\n message.volume = options.volume;\n }\n if ('_voiceIndex' in options && options._voiceIndex != null) {\n const voices = window.speechSynthesis.getVoices();\n message.voice = voices[Math.min(voices.length - 1, Math.max(0, options._voiceIndex))];\n }\n if (typeof options.onResume === 'function') {\n message.onresume = options.onResume;\n }\n if (typeof options.onMark === 'function') {\n message.onmark = options.onMark;\n }\n if (typeof options.onBoundary === 'function') {\n message.onboundary = options.onBoundary;\n }\n\n message.onstart = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingStarted', { id, nativeEvent });\n };\n message.onend = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingDone', { id, nativeEvent });\n };\n message.onpause = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingStopped', { id, nativeEvent });\n };\n message.onerror = (nativeEvent: SpeechSynthesisErrorEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingError', { id, nativeEvent });\n };\n\n message.text = text;\n\n window.speechSynthesis.speak(message);\n\n return message;\n },\n getVoices(): WebVoice[] {\n const voices = window.speechSynthesis.getVoices();\n return voices.map(voice => ({\n identifier: voice.voiceURI,\n quality: VoiceQuality.Default,\n isDefault: voice.default,\n language: voice.lang,\n localService: voice.localService,\n name: voice.name,\n voiceURI: voice.voiceURI,\n }));\n },\n async isSpeaking(): Promise<boolean> {\n return window.speechSynthesis.speaking;\n },\n async stop(): Promise<void> {\n return window.speechSynthesis.cancel();\n },\n async pause(): Promise<void> {\n return window.speechSynthesis.pause();\n },\n async resume(): Promise<void> {\n return window.speechSynthesis.resume();\n },\n maxSpeechInputLength: MAX_SPEECH_INPUT_LENGTH,\n};\n"]}
1
+ {"version":3,"file":"ExponentSpeech.web.js","sourceRoot":"","sources":["../src/Speech/ExponentSpeech.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { SyntheticPlatformEmitter, CodedError } from 'expo-modules-core';\n\nimport { SpeechOptions, WebVoice, VoiceQuality } from './Speech.types';\n\n//https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text\nconst MAX_SPEECH_INPUT_LENGTH = 32767;\n\nasync function getVoices(): Promise<SpeechSynthesisVoice[]> {\n return new Promise<SpeechSynthesisVoice[]>((resolve) => {\n const voices = window.speechSynthesis.getVoices();\n\n if (voices.length > 0) {\n resolve(voices);\n return;\n }\n\n // when a page loads it takes some amount of time to populate the voices list\n // see https://stackoverflow.com/a/52005323/4337317\n window.speechSynthesis.onvoiceschanged = function () {\n const voices = window.speechSynthesis.getVoices();\n resolve(voices);\n };\n });\n}\n\nexport default {\n get name(): string {\n return 'ExponentSpeech';\n },\n async speak(id: string, text: string, options: SpeechOptions): Promise<SpeechSynthesisUtterance> {\n if (text.length > MAX_SPEECH_INPUT_LENGTH) {\n throw new CodedError(\n 'ERR_SPEECH_INPUT_LENGTH',\n 'Speech input text is too long! Limit of input length is: ' + MAX_SPEECH_INPUT_LENGTH\n );\n }\n\n const message = new SpeechSynthesisUtterance();\n\n if (typeof options.rate === 'number') {\n message.rate = options.rate;\n }\n if (typeof options.pitch === 'number') {\n message.pitch = options.pitch;\n }\n if (typeof options.language === 'string') {\n message.lang = options.language;\n }\n if (typeof options.volume === 'number') {\n message.volume = options.volume;\n }\n if ('_voiceIndex' in options && options._voiceIndex != null) {\n const voices = await getVoices();\n message.voice = voices[Math.min(voices.length - 1, Math.max(0, options._voiceIndex))];\n }\n if (typeof options.voice === 'string') {\n const voices = await getVoices();\n message.voice =\n voices[\n Math.max(\n 0,\n voices.findIndex((voice) => voice.voiceURI === options.voice)\n )\n ];\n }\n if (typeof options.onResume === 'function') {\n message.onresume = options.onResume;\n }\n if (typeof options.onMark === 'function') {\n message.onmark = options.onMark;\n }\n if (typeof options.onBoundary === 'function') {\n message.onboundary = options.onBoundary;\n }\n\n message.onstart = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingStarted', { id, nativeEvent });\n };\n message.onend = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingDone', { id, nativeEvent });\n };\n message.onpause = (nativeEvent: SpeechSynthesisEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingStopped', { id, nativeEvent });\n };\n message.onerror = (nativeEvent: SpeechSynthesisErrorEvent) => {\n SyntheticPlatformEmitter.emit('Exponent.speakingError', { id, nativeEvent });\n };\n\n message.text = text;\n\n window.speechSynthesis.speak(message);\n\n return message;\n },\n async getVoices(): Promise<WebVoice[]> {\n const voices = await getVoices();\n return voices.map((voice) => ({\n identifier: voice.voiceURI,\n quality: VoiceQuality.Default,\n isDefault: voice.default,\n language: voice.lang,\n localService: voice.localService,\n name: voice.name,\n voiceURI: voice.voiceURI,\n }));\n },\n async isSpeaking(): Promise<boolean> {\n return window.speechSynthesis.speaking;\n },\n async stop(): Promise<void> {\n return window.speechSynthesis.cancel();\n },\n async pause(): Promise<void> {\n return window.speechSynthesis.pause();\n },\n async resume(): Promise<void> {\n return window.speechSynthesis.resume();\n },\n maxSpeechInputLength: MAX_SPEECH_INPUT_LENGTH,\n};\n"]}
package/build/Speech.d.ts CHANGED
@@ -1,9 +1,38 @@
1
- import { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice } from './Speech.types';
2
- export { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice };
1
+ import { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice, WebVoice } from './Speech.types';
2
+ export { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice, WebVoice };
3
+ /**
4
+ * Speak out loud the text given options. Calling this when another text is being spoken adds
5
+ * an utterance to queue.
6
+ * @param text The text to be spoken. Cannot be longer than [`Speech.maxSpeechInputLength`](#speechmaxspeechinputlength).
7
+ * @param options A `SpeechOptions` object.
8
+ */
3
9
  export declare function speak(text: string, options?: SpeechOptions): void;
10
+ /**
11
+ * Returns list of all available voices.
12
+ * @return List of `Voice` objects.
13
+ */
4
14
  export declare function getAvailableVoicesAsync(): Promise<Voice[]>;
15
+ /**
16
+ * Determine whether the Text-to-speech utility is currently speaking. Will return `true` if speaker
17
+ * is paused.
18
+ * @return Returns a Promise that fulfils with a boolean, `true` if speaking, `false` if not.
19
+ */
5
20
  export declare function isSpeakingAsync(): Promise<boolean>;
21
+ /**
22
+ * Interrupts current speech and deletes all in queue.
23
+ */
6
24
  export declare function stop(): Promise<void>;
25
+ /**
26
+ * Pauses current speech. This method is not available on Android.
27
+ */
7
28
  export declare function pause(): Promise<void>;
29
+ /**
30
+ * Resumes speaking previously paused speech or does nothing if there's none. This method is not
31
+ * available on Android.
32
+ */
8
33
  export declare function resume(): Promise<void>;
34
+ /**
35
+ * Maximum possible text length acceptable by `Speech.speak()` method. It is platform-dependent.
36
+ * On iOS, this returns `Number.MAX_VALUE`.
37
+ */
9
38
  export declare const maxSpeechInputLength: number;
package/build/Speech.js CHANGED
@@ -1,4 +1,4 @@
1
- import { UnavailabilityError } from '@unimodules/core';
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
2
  import { NativeEventEmitter } from 'react-native';
3
3
  import ExponentSpeech from './ExponentSpeech';
4
4
  import { VoiceQuality } from './Speech.types';
@@ -51,30 +51,61 @@ function _registerListenersIfNeeded() {
51
51
  _unregisterListenersIfNeeded();
52
52
  });
53
53
  }
54
+ // @needsAudit
55
+ /**
56
+ * Speak out loud the text given options. Calling this when another text is being spoken adds
57
+ * an utterance to queue.
58
+ * @param text The text to be spoken. Cannot be longer than [`Speech.maxSpeechInputLength`](#speechmaxspeechinputlength).
59
+ * @param options A `SpeechOptions` object.
60
+ */
54
61
  export function speak(text, options = {}) {
55
62
  const id = _nextCallbackId++;
56
63
  _CALLBACKS[id] = options;
57
64
  _registerListenersIfNeeded();
58
65
  ExponentSpeech.speak(String(id), text, options);
59
66
  }
67
+ // @needsAudit
68
+ /**
69
+ * Returns list of all available voices.
70
+ * @return List of `Voice` objects.
71
+ */
60
72
  export async function getAvailableVoicesAsync() {
61
73
  if (!ExponentSpeech.getVoices) {
62
74
  throw new UnavailabilityError('Speech', 'getVoices');
63
75
  }
64
76
  return ExponentSpeech.getVoices();
65
77
  }
78
+ //@needsAudit
79
+ /**
80
+ * Determine whether the Text-to-speech utility is currently speaking. Will return `true` if speaker
81
+ * is paused.
82
+ * @return Returns a Promise that fulfils with a boolean, `true` if speaking, `false` if not.
83
+ */
66
84
  export async function isSpeakingAsync() {
67
85
  return ExponentSpeech.isSpeaking();
68
86
  }
87
+ // @needsAudit
88
+ /**
89
+ * Interrupts current speech and deletes all in queue.
90
+ */
69
91
  export async function stop() {
70
92
  return ExponentSpeech.stop();
71
93
  }
94
+ // @needsAudit
95
+ /**
96
+ * Pauses current speech. This method is not available on Android.
97
+ */
72
98
  export async function pause() {
73
99
  if (!ExponentSpeech.pause) {
74
100
  throw new UnavailabilityError('Speech', 'pause');
75
101
  }
76
102
  return ExponentSpeech.pause();
77
103
  }
104
+ // @needsAudit
105
+ /**
106
+ * Resumes speaking previously paused speech or does nothing if there's none. This method is not
107
+ * available on Android.
108
+ */
78
109
  export async function resume() {
79
110
  if (!ExponentSpeech.resume) {
80
111
  throw new UnavailabilityError('Speech', 'resume');
@@ -96,5 +127,10 @@ function setSpeakingListener(eventName, callback) {
96
127
  function removeSpeakingListener(eventName) {
97
128
  SpeechEventEmitter.removeAllListeners(eventName);
98
129
  }
130
+ // @needsAudit
131
+ /**
132
+ * Maximum possible text length acceptable by `Speech.speak()` method. It is platform-dependent.
133
+ * On iOS, this returns `Number.MAX_VALUE`.
134
+ */
99
135
  export const maxSpeechInputLength = ExponentSpeech.maxSpeechInputLength || Number.MAX_VALUE;
100
136
  //# sourceMappingURL=Speech.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Speech.js","sourceRoot":"","sources":["../src/Speech/Speech.ts"],"names":[],"mappings":"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","sourcesContent":["import { UnavailabilityError } from '@unimodules/core';\nimport { NativeEventEmitter } from 'react-native';\n\nimport ExponentSpeech from './ExponentSpeech';\nimport { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice } from './Speech.types';\n\nconst SpeechEventEmitter = ExponentSpeech && new NativeEventEmitter(ExponentSpeech);\n\nexport { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice };\n\nconst _CALLBACKS = {};\nlet _nextCallbackId = 1;\nlet _didSetListeners = false;\n\nfunction _unregisterListenersIfNeeded() {\n if (Object.keys(_CALLBACKS).length === 0) {\n removeSpeakingListener('Exponent.speakingStarted');\n removeSpeakingListener('Exponent.speakingDone');\n removeSpeakingListener('Exponent.speakingStopped');\n removeSpeakingListener('Exponent.speakingError');\n _didSetListeners = false;\n }\n}\n\nfunction _registerListenersIfNeeded() {\n if (_didSetListeners) return;\n _didSetListeners = true;\n setSpeakingListener('Exponent.speakingStarted', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onStart) {\n options.onStart();\n }\n });\n setSpeakingListener('Exponent.speakingDone', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onDone) {\n options.onDone();\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n setSpeakingListener('Exponent.speakingStopped', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onStopped) {\n options.onStopped();\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n setSpeakingListener('Exponent.speakingError', ({ id, error }) => {\n const options = _CALLBACKS[id];\n if (options && options.onError) {\n options.onError(new Error(error));\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n}\n\nexport function speak(text: string, options: SpeechOptions = {}) {\n const id = _nextCallbackId++;\n _CALLBACKS[id] = options;\n _registerListenersIfNeeded();\n ExponentSpeech.speak(String(id), text, options);\n}\n\nexport async function getAvailableVoicesAsync(): Promise<Voice[]> {\n if (!ExponentSpeech.getVoices) {\n throw new UnavailabilityError('Speech', 'getVoices');\n }\n return ExponentSpeech.getVoices();\n}\n\nexport async function isSpeakingAsync(): Promise<boolean> {\n return ExponentSpeech.isSpeaking();\n}\n\nexport async function stop(): Promise<void> {\n return ExponentSpeech.stop();\n}\n\nexport async function pause(): Promise<void> {\n if (!ExponentSpeech.pause) {\n throw new UnavailabilityError('Speech', 'pause');\n }\n return ExponentSpeech.pause();\n}\n\nexport async function resume(): Promise<void> {\n if (!ExponentSpeech.resume) {\n throw new UnavailabilityError('Speech', 'resume');\n }\n\n return ExponentSpeech.resume();\n}\n\nfunction setSpeakingListener(eventName, callback) {\n // @ts-ignore: the EventEmitter interface has been changed in react-native@0.64.0\n const listenerCount = SpeechEventEmitter.listenerCount\n ? // @ts-ignore: this is available since 0.64\n SpeechEventEmitter.listenerCount(eventName)\n : // @ts-ignore: this is available in older versions\n SpeechEventEmitter.listeners(eventName).length;\n if (listenerCount > 0) {\n SpeechEventEmitter.removeAllListeners(eventName);\n }\n SpeechEventEmitter.addListener(eventName, callback);\n}\n\nfunction removeSpeakingListener(eventName) {\n SpeechEventEmitter.removeAllListeners(eventName);\n}\n\nexport const maxSpeechInputLength: number = ExponentSpeech.maxSpeechInputLength || Number.MAX_VALUE;\n"]}
1
+ {"version":3,"file":"Speech.js","sourceRoot":"","sources":["../src/Speech/Speech.ts"],"names":[],"mappings":"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","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\nimport { NativeEventEmitter } from 'react-native';\n\nimport ExponentSpeech from './ExponentSpeech';\nimport { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice, WebVoice } from './Speech.types';\n\nconst SpeechEventEmitter = ExponentSpeech && new NativeEventEmitter(ExponentSpeech);\n\nexport { SpeechOptions, SpeechEventCallback, VoiceQuality, Voice, WebVoice };\n\nconst _CALLBACKS = {};\nlet _nextCallbackId = 1;\nlet _didSetListeners = false;\n\nfunction _unregisterListenersIfNeeded() {\n if (Object.keys(_CALLBACKS).length === 0) {\n removeSpeakingListener('Exponent.speakingStarted');\n removeSpeakingListener('Exponent.speakingDone');\n removeSpeakingListener('Exponent.speakingStopped');\n removeSpeakingListener('Exponent.speakingError');\n _didSetListeners = false;\n }\n}\n\nfunction _registerListenersIfNeeded() {\n if (_didSetListeners) return;\n _didSetListeners = true;\n setSpeakingListener('Exponent.speakingStarted', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onStart) {\n options.onStart();\n }\n });\n setSpeakingListener('Exponent.speakingDone', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onDone) {\n options.onDone();\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n setSpeakingListener('Exponent.speakingStopped', ({ id }) => {\n const options = _CALLBACKS[id];\n if (options && options.onStopped) {\n options.onStopped();\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n setSpeakingListener('Exponent.speakingError', ({ id, error }) => {\n const options = _CALLBACKS[id];\n if (options && options.onError) {\n options.onError(new Error(error));\n }\n delete _CALLBACKS[id];\n _unregisterListenersIfNeeded();\n });\n}\n\n// @needsAudit\n/**\n * Speak out loud the text given options. Calling this when another text is being spoken adds\n * an utterance to queue.\n * @param text The text to be spoken. Cannot be longer than [`Speech.maxSpeechInputLength`](#speechmaxspeechinputlength).\n * @param options A `SpeechOptions` object.\n */\nexport function speak(text: string, options: SpeechOptions = {}) {\n const id = _nextCallbackId++;\n _CALLBACKS[id] = options;\n _registerListenersIfNeeded();\n ExponentSpeech.speak(String(id), text, options);\n}\n\n// @needsAudit\n/**\n * Returns list of all available voices.\n * @return List of `Voice` objects.\n */\nexport async function getAvailableVoicesAsync(): Promise<Voice[]> {\n if (!ExponentSpeech.getVoices) {\n throw new UnavailabilityError('Speech', 'getVoices');\n }\n return ExponentSpeech.getVoices();\n}\n\n//@needsAudit\n/**\n * Determine whether the Text-to-speech utility is currently speaking. Will return `true` if speaker\n * is paused.\n * @return Returns a Promise that fulfils with a boolean, `true` if speaking, `false` if not.\n */\nexport async function isSpeakingAsync(): Promise<boolean> {\n return ExponentSpeech.isSpeaking();\n}\n\n// @needsAudit\n/**\n * Interrupts current speech and deletes all in queue.\n */\nexport async function stop(): Promise<void> {\n return ExponentSpeech.stop();\n}\n\n// @needsAudit\n/**\n * Pauses current speech. This method is not available on Android.\n */\nexport async function pause(): Promise<void> {\n if (!ExponentSpeech.pause) {\n throw new UnavailabilityError('Speech', 'pause');\n }\n return ExponentSpeech.pause();\n}\n\n// @needsAudit\n/**\n * Resumes speaking previously paused speech or does nothing if there's none. This method is not\n * available on Android.\n */\nexport async function resume(): Promise<void> {\n if (!ExponentSpeech.resume) {\n throw new UnavailabilityError('Speech', 'resume');\n }\n\n return ExponentSpeech.resume();\n}\n\nfunction setSpeakingListener(eventName, callback) {\n // @ts-ignore: the EventEmitter interface has been changed in react-native@0.64.0\n const listenerCount = SpeechEventEmitter.listenerCount\n ? // @ts-ignore: this is available since 0.64\n SpeechEventEmitter.listenerCount(eventName)\n : // @ts-ignore: this is available in older versions\n SpeechEventEmitter.listeners(eventName).length;\n if (listenerCount > 0) {\n SpeechEventEmitter.removeAllListeners(eventName);\n }\n SpeechEventEmitter.addListener(eventName, callback);\n}\n\nfunction removeSpeakingListener(eventName) {\n SpeechEventEmitter.removeAllListeners(eventName);\n}\n\n// @needsAudit\n/**\n * Maximum possible text length acceptable by `Speech.speak()` method. It is platform-dependent.\n * On iOS, this returns `Number.MAX_VALUE`.\n */\nexport const maxSpeechInputLength: number = ExponentSpeech.maxSpeechInputLength || Number.MAX_VALUE;\n"]}