@focus8/expo-acapela-tts 0.1.11 → 0.2.0

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.
@@ -1,33 +1,23 @@
1
1
  package expo.modules.acapelatts
2
2
 
3
- import android.Manifest
4
- import android.content.Intent
5
- import android.content.pm.PackageManager
6
- import android.net.Uri
7
- import android.os.Build
8
- import android.os.Environment
9
- import android.provider.Settings
10
3
  import android.util.Log
11
- import androidx.core.content.ContextCompat
12
4
  import com.acapelagroup.android.tts.acattsandroid
13
5
  import com.acapelagroup.android.tts.acattsandroid.iTTSEventsCallback
14
6
  import expo.modules.kotlin.modules.Module
15
7
  import expo.modules.kotlin.modules.ModuleDefinition
16
- import java.io.File
17
8
 
18
9
  class ExpoAcapelaTtsModule : Module(), iTTSEventsCallback {
19
10
 
20
11
  private var tts: acattsandroid? = null
21
12
  private var isInitialized = false
22
13
  private var currentVoice: String? = null
23
- private var voicePaths = mutableListOf("/sdcard/voices", "/system/media/voices", "/data/media/voices")
14
+ private var voicePaths = mutableListOf<String>()
24
15
  private var licenseUserId: Long? = null
25
16
  private var licensePassword: Long? = null
26
17
  private var licenseKey: String? = null
27
18
 
28
19
  companion object {
29
20
  private const val TAG = "ExpoAcapelaTts"
30
-
31
21
  private var nativeLibLoaded = false
32
22
 
33
23
  init {
@@ -47,63 +37,8 @@ class ExpoAcapelaTtsModule : Module(), iTTSEventsCallback {
47
37
 
48
38
  Events("onSpeechStart", "onSpeechEnd", "onError")
49
39
 
50
- Function("hasStoragePermission") {
51
- hasStorageAccess()
52
- }
53
-
54
- AsyncFunction("requestStoragePermissionAsync") {
55
- val context = appContext.reactContext ?: return@AsyncFunction false
56
-
57
- if (hasStorageAccess()) {
58
- logInfo("Storage permission already granted")
59
- return@AsyncFunction true
60
- }
61
-
62
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
63
- // Android 11+ needs MANAGE_EXTERNAL_STORAGE via Settings intent
64
- try {
65
- val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
66
- data = Uri.fromParts("package", context.packageName, null)
67
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
68
- }
69
- context.startActivity(intent)
70
- logInfo("Launched MANAGE_EXTERNAL_STORAGE settings for ${context.packageName}")
71
- } catch (e: Exception) {
72
- // Fallback for devices that don't support the per-app intent
73
- try {
74
- val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION).apply {
75
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
76
- }
77
- context.startActivity(intent)
78
- } catch (e2: Exception) {
79
- logError("Failed to launch storage permission settings", e2)
80
- return@AsyncFunction false
81
- }
82
- }
83
- // User needs to grant in settings and come back - we can't wait for result
84
- false
85
- } else {
86
- // Pre-Android 11: READ_EXTERNAL_STORAGE is enough, granted via manifest on enrolled AOSP
87
- logInfo("Pre-Android 11: storage permissions handled by manifest")
88
- true
89
- }
90
- }
91
-
92
40
  Function("isAvailable") {
93
- if (!nativeLibLoaded) {
94
- return@Function false
95
- }
96
- try {
97
- val available = voicePaths.any { path ->
98
- val dir = File(path)
99
- dir.exists() && dir.isDirectory && (dir.list()?.isNotEmpty() == true)
100
- }
101
- logInfo("isAvailable: $available (paths: ${voicePaths.joinToString()})")
102
- available
103
- } catch (e: Exception) {
104
- logError("isAvailable check failed", e)
105
- false
106
- }
41
+ nativeLibLoaded && voicePaths.isNotEmpty()
107
42
  }
108
43
 
109
44
  Function("addVoicePath") { path: String ->
@@ -117,109 +52,64 @@ class ExpoAcapelaTtsModule : Module(), iTTSEventsCallback {
117
52
  licenseUserId = java.lang.Long.decode(userIdStr)
118
53
  licensePassword = java.lang.Long.decode(passwordStr)
119
54
  licenseKey = key
120
- logInfo("License set: userId=0x${java.lang.Long.toHexString(licenseUserId!!)} password=0x${java.lang.Long.toHexString(licensePassword!!)}")
55
+ logInfo("License set")
121
56
  }
122
57
 
123
58
  AsyncFunction("initializeAsync") {
124
59
  if (!nativeLibLoaded) {
125
- logWarning("Cannot initialize: native library not loaded")
126
60
  return@AsyncFunction false
127
61
  }
128
-
129
62
  if (isInitialized && tts != null) {
130
- logInfo("Already initialized")
131
63
  return@AsyncFunction true
132
64
  }
133
-
134
- // Use BuildConfig values as fallback if setLicense() was not called from JS
135
- val uid = licenseUserId ?: BuildConfig.ACAPELA_USER_ID
136
- val pwd = licensePassword ?: BuildConfig.ACAPELA_PASSWORD
137
- val key = licenseKey ?: BuildConfig.ACAPELA_LICENSE_KEY
138
-
65
+ val uid = licenseUserId ?: 0L
66
+ val pwd = licensePassword ?: 0L
67
+ val key = licenseKey
139
68
  if (uid == 0L || key.isNullOrEmpty()) {
140
- logWarning("Cannot initialize: no license configured (neither via setLicense() nor BuildConfig)")
69
+ logWarning("No license configured")
141
70
  return@AsyncFunction false
142
71
  }
143
-
144
72
  try {
145
- val context = appContext.reactContext ?: run {
146
- logWarning("ReactContext not available")
147
- return@AsyncFunction false
148
- }
149
-
73
+ val context = appContext.reactContext ?: return@AsyncFunction false
150
74
  tts = acattsandroid(context, this@ExpoAcapelaTtsModule, null)
151
75
  tts!!.setLog(true)
152
- logInfo("setLicense userId=0x${java.lang.Long.toHexString(uid)} password=0x${java.lang.Long.toHexString(pwd)} keyLength=${key?.length}")
153
76
  tts!!.setLicense(uid, pwd, key)
154
-
155
- // Store for re-use after getVoicesList
156
- licenseUserId = uid
157
- licensePassword = pwd
158
- licenseKey = key
159
-
160
- val version = tts!!.version
161
- logInfo("Initialized, SDK version: $version")
162
-
77
+ logInfo("Initialized, version: ${tts!!.version}")
163
78
  isInitialized = true
164
79
  true
165
80
  } catch (e: Exception) {
166
- logError("Failed to initialize", e)
81
+ logError("Init failed", e)
167
82
  tts = null
168
83
  isInitialized = false
169
84
  false
170
85
  }
171
86
  }
172
87
 
173
- AsyncFunction("getVoicesAsync") {
88
+ AsyncFunction("getVoicesAsync") { paths: List<String> ->
174
89
  if (tts == null) {
175
- logWarning("getVoicesAsync: TTS not initialized")
176
90
  return@AsyncFunction emptyList<Map<String, Any>>()
177
91
  }
178
-
179
92
  try {
180
- val voiceDirPaths = voicePaths.toTypedArray()
181
- logInfo("getVoicesAsync: scanning paths: ${voiceDirPaths.joinToString()}")
182
- for (path in voiceDirPaths) {
183
- val dir = java.io.File(path)
184
- if (dir.exists()) {
185
- val files = dir.list() ?: emptyArray()
186
- logInfo(" Path $path: exists=${dir.exists()}, canRead=${dir.canRead()}, entries=${files.size}")
187
- } else {
188
- logInfo(" Path $path: does not exist")
189
- }
190
- }
191
- val voicesList = tts!!.getVoicesList(voiceDirPaths) ?: emptyArray()
192
- // Re-set license after getVoicesList as it may reset internal state
93
+ val dirPaths = paths.toTypedArray()
94
+ val voicesList = tts!!.getVoicesList(dirPaths) ?: emptyArray()
95
+ // Re-set license after getVoicesList
193
96
  if (licenseUserId != null && licensePassword != null && licenseKey != null) {
194
97
  tts!!.setLicense(licenseUserId!!, licensePassword!!, licenseKey)
195
98
  }
196
- logInfo("Found ${voicesList.size} voices")
197
- for (v in voicesList) {
198
- logInfo(" Voice: $v")
199
- }
200
-
201
- val voices = voicesList.map { voiceName ->
99
+ logInfo("Found ${voicesList.size} voices in ${paths.joinToString()}")
100
+ voicesList.map { voiceName ->
202
101
  val info = tts!!.getVoiceInfo(voiceName) ?: emptyMap()
203
- val genderValue = info["gender"] ?: "0"
204
102
  mapOf(
205
103
  "name" to voiceName,
206
104
  "locale" to (info["locale"] ?: ""),
207
105
  "language" to (info["language"] ?: ""),
208
- "speaker" to (info["name"]?.let { extractSpeakerName(it) } ?: ""),
209
- "gender" to if (genderValue == "1") "female" else "male",
106
+ "speaker" to (info["name"] ?: ""),
107
+ "gender" to if ((info["gender"] ?: "0") == "1") "female" else "male",
210
108
  "quality" to (info["quality"] ?: ""),
211
109
  "age" to (info["age"] ?: ""),
212
110
  "frequency" to (info["frequency"] ?: "")
213
111
  )
214
112
  }
215
-
216
- // Reload the current voice since getVoicesList unloads any loaded voice
217
- if (currentVoice != null) {
218
- tts!!.load(currentVoice, "MODE=prep_full")
219
- logInfo("Reloaded voice after listing: $currentVoice")
220
- }
221
-
222
- voices
223
113
  } catch (e: Exception) {
224
114
  logError("Failed to get voices", e)
225
115
  emptyList<Map<String, Any>>()
@@ -228,12 +118,10 @@ class ExpoAcapelaTtsModule : Module(), iTTSEventsCallback {
228
118
 
229
119
  AsyncFunction("loadVoiceAsync") { voiceName: String ->
230
120
  if (tts == null) {
231
- logWarning("loadVoiceAsync: TTS not initialized")
232
121
  return@AsyncFunction false
233
122
  }
234
-
235
123
  try {
236
- val result = tts!!.load(voiceName, "MODE=prep_full")
124
+ val result = tts!!.load(voiceName, "")
237
125
  if (result == 0) {
238
126
  currentVoice = voiceName
239
127
  logInfo("Voice loaded: $voiceName")
@@ -250,125 +138,51 @@ class ExpoAcapelaTtsModule : Module(), iTTSEventsCallback {
250
138
 
251
139
  AsyncFunction("speakAsync") { text: String ->
252
140
  if (tts == null) {
253
- logWarning("speakAsync: TTS not initialized")
254
141
  return@AsyncFunction -1
255
142
  }
256
-
257
143
  try {
258
144
  if (tts!!.isSpeaking) {
259
145
  tts!!.stop()
260
146
  }
261
- val result = tts!!.speak(text)
262
- if (result < 0) {
263
- logWarning("speak returned error: $result")
264
- }
265
- result
147
+ tts!!.speak(text)
266
148
  } catch (e: Exception) {
267
149
  logError("Failed to speak", e)
268
150
  -1
269
151
  }
270
152
  }
271
153
 
272
- Function("stop") {
273
- try {
274
- tts?.stop()
275
- } catch (e: Exception) {
276
- logError("Failed to stop", e)
277
- }
278
- }
154
+ Function("stop") { tts?.stop() }
279
155
 
280
- Function("isSpeaking") {
281
- try {
282
- tts?.isSpeaking ?: false
283
- } catch (e: Exception) {
284
- false
285
- }
286
- }
156
+ Function("isSpeaking") { tts?.isSpeaking ?: false }
287
157
 
288
158
  Function("setSpeechRate") { rate: Float ->
289
- try {
290
- // JS sends 0.5-2.0, Acapela expects 30-400 (percentage)
291
- val acapelaRate = rate * 100f
292
- tts?.setSpeechRate(acapelaRate)
293
- } catch (e: Exception) {
294
- logError("Failed to set speech rate", e)
295
- }
159
+ tts?.setSpeechRate(rate * 100f)
296
160
  }
297
161
 
298
162
  Function("setPitch") { pitch: Float ->
299
- try {
300
- tts?.setPitch(pitch)
301
- } catch (e: Exception) {
302
- logError("Failed to set pitch", e)
303
- }
163
+ tts?.setPitch(pitch)
304
164
  }
305
165
 
306
166
  Function("setAudioBoost") { boost: Int ->
307
- try {
308
- tts?.setAudioBoost(boost)
309
- } catch (e: Exception) {
310
- logError("Failed to set audio boost", e)
311
- }
167
+ tts?.setAudioBoost(boost)
312
168
  }
313
169
 
314
170
  AsyncFunction("shutdownAsync") {
315
- try {
316
- tts?.stop()
317
- tts?.shutdown()
318
- tts = null
319
- isInitialized = false
320
- currentVoice = null
321
- logInfo("Shutdown complete")
322
- } catch (e: Exception) {
323
- logError("Failed to shutdown", e)
324
- }
171
+ tts?.stop()
172
+ tts?.shutdown()
173
+ tts = null
174
+ isInitialized = false
175
+ currentVoice = null
325
176
  }
326
177
  }
327
178
 
328
- // iTTSEventsCallback implementation
329
179
  override fun ttsevents(type: Long, param1: Long, param2: Long, param3: Long, param4: Long) {
330
- try {
331
- when (type) {
332
- acattsandroid.EVENT_AUDIO_START.toLong() -> {
333
- logInfo("Speech started (text index: $param1)")
334
- sendEvent("onSpeechStart", emptyMap<String, Any>())
335
- }
336
- acattsandroid.EVENT_AUDIO_END.toLong() -> {
337
- logInfo("Speech ended (text index: $param1, samples: $param2)")
338
- sendEvent("onSpeechEnd", emptyMap<String, Any>())
339
- }
340
- acattsandroid.EVENT_TEXT_START.toLong() -> {
341
- logInfo("Text processing started (index: $param1)")
342
- }
343
- acattsandroid.EVENT_TEXT_END.toLong() -> {
344
- logInfo("Text processing ended (index: $param1)")
345
- }
346
- acattsandroid.EVENT_WORD_POS.toLong() -> {
347
- // Word position event - available for future text highlighting
348
- }
349
- }
350
- } catch (e: Exception) {
351
- logError("Error in ttsevents callback", e)
180
+ when (type) {
181
+ acattsandroid.EVENT_AUDIO_START.toLong() -> sendEvent("onSpeechStart", emptyMap<String, Any>())
182
+ acattsandroid.EVENT_AUDIO_END.toLong() -> sendEvent("onSpeechEnd", emptyMap<String, Any>())
352
183
  }
353
184
  }
354
185
 
355
- private fun hasStorageAccess(): Boolean {
356
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
357
- Environment.isExternalStorageManager()
358
- } else {
359
- val context = appContext.reactContext ?: return false
360
- ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
361
- }
362
- }
363
-
364
- private fun extractSpeakerName(voiceFileName: String): String {
365
- // Voice file names like "non_kari_22k_ns.qvcu" -> "Kari"
366
- // Or voice names like "hq-ref-Norwegian-Kari-22khz" -> "Kari"
367
- val parts = voiceFileName.split("-", "_")
368
- return parts.find { it.length > 2 && it[0].isUpperCase() && it.all { c -> c.isLetter() } }
369
- ?: voiceFileName
370
- }
371
-
372
186
  private fun logInfo(msg: String) = Log.i(TAG, msg)
373
187
  private fun logWarning(msg: String) = Log.w(TAG, msg)
374
188
  private fun logError(msg: String, e: Throwable) = Log.e(TAG, msg, e)
@@ -2,12 +2,10 @@ import { NativeModule } from 'expo';
2
2
  import { AcapelaVoice, ExpoAcapelaTtsModuleEvents } from './ExpoAcapelaTts.types';
3
3
  declare class ExpoAcapelaTtsModule extends NativeModule<ExpoAcapelaTtsModuleEvents> {
4
4
  isAvailable(): boolean;
5
- hasStoragePermission(): boolean;
6
- requestStoragePermissionAsync(): Promise<boolean>;
7
5
  addVoicePath(path: string): void;
8
6
  setLicense(userId: string, password: string, key: string): void;
9
7
  initializeAsync(): Promise<boolean>;
10
- getVoicesAsync(): Promise<AcapelaVoice[]>;
8
+ getVoicesAsync(paths: string[]): Promise<AcapelaVoice[]>;
11
9
  loadVoiceAsync(voiceName: string): Promise<boolean>;
12
10
  speakAsync(text: string): Promise<number>;
13
11
  stop(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAcapelaTtsModule.android.d.ts","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,OAAO,oBAAqB,SAAQ,YAAY,CAAC,0BAA0B,CAAC;IACjF,WAAW,IAAI,OAAO;IACtB,oBAAoB,IAAI,OAAO;IAC/B,6BAA6B,IAAI,OAAO,CAAC,OAAO,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAChC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAC/D,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IACnC,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IACzC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IACnD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACzC,IAAI,IAAI,IAAI;IACZ,UAAU,IAAI,OAAO;IACrB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC7B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAClC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B;;AAED,wBAA2E"}
1
+ {"version":3,"file":"ExpoAcapelaTtsModule.android.d.ts","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,OAAO,oBAAqB,SAAQ,YAAY,CAAC,0BAA0B,CAAC;IACjF,WAAW,IAAI,OAAO;IACtB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAChC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAC/D,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IACnC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IACxD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IACnD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACzC,IAAI,IAAI,IAAI;IACZ,UAAU,IAAI,OAAO;IACrB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC7B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAClC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B;;AAED,wBAA2E"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAcapelaTtsModule.android.js","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAyBzD,eAAe,mBAAmB,CAAuB,gBAAgB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n AcapelaVoice,\n ExpoAcapelaTtsModuleEvents,\n} from './ExpoAcapelaTts.types';\n\ndeclare class ExpoAcapelaTtsModule extends NativeModule<ExpoAcapelaTtsModuleEvents> {\n isAvailable(): boolean;\n hasStoragePermission(): boolean;\n requestStoragePermissionAsync(): Promise<boolean>;\n addVoicePath(path: string): void;\n setLicense(userId: string, password: string, key: string): void;\n initializeAsync(): Promise<boolean>;\n getVoicesAsync(): Promise<AcapelaVoice[]>;\n loadVoiceAsync(voiceName: string): Promise<boolean>;\n speakAsync(text: string): Promise<number>;\n stop(): void;\n isSpeaking(): boolean;\n setSpeechRate(rate: number): void;\n setPitch(pitch: number): void;\n setAudioBoost(boost: number): void;\n shutdownAsync(): Promise<void>;\n}\n\nexport default requireNativeModule<ExpoAcapelaTtsModule>('ExpoAcapelaTts');\n"]}
1
+ {"version":3,"file":"ExpoAcapelaTtsModule.android.js","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAuBzD,eAAe,mBAAmB,CAAuB,gBAAgB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n AcapelaVoice,\n ExpoAcapelaTtsModuleEvents,\n} from './ExpoAcapelaTts.types';\n\ndeclare class ExpoAcapelaTtsModule extends NativeModule<ExpoAcapelaTtsModuleEvents> {\n isAvailable(): boolean;\n addVoicePath(path: string): void;\n setLicense(userId: string, password: string, key: string): void;\n initializeAsync(): Promise<boolean>;\n getVoicesAsync(paths: string[]): Promise<AcapelaVoice[]>;\n loadVoiceAsync(voiceName: string): Promise<boolean>;\n speakAsync(text: string): Promise<number>;\n stop(): void;\n isSpeaking(): boolean;\n setSpeechRate(rate: number): void;\n setPitch(pitch: number): void;\n setAudioBoost(boost: number): void;\n shutdownAsync(): Promise<void>;\n}\n\nexport default requireNativeModule<ExpoAcapelaTtsModule>('ExpoAcapelaTts');\n"]}
@@ -1,11 +1,9 @@
1
1
  declare const _default: {
2
2
  isAvailable(): boolean;
3
- hasStoragePermission(): boolean;
4
- requestStoragePermissionAsync(): Promise<boolean>;
5
3
  addVoicePath(_path: string): void;
6
4
  setLicense(_userId: string, _password: string, _key: string): void;
7
5
  initializeAsync(): Promise<boolean>;
8
- getVoicesAsync(): Promise<never[]>;
6
+ getVoicesAsync(_paths: string[]): Promise<never[]>;
9
7
  loadVoiceAsync(_voiceName: string): Promise<boolean>;
10
8
  speakAsync(_text: string): Promise<number>;
11
9
  stop(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAcapelaTtsModule.d.ts","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.ts"],"names":[],"mappings":";mBAEiB,OAAO;4BAGE,OAAO;qCAGQ,OAAO,CAAC,OAAO,CAAC;wBAGnC,MAAM;wBACN,MAAM,aAAa,MAAM,QAAQ,MAAM;uBAClC,OAAO,CAAC,OAAO,CAAC;;+BAMR,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;sBAGlC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;;kBAIlC,OAAO;yBAGA,MAAM;qBACV,MAAM;0BACD,MAAM;;;;;;;AA9B9B,wBAoCE"}
1
+ {"version":3,"file":"ExpoAcapelaTtsModule.d.ts","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.ts"],"names":[],"mappings":";mBACiB,OAAO;wBAGF,MAAM;wBACN,MAAM,aAAa,MAAM,QAAQ,MAAM;uBAClC,OAAO,CAAC,OAAO,CAAC;2BAGZ,MAAM,EAAE;+BAGJ,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;sBAGlC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;;kBAIlC,OAAO;yBAGA,MAAM;qBACV,MAAM;0BACD,MAAM;;;;;;;AAxB9B,wBA8BE"}
@@ -1,20 +1,13 @@
1
- // No-op stub for non-Android platforms
2
1
  export default {
3
2
  isAvailable() {
4
3
  return false;
5
4
  },
6
- hasStoragePermission() {
7
- return true;
8
- },
9
- async requestStoragePermissionAsync() {
10
- return true;
11
- },
12
5
  addVoicePath(_path) { },
13
6
  setLicense(_userId, _password, _key) { },
14
7
  async initializeAsync() {
15
8
  return false;
16
9
  },
17
- async getVoicesAsync() {
10
+ async getVoicesAsync(_paths) {
18
11
  return [];
19
12
  },
20
13
  async loadVoiceAsync(_voiceName) {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAcapelaTtsModule.js","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,eAAe;IACb,WAAW;QACT,OAAO,KAAK,CAAC;IACf,CAAC;IACD,oBAAoB;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,6BAA6B;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,YAAY,CAAC,KAAa,IAAG,CAAC;IAC9B,UAAU,CAAC,OAAe,EAAE,SAAiB,EAAE,IAAY,IAAG,CAAC;IAC/D,KAAK,CAAC,eAAe;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,cAAc;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IACD,IAAI,KAAI,CAAC;IACT,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IACD,aAAa,CAAC,KAAa,IAAG,CAAC;IAC/B,QAAQ,CAAC,MAAc,IAAG,CAAC;IAC3B,aAAa,CAAC,MAAc,IAAG,CAAC;IAChC,KAAK,CAAC,aAAa,KAAI,CAAC;IACxB,WAAW;QACT,OAAO,EAAE,MAAM,KAAI,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,eAAe,KAAI,CAAC;CACrB,CAAC","sourcesContent":["// No-op stub for non-Android platforms\nexport default {\n isAvailable(): boolean {\n return false;\n },\n hasStoragePermission(): boolean {\n return true;\n },\n async requestStoragePermissionAsync(): Promise<boolean> {\n return true;\n },\n addVoicePath(_path: string) {},\n setLicense(_userId: string, _password: string, _key: string) {},\n async initializeAsync(): Promise<boolean> {\n return false;\n },\n async getVoicesAsync() {\n return [];\n },\n async loadVoiceAsync(_voiceName: string): Promise<boolean> {\n return false;\n },\n async speakAsync(_text: string): Promise<number> {\n return -1;\n },\n stop() {},\n isSpeaking(): boolean {\n return false;\n },\n setSpeechRate(_rate: number) {},\n setPitch(_pitch: number) {},\n setAudioBoost(_boost: number) {},\n async shutdownAsync() {},\n addListener() {\n return { remove() {} };\n },\n removeListeners() {},\n};\n"]}
1
+ {"version":3,"file":"ExpoAcapelaTtsModule.js","sourceRoot":"","sources":["../src/ExpoAcapelaTtsModule.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,WAAW;QACT,OAAO,KAAK,CAAC;IACf,CAAC;IACD,YAAY,CAAC,KAAa,IAAG,CAAC;IAC9B,UAAU,CAAC,OAAe,EAAE,SAAiB,EAAE,IAAY,IAAG,CAAC;IAC/D,KAAK,CAAC,eAAe;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,MAAgB;QACnC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IACD,IAAI,KAAI,CAAC;IACT,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IACD,aAAa,CAAC,KAAa,IAAG,CAAC;IAC/B,QAAQ,CAAC,MAAc,IAAG,CAAC;IAC3B,aAAa,CAAC,MAAc,IAAG,CAAC;IAChC,KAAK,CAAC,aAAa,KAAI,CAAC;IACxB,WAAW;QACT,OAAO,EAAE,MAAM,KAAI,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,eAAe,KAAI,CAAC;CACrB,CAAC","sourcesContent":["export default {\n isAvailable(): boolean {\n return false;\n },\n addVoicePath(_path: string) {},\n setLicense(_userId: string, _password: string, _key: string) {},\n async initializeAsync(): Promise<boolean> {\n return false;\n },\n async getVoicesAsync(_paths: string[]) {\n return [];\n },\n async loadVoiceAsync(_voiceName: string): Promise<boolean> {\n return false;\n },\n async speakAsync(_text: string): Promise<number> {\n return -1;\n },\n stop() {},\n isSpeaking(): boolean {\n return false;\n },\n setSpeechRate(_rate: number) {},\n setPitch(_pitch: number) {},\n setAudioBoost(_boost: number) {},\n async shutdownAsync() {},\n addListener() {\n return { remove() {} };\n },\n removeListeners() {},\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@focus8/expo-acapela-tts",
3
- "version": "0.1.11",
3
+ "version": "0.2.0",
4
4
  "description": "Acapela TTS integration for Expo on Android",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -7,12 +7,10 @@ import {
7
7
 
8
8
  declare class ExpoAcapelaTtsModule extends NativeModule<ExpoAcapelaTtsModuleEvents> {
9
9
  isAvailable(): boolean;
10
- hasStoragePermission(): boolean;
11
- requestStoragePermissionAsync(): Promise<boolean>;
12
10
  addVoicePath(path: string): void;
13
11
  setLicense(userId: string, password: string, key: string): void;
14
12
  initializeAsync(): Promise<boolean>;
15
- getVoicesAsync(): Promise<AcapelaVoice[]>;
13
+ getVoicesAsync(paths: string[]): Promise<AcapelaVoice[]>;
16
14
  loadVoiceAsync(voiceName: string): Promise<boolean>;
17
15
  speakAsync(text: string): Promise<number>;
18
16
  stop(): void;
@@ -1,20 +1,13 @@
1
- // No-op stub for non-Android platforms
2
1
  export default {
3
2
  isAvailable(): boolean {
4
3
  return false;
5
4
  },
6
- hasStoragePermission(): boolean {
7
- return true;
8
- },
9
- async requestStoragePermissionAsync(): Promise<boolean> {
10
- return true;
11
- },
12
5
  addVoicePath(_path: string) {},
13
6
  setLicense(_userId: string, _password: string, _key: string) {},
14
7
  async initializeAsync(): Promise<boolean> {
15
8
  return false;
16
9
  },
17
- async getVoicesAsync() {
10
+ async getVoicesAsync(_paths: string[]) {
18
11
  return [];
19
12
  },
20
13
  async loadVoiceAsync(_voiceName: string): Promise<boolean> {