From f7a13df899c30ddddbbf63274bc28174f6391f29 Mon Sep 17 00:00:00 2001 From: Sandeep Siddhartha Date: Wed, 11 Jun 2014 14:11:06 -0700 Subject: [PATCH] Add SoundTriggerManager to handle calls to SoundTrigger - We are abstracting out the nitty-gritty details of the code that talks to the SoundTrigger APIs as the VoiceInteractionService is mostly interested in the "voice" related aspects of the sound trigger APIs Change-Id: I4a450033040280f2e67d06785d2b05a0e5cdc192 --- core/java/android/service/voice/DspInfo.java | 6 +- .../service/voice/SoundTriggerManager.java | 73 +++++++++++++++++++ .../voice/VoiceInteractionService.java | 36 +++++++-- 3 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 core/java/android/service/voice/SoundTriggerManager.java diff --git a/core/java/android/service/voice/DspInfo.java b/core/java/android/service/voice/DspInfo.java index 5c113881f4cd4..086230962cee7 100644 --- a/core/java/android/service/voice/DspInfo.java +++ b/core/java/android/service/voice/DspInfo.java @@ -39,18 +39,18 @@ public class DspInfo { /** * Human readable voice detection engine version */ - public final String voiceEngineVersion; + public final int voiceEngineVersion; /** * Rated power consumption when detection is active. */ public final int powerConsumptionMw; public DspInfo(UUID voiceEngineId, String voiceEngineImplementor, - String voiceEngineDescription, String voiceEngineVersion, int powerConsumptionMw) { + String voiceEngineDescription, int version, int powerConsumptionMw) { this.voiceEngineId = voiceEngineId; this.voiceEngineImplementor = voiceEngineImplementor; this.voiceEngineDescription = voiceEngineDescription; - this.voiceEngineVersion = voiceEngineVersion; + this.voiceEngineVersion = version; this.powerConsumptionMw = powerConsumptionMw; } } diff --git a/core/java/android/service/voice/SoundTriggerManager.java b/core/java/android/service/voice/SoundTriggerManager.java new file mode 100644 index 0000000000000..2d049b9e8160e --- /dev/null +++ b/core/java/android/service/voice/SoundTriggerManager.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.voice; + +import android.hardware.soundtrigger.SoundTrigger; +import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; + +import java.util.ArrayList; + +/** + * Manager for {@link SoundTrigger} APIs. + * Currently this just acts as an abstraction over all SoundTrigger API calls. + * @hide + */ +public class SoundTriggerManager { + /** The {@link DspInfo} for the system, or null if none exists. */ + public DspInfo dspInfo; + + public SoundTriggerManager() { + ArrayList modules = new ArrayList<>(); + int status = SoundTrigger.listModules(modules); + if (status != SoundTrigger.STATUS_OK || modules.size() == 0) { + // TODO(sansid, elaurent): Figure out how to handle errors in listing the modules here. + dspInfo = null; + } else { + // TODO(sansid, elaurent): Figure out how to determine which module corresponds to the + // DSP hardware. + ModuleProperties properties = modules.get(0); + dspInfo = new DspInfo(properties.uuid, properties.implementor, properties.description, + properties.version, properties.powerConsumptionMw); + } + } + + /** + * @return True, if the keyphrase is supported on DSP for the given locale. + */ + public boolean isKeyphraseSupported(String keyphrase, String locale) { + // TODO(sansid): We also need to look into a SoundTrigger API that let's us + // query this. For now just return supported if there's a DSP available. + return dspInfo != null; + } + + /** + * @return True, if the keyphrase is has been enrolled for the given locale. + */ + public boolean isKeyphraseEnrolled(String keyphrase, String locale) { + // TODO(sansid, elaurent): Query SoundTrigger to list currently loaded sound models. + // They have been enrolled. + return false; + } + + /** + * @return True, if a recognition for the keyphrase is active for the given locale. + */ + public boolean isKeyphraseActive(String keyphrase, String locale) { + // TODO(sansid, elaurent): Check if the recognition for the keyphrase is currently active. + return false; + } +} diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 7c5d270f33d73..e0329f84564a2 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -28,6 +28,7 @@ import android.os.ServiceManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractionManagerService; + /** * Top-level service of the current global voice interactor, which is providing * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc. @@ -52,6 +53,16 @@ public class VoiceInteractionService extends Service { public static final String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; + // TODO(sansid): Unhide these. + /** @hide */ + public static final int KEYPHRASE_UNAVAILABLE = 0; + /** @hide */ + public static final int KEYPHRASE_UNENROLLED = 1; + /** @hide */ + public static final int KEYPHRASE_ENROLLED = 2; + /** @hide */ + public static final int KEYPHRASE_ACTIVE = 3; + /** * Name under which a VoiceInteractionService component publishes information about itself. * This meta-data should reference an XML resource containing a @@ -65,7 +76,7 @@ public class VoiceInteractionService extends Service { IVoiceInteractionManagerService mSystemService; - private DspInfo mDspInfo; + private SoundTriggerManager mSoundTriggerManager; private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo; public void startSession(Bundle args) { @@ -81,7 +92,7 @@ public class VoiceInteractionService extends Service { mSystemService = IVoiceInteractionManagerService.Stub.asInterface( ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager()); - // TODO(sansid): Read mDspInfo from the SoundTriggerModel API. + mSoundTriggerManager = new SoundTriggerManager(); } @Override @@ -93,21 +104,34 @@ public class VoiceInteractionService extends Service { } /** - * Indicates if always-on hotword detection is available for the given keyphrase and locale + * Gets the state of always-on hotword detection for the given keyphrase and locale * on this system. * Availability implies that the hardware on this system is capable of listening for * the given keyphrase or not. + * The return code is one of {@link #KEYPHRASE_UNAVAILABLE}, {@link #KEYPHRASE_UNENROLLED} + * {@link #KEYPHRASE_ENROLLED} or {@link #KEYPHRASE_ACTIVE}. + * * @param keyphrase The keyphrase whose availability is being checked. * @param locale The locale for which the availability is being checked. * @return Indicates if always-on hotword detection is available for the given keyphrase. * TODO(sansid): Unhide this. * @hide */ - public final boolean isAlwaysOnHotwordAvailable(String keyphrase, String locale) { + public final int getAlwaysOnKeyphraseAvailability(String keyphrase, String locale) { // The available keyphrases is a combination of DSP availability and // the keyphrases that have an enrollment application for them. - return mDspInfo != null - && mKeyphraseEnrollmentInfo.isKeyphraseEnrollmentSupported(keyphrase, locale); + if (!mSoundTriggerManager.isKeyphraseSupported(keyphrase, locale) + || !mKeyphraseEnrollmentInfo.isKeyphraseEnrollmentSupported(keyphrase, locale)) { + return KEYPHRASE_UNAVAILABLE; + } + if (!mSoundTriggerManager.isKeyphraseEnrolled(keyphrase, locale)) { + return KEYPHRASE_UNENROLLED; + } + if (!mSoundTriggerManager.isKeyphraseActive(keyphrase, locale)) { + return KEYPHRASE_ENROLLED; + } else { + return KEYPHRASE_ACTIVE; + } } /**