首页 > 解决方案 > 应用程序在后台时,热词检测无法重新启动,Android?

问题描述

因此,在我的助手应用程序中,我检测到用户何时说出特定单词,然后在后台启动我的应用程序。我在前台服务中使用了一个名为PocketSphinx的库来检测热词,它工作得相当好。这是我正在启动的前台服务:

public class HotKeyWordDetectionService extends Service
    implements RecognitionListener {


private static final String KWS_SEARCH = "wakeup";

/* Keyword we are looking for to activate menu */
private static final String KEYPHRASE = "hello buddy";
private SpeechRecognizer recognizer;
private ExecutorService service;



@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    startForeground(1, createNotification());
    service = Executors.newFixedThreadPool(3);
    // Recognizer initialization is a time-consuming and it involves IO,
    // so we execute it in a separate thread.
    init();
    return START_NOT_STICKY;
}


public void init() {
    service.submit(() -> {
        try {
            Assets assets = new Assets(HotKeyWordDetectionService5.this);
            File assetDir = assets.syncAssets();
            setupRecognizer(assetDir);
            Log.i("sphinx_test", "setup success: ");
            handler.sendEmptyMessage(0);
        } catch (IOException e) {
            Log.i("sphinx_test", "setup failed: "+"Failed to init recognizer " + e.getMessage());
            e.printStackTrace();
        }
    });
}

private Handler handler = new Handler(message -> {
    switchSearch(KWS_SEARCH);
    return false;
});


@Override
public void onResult(Hypothesis hypothesis) {
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        if (text.equals(KEYPHRASE)) 
            launchMyApp(); 
    }
}


private void switchSearch(String searchName) {
    recognizer.stop();
    recognizer.startListening(KWS_SEARCH);
}

private void setupRecognizer(File assetsDir) throws IOException {
    // The recognizer can be configured to perform multiple searches
    // of different kind and switch between them

    recognizer = SpeechRecognizerSetup.defaultSetup()
            .setAcousticModel(new File(assetsDir, "en-us-ptm"))
            .setDictionary(new File(assetsDir, "cmudict-en-us.dict"))
            .setRawLogDir(assetsDir) 
            .getRecognizer();
    recognizer.addListener(this);

    // Create keyword-activation search.
    recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);

    // Create grammar-based search for selection between demos
    File menuGrammar = new File(assetsDir, "menu.gram");
    recognizer.addGrammarSearch(MENU_SEARCH, menuGrammar);

    // Create grammar-based search for digit recognition
    File digitsGrammar = new File(assetsDir, "digits.gram");
    recognizer.addGrammarSearch(DIGITS_SEARCH, digitsGrammar);

    // Create language model search
    File languageModel = new File(assetsDir, "weather.dmp");
    recognizer.addNgramSearch(FORECAST_SEARCH, languageModel);

    // Phonetic search
    File phoneticModel = new File(assetsDir, "en-phone.dmp");
    recognizer.addAllphoneSearch(PHONE_SEARCH, phoneticModel);
}

}

当用户使用另一个应用程序(如 WhatsApp)录制音频时,问题就出现了。这会导致我的应用失去对麦克风的控制。用户在其他应用程序中使用完麦克风后,我的应用程序将无法重新控制麦克风,至少在 Android 11 及更高版本中,除非用户再次启动我的应用程序。这是我的前台服务尝试恢复热词检测但失败时的错误日志:

>com.parts.assitant E/IAudioFlinger: createRecord returned error -1
>com.parts.assitant E/AudioRecord: createRecord_l(5263): AudioFlinger could not create record track, status: -1
>com.parts.assitant W/AudioRecord: restoreRecord_l(5263): failed status -1, retries 2
>com.parts.assitant I/BpBinder: onLastStrongRef automatically unlinking death recipients: <uncached descriptor>

重点是我在应用程序处于前台时启动前台服务,所以我相信它不包含在 Android 11 及更高版本中引入的新限制中。但是在重新启动应用程序(再次在前台)之前,我的进程仍然无法重新控制麦克风。我该如何解决这个问题?

标签: androidmicrophoneforeground-servicepocketsphinx

解决方案


经过更多研究,我找到了解决方案。在 Android 11 及更高版本中,我必须在android:foregroundServiceType="microphone"我的前台服务声明中添加AndroidManifest.xml

<service android:name=".HotKeyWordDetectionService" android:foregroundServiceType="microphone"/>

还有我的服务onStartCommand()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
    startForeground(1, createNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
else
    startForeground(1, createNotification());

现在,当我使用 WhatsApp 或任何其他应用程序录制音频时,我的服务会停止工作,当我使用完麦克风后,我的服务会恢复成功的检测过程。


推荐阅读