capacitor-microphone 0.1.15 → 0.1.17

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.
@@ -40,6 +40,8 @@ private boolean isDestroyed = false;
40
40
  private long lastStopTime = 0;
41
41
  private static final long RESTART_COOLDOWN_MS = 400;
42
42
  private Runnable delayedStartRunnable;
43
+ private boolean restartScheduled = false;
44
+
43
45
 
44
46
 
45
47
  @PluginMethod
@@ -149,6 +151,22 @@ public void startListening(PluginCall call) {
149
151
  startListeningInternal(call, lang);
150
152
  }
151
153
 
154
+ private void safeRestartListening() {
155
+ if (restartScheduled) return;
156
+ restartScheduled = true;
157
+
158
+ getActivity()
159
+ .getWindow()
160
+ .getDecorView()
161
+ .postDelayed(() -> {
162
+ restartScheduled = false;
163
+ if (!isDestroyed && isListening && speechRecognizer != null) {
164
+ speechRecognizer.startListening(speechIntent);
165
+ }
166
+ }, 350);
167
+ }
168
+
169
+
152
170
 
153
171
  private void startListeningInternal(PluginCall call, String lang) {
154
172
  isDestroyed = false;
@@ -187,10 +205,7 @@ private void startListeningInternal(PluginCall call, String lang) {
187
205
 
188
206
  if (error == SpeechRecognizer.ERROR_NO_MATCH ||
189
207
  error == SpeechRecognizer.ERROR_SPEECH_TIMEOUT) {
190
-
191
- if (!isDestroyed && isListening && speechRecognizer != null) {
192
- speechRecognizer.startListening(speechIntent);
193
- }
208
+ safeRestartListening();
194
209
  return;
195
210
  }
196
211
 
@@ -215,7 +230,7 @@ private void startListeningInternal(PluginCall call, String lang) {
215
230
  }
216
231
 
217
232
  if (!isDestroyed && isListening && speechRecognizer != null) {
218
- speechRecognizer.startListening(speechIntent);
233
+ safeRestartListening();
219
234
  }
220
235
  }
221
236
 
@@ -250,6 +265,14 @@ private void startListeningInternal(PluginCall call, String lang) {
250
265
  RecognizerIntent.EXTRA_LANGUAGE, lang);
251
266
  speechIntent.putExtra(
252
267
  RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
268
+ speechIntent.putExtra(
269
+ RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
270
+ 1500
271
+ );
272
+ speechIntent.putExtra(
273
+ RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
274
+ 1500
275
+ );
253
276
 
254
277
 
255
278
  speechRecognizer.startListening(speechIntent);
@@ -317,98 +340,147 @@ private void startListeningInternal(PluginCall call, String lang) {
317
340
  call.resolve();
318
341
  }
319
342
 
343
+
344
+
320
345
  @PluginMethod
321
346
  public void restartListening(PluginCall call) {
322
- // 1. Obtener lenguaje actual o del parámetro
323
347
  String currentLang = "es-MX";
324
- if (currentCall != null) {
325
- currentLang = currentCall.getString("lang", "es-MX");
326
- } else {
327
- currentLang = call.getString("lang", "es-MX");
348
+ if (speechIntent != null) {
349
+ currentLang = speechIntent.getStringExtra(RecognizerIntent.EXTRA_LANGUAGE);
350
+ if (currentLang == null) currentLang = "es-MX";
328
351
  }
352
+ currentLang = call.getString("lang", currentLang);
329
353
 
330
- // 2. Guardar para usar después
331
354
  final String lang = currentLang;
332
355
 
333
- // 3. Enviar respuesta INMEDIATA
356
+ // Resolver INMEDIATAMENTE
334
357
  call.resolve(new JSObject().put("success", true));
335
358
 
336
- // 4. En el background, hacer el restart REAL
337
- new Thread(() -> {
338
- try {
339
- // 4.1 Detener completamente
340
- if (isListening) {
341
- getActivity().runOnUiThread(() -> {
342
- isListening = false;
343
- isDestroyed = true;
344
-
345
- if (delayedStartRunnable != null) {
346
- getActivity()
347
- .getWindow()
348
- .getDecorView()
349
- .removeCallbacks(delayedStartRunnable);
350
- delayedStartRunnable = null;
351
- }
359
+ // Hacer el restart real EN EL UI THREAD desde el inicio
360
+ getActivity().runOnUiThread(() -> {
361
+ // DESTRUIR TODO
362
+ isListening = false;
363
+ isDestroyed = true;
352
364
 
353
- if (speechRecognizer != null) {
354
- speechRecognizer.cancel();
355
- speechRecognizer.destroy();
356
- speechRecognizer = null;
357
- }
365
+ if (delayedStartRunnable != null) {
366
+ getActivity()
367
+ .getWindow()
368
+ .getDecorView()
369
+ .removeCallbacks(delayedStartRunnable);
370
+ delayedStartRunnable = null;
371
+ }
358
372
 
359
- currentCall = null;
360
- speechIntent = null;
361
- });
373
+ if (speechRecognizer != null) {
374
+ speechRecognizer.cancel();
375
+ speechRecognizer.setRecognitionListener(null);
376
+ speechRecognizer.destroy();
377
+ speechRecognizer = null;
378
+ }
362
379
 
363
- // 4.2 Esperar 500ms
364
- Thread.sleep(500);
365
- }
380
+ currentCall = null;
381
+ speechIntent = null;
366
382
 
367
- // 4.3 Reiniciar
368
- getActivity().runOnUiThread(() -> {
369
- isListening = true;
370
- isDestroyed = false;
383
+ // Reiniciar después de 500ms
384
+ getActivity()
385
+ .getWindow()
386
+ .getDecorView()
387
+ .postDelayed(() -> startListeningInternalWithoutCall(lang), 500);
388
+ });
389
+ }
371
390
 
372
- // Usar el call ORIGINAL pero solo para startListeningInternal
373
- // No hay problema porque ya fue resuelto
374
- startListeningInternal(call, lang);
375
- });
391
+ // Nueva versión que NO requiere un PluginCall
392
+ private void startListeningInternalWithoutCall(String lang) {
393
+ isDestroyed = false;
394
+ isListening = true;
376
395
 
377
- } catch (Exception e) {
378
- // Log error si es necesario
379
- }
380
- }).start();
381
- }
396
+ if (getPermissionState("microphone") != PermissionState.GRANTED) {
397
+ return;
398
+ }
382
399
 
383
- private void destroyEverything() {
384
- // Limpiar runnables
385
- if (delayedStartRunnable != null) {
386
- getActivity().runOnUiThread(() -> {
387
- getActivity()
388
- .getWindow()
389
- .getDecorView()
390
- .removeCallbacks(delayedStartRunnable);
391
- });
392
- delayedStartRunnable = null;
400
+ if (!SpeechRecognizer.isRecognitionAvailable(getContext())) {
401
+ return;
393
402
  }
394
403
 
395
- // Limpiar speech recognizer
396
404
  if (speechRecognizer != null) {
405
+ stopSpeech();
406
+ }
407
+
408
+ getActivity().runOnUiThread(() -> {
397
409
  try {
398
- speechRecognizer.cancel();
399
- speechRecognizer.destroy();
410
+ speechRecognizer = SpeechRecognizer.createSpeechRecognizer(getActivity());
411
+ speechRecognizer.setRecognitionListener(new RecognitionListener() {
412
+ @Override public void onReadyForSpeech(Bundle params) {}
413
+ @Override public void onBeginningOfSpeech() {}
414
+ @Override public void onRmsChanged(float rmsdB) {}
415
+ @Override public void onBufferReceived(byte[] buffer) {}
416
+ @Override public void onEndOfSpeech() {}
417
+
418
+ @Override
419
+ public void onError(int error) {
420
+ if (isDestroyed || !isListening) return;
421
+
422
+ if (error == SpeechRecognizer.ERROR_NO_MATCH ||
423
+ error == SpeechRecognizer.ERROR_SPEECH_TIMEOUT) {
424
+ if (!isDestroyed && isListening && speechRecognizer != null) {
425
+ safeRestartListening();
426
+ }
427
+ return;
428
+ }
429
+
430
+ stopSpeech();
431
+ }
432
+
433
+ @Override
434
+ public void onResults(Bundle results) {
435
+ if (!isListening) return;
436
+
437
+ ArrayList<String> matches =
438
+ results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
439
+
440
+ if (matches != null && !matches.isEmpty()) {
441
+ notifyListeners(
442
+ "partialResult",
443
+ new JSObject()
444
+ .put("text", matches.get(0))
445
+ .put("isFinal", true)
446
+ );
447
+ }
448
+
449
+ safeRestartListening();
450
+ }
451
+
452
+ @Override
453
+ public void onPartialResults(Bundle partialResults) {
454
+ if (!isListening || isDestroyed) return;
455
+
456
+ ArrayList<String> matches =
457
+ partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
458
+
459
+ if (matches != null && !matches.isEmpty()) {
460
+ notifyListeners(
461
+ "partialResult",
462
+ new JSObject()
463
+ .put("text", matches.get(0))
464
+ .put("isFinal", false)
465
+ );
466
+ }
467
+ }
468
+
469
+ @Override public void onEvent(int eventType, Bundle params) {}
470
+ });
471
+
472
+ speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
473
+ speechIntent.putExtra(
474
+ RecognizerIntent.EXTRA_LANGUAGE_MODEL,
475
+ RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
476
+ speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, lang);
477
+ speechIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
478
+
479
+ speechRecognizer.startListening(speechIntent);
400
480
  } catch (Exception e) {
401
- // Ignorar
481
+ // Log error si es necesario
402
482
  }
403
- speechRecognizer = null;
404
- }
405
-
406
- // Resetear estado
407
- currentCall = null;
408
- speechIntent = null;
409
- isListening = false;
410
- isDestroyed = true;
411
- lastStopTime = System.currentTimeMillis();
483
+ });
412
484
  }
413
485
 
414
486
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-microphone",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "plugin to use the microphone",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",