How to release microphone from pocketsphynx in Android

1

I'm using pocketsphynx library on Android for keyword spotting, and it serves its purpose great. However, when I am trying to release microphone to make use of it in another component of the app, I am unable to do so. I get the following error in logcat:

12-11 10:19:55.827 255-30344/? I/AudioFlinger_Threads: AudioFlinger's thread 0xa6cc0000 ready to run
12-11 10:19:55.849 255-31292/? W/APM::AudioPolicyManager: startInput(17675) preempting low-priority input 17671
12-11 10:19:55.859 255-29587/? W/AudioALSAStreamManager: -routingInputDevice(), input_device == AUDIO_DEVICE_NONE(0x0), return
12-11 10:19:55.924 27054-1900/? W/AudioRecord: dead IAudioRecord, creating a new one from obtainBuffer()
12-11 10:19:55.925 255-30344/? W/AudioALSAStreamManager: -routingInputDevice(), input_device == current_input_device(0x80000004), return
12-11 10:19:55.927 255-30346/? I/AudioFlinger_Threads: AudioFlinger's thread 0xaa880000 ready to run
12-11 10:19:55.930 255-31292/? W/APM::AudioPolicyManager: stopInput() unknown input 17671
12-11 10:19:55.930 255-31292/? W/APM::AudioPolicyManager: releaseInput() releasing unknown input 17671
12-11 10:19:55.931 255-953/? W/APM::AudioPolicyManager: startInput(AUDIO_SOURCE_HOTWORD) invalid, already started high-priority input 17675
12-11 10:19:55.931 27054-1900/? W/AudioRecord: restoreRecord_l() failed status -38
12-11 10:19:55.934 27054-1900/? E/AudioRecord-JNI: Error -38 during AudioRecord native read
12-11 10:19:55.951 27054-1900/? E/AudioProvider: audioRecord read failed
                                                 com.google.android.apps.gsa.shared.exception.GsaIOException: Error code: 393221 | not open
                                                     at com.google.android.libraries.assistant.hotword.a.a(SourceFile:67)
                                                     at com.google.android.libraries.assistant.hotword.b.run(SourceFile:30)
                                                     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
                                                     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
                                                     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
                                                     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                     at java.lang.Thread.run(Thread.java:818)

This happens when I'm attempting to use getUserMedia from WebView. Before doing so, I am calling

recognizer.cancel();

from my Activity, but that doesn't seem to help.

I also tried using .stop(), .removeListener(...) APIs, but the issue still remains. Please suggest if there is a way to release a hold on a mic that pocketsphinx is making, so that other components of the app can use mic again.

Any help is appreciated.

UPDATE 1: Added more logs and looked at Android code for AudioPolicyManager. It seems like two processes (31292 and 953) were trying to compete by doing startInput call, and one (31292) shut down another (953). Obviously, I may be misinterpreting the log.

UPDATE 2: I looked into pocketsphynx SpeechRecognizer.shutdown method and found that this is the method that actually releases the AudioRecord object. By trial-end-error I managed to figure out how to call shutdown and not crash the app (it has to happen in onResult, after all the listeners are removed). After that, my another component started to work. I did not yet have a chance to confirm whether or not I can re-start keyword spotting after shutdown. If re-initialization is required after that (which takes a lot of time), that's not going to be an acceptable workaround.

UPDATE 3: I confirmed that shutdown is not necessary to release a hold on a mic. I managed to make my other component after just calling stop API. The key seems to be that stopping pocketsphinx takes a bit of time, and the other component should wait for that. The event I used, that worked for me was onResult. At that point another component is already able to get a hold of a new AudioRecord. I still haven't tried re-starting pocketsphinx after that.

android
microphone
android-audiomanager
android-audiorecord
pocketsphinx-android
asked on Stack Overflow Dec 9, 2017 by Shalom Aleichem • edited Dec 12, 2017 by Shalom Aleichem

1 Answer

1

Alright, I got it to work. Calling SpeechRecognizer.shutdown is indeed unnecessary. I was able to use SpeechRecognizer.stop API while making sure to wait for the last result to come in in onResult callback of my RecognitionListener implementation. After that I am able to call getUserMedia browser API and it successfully gets a hold of a mic.

onResult code in my RecognitionListener implementation:

recognizer.removeListener(listener);

I also was able to confirm that re-starting recognition is easy, I just needed to do the following:

recognizer.addListener(listener);
recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);
recognizer.startListening(KWS_SEARCH);

Note: I am stopping the recognizer in a separate thread similarly to how recognizer was instantiated, but I have not confirmed whether or not it is necessary.

answered on Stack Overflow Dec 13, 2017 by Shalom Aleichem • edited Dec 13, 2017 by Shalom Aleichem

User contributions licensed under CC BY-SA 3.0