Merge "Unload logic for generic and keyphrase sound models." into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
78c0704d25
@@ -199,6 +199,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
modelData.setHandle(handle[0]);
|
||||
modelData.setLoaded();
|
||||
Slog.d(TAG, "Generic sound model loaded with handle:" + handle[0]);
|
||||
}
|
||||
modelData.setCallback(callback);
|
||||
modelData.setRecognitionConfig(recognitionConfig);
|
||||
@@ -227,7 +228,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
|
||||
synchronized (mLock) {
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
|
||||
Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
|
||||
+ " soundModel=" + soundModel + ", listener=" + listener.asBinder()
|
||||
+ ", recognitionConfig=" + recognitionConfig);
|
||||
Slog.d(TAG, "moduleProperties=" + mModuleProperties);
|
||||
@@ -243,13 +244,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
|
||||
if (mModuleProperties == null) {
|
||||
Slog.w(TAG, "Attempting startRecognition without the capability");
|
||||
Slog.w(TAG, "Attempting startKeyphraseRecognition without the capability");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if (mModule == null) {
|
||||
mModule = SoundTrigger.attachModule(mModuleProperties.id, this, null);
|
||||
if (mModule == null) {
|
||||
Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
|
||||
Slog.w(TAG, "startKeyphraseRecognition cannot attach to sound trigger module");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -348,26 +349,29 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
|
||||
if (currentCallback == null || !modelData.isModelStarted()) {
|
||||
// startRecognition hasn't been called or it failed.
|
||||
Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
|
||||
// startGenericRecognition hasn't been called or it failed.
|
||||
Slog.w(TAG, "Attempting stopGenericRecognition without a successful" +
|
||||
" startGenericRecognition");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if (currentCallback.asBinder() != listener.asBinder()) {
|
||||
// We don't allow a different listener to stop the recognition than the one
|
||||
// that started it.
|
||||
Slog.w(TAG, "Attempting stopRecognition for another recognition");
|
||||
Slog.w(TAG, "Attempting stopGenericRecognition for another recognition");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
int status = stopGenericRecognitionLocked(modelData, false /* don't notify for synchronous calls */);
|
||||
int status = stopGenericRecognitionLocked(modelData,
|
||||
false /* don't notify for synchronous calls */);
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
Slog.w(TAG, "stopGenericRecognition failed: " + status);
|
||||
return status;
|
||||
}
|
||||
|
||||
// We leave the sound model loaded but not started, this helps us when we start
|
||||
// back.
|
||||
// Also clear the internal state once the recognition has been stopped.
|
||||
modelData.clearState();
|
||||
modelData.setLoaded();
|
||||
modelData.clearCallback();
|
||||
if (!computeRecognitionRunning()) {
|
||||
internalClearGlobalStateLocked();
|
||||
@@ -471,6 +475,66 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
return mModuleProperties;
|
||||
}
|
||||
|
||||
int unloadKeyphraseSoundModel(int keyphraseId) {
|
||||
if (mModule == null || mCurrentKeyphraseModelHandle == INVALID_VALUE) {
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if (mKeyphraseId != keyphraseId) {
|
||||
Slog.w(TAG, "Given sound model is not the one loaded.");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
// Stop recognition if it's the current one.
|
||||
mRequested = false;
|
||||
int status = updateRecognitionLocked(false /* don't notify */);
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
|
||||
}
|
||||
|
||||
status = mModule.unloadSoundModel(mCurrentKeyphraseModelHandle);
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
|
||||
}
|
||||
internalClearKeyphraseSoundModelLocked();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
int unloadGenericSoundModel(UUID modelId) {
|
||||
if (modelId == null || mModule == null) {
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
ModelData modelData = mGenericModelDataMap.get(modelId);
|
||||
if (modelData == null) {
|
||||
Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (!modelData.isModelLoaded()) {
|
||||
// Nothing to do here.
|
||||
Slog.i(TAG, "Unload: Given generic model is not loaded:" + modelId);
|
||||
return STATUS_OK;
|
||||
}
|
||||
if (modelData.isModelStarted()) {
|
||||
int status = stopGenericRecognitionLocked(modelData,
|
||||
false /* don't notify for synchronous calls */);
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
Slog.w(TAG, "stopGenericRecognition failed: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
int status = mModule.unloadSoundModel(modelData.getHandle());
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
|
||||
Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
|
||||
}
|
||||
mGenericModelDataMap.remove(modelId);
|
||||
if (DBG) dumpGenericModelState();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
//---- SoundTrigger.StatusListener methods
|
||||
@Override
|
||||
public void onRecognition(RecognitionEvent event) {
|
||||
@@ -913,6 +977,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.i(TAG, "startRecognition successful.");
|
||||
modelData.setStarted();
|
||||
// Notify of resume if needed.
|
||||
if (notify) {
|
||||
@@ -923,6 +988,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DBG) dumpGenericModelState();
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -951,9 +1017,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DBG) dumpGenericModelState();
|
||||
return status;
|
||||
}
|
||||
|
||||
private void dumpGenericModelState() {
|
||||
for (UUID modelId : mGenericModelDataMap.keySet()) {
|
||||
ModelData modelData = mGenericModelDataMap.get(modelId);
|
||||
Slog.i(TAG, "Model :" + modelData.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Computes whether we have any recognition running at all (voice or generic). Sets
|
||||
// the mRecognitionRunning variable with the result.
|
||||
private boolean computeRecognitionRunning() {
|
||||
@@ -1069,5 +1143,18 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
synchronized RecognitionConfig getRecognitionConfig() {
|
||||
return mRecognitionConfig;
|
||||
}
|
||||
|
||||
String stateToString() {
|
||||
switch(mModelState) {
|
||||
case MODEL_NOTLOADED: return "NOT_LOADED";
|
||||
case MODEL_LOADED: return "LOADED";
|
||||
case MODEL_STARTED: return "STARTED";
|
||||
}
|
||||
return "Unknown state";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Handle: " + mModelHandle + "ModelState: " + stateToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,5 +75,7 @@ public abstract class SoundTriggerInternal {
|
||||
|
||||
public abstract ModuleProperties getModuleProperties();
|
||||
|
||||
public abstract int unloadKeyphraseModel(int keyphaseId);
|
||||
|
||||
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
}
|
||||
|
||||
@@ -122,10 +122,10 @@ public class SoundTriggerService extends SystemService {
|
||||
public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
|
||||
RecognitionConfig config) {
|
||||
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
|
||||
if (!isInitialized()) return STATUS_ERROR;
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
|
||||
}
|
||||
if (!isInitialized()) return STATUS_ERROR;
|
||||
|
||||
GenericSoundModel model = getSoundModel(parcelUuid);
|
||||
if (model == null) {
|
||||
@@ -173,6 +173,8 @@ public class SoundTriggerService extends SystemService {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
|
||||
}
|
||||
// Unload the model if it is loaded.
|
||||
mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
|
||||
mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
|
||||
}
|
||||
}
|
||||
@@ -215,6 +217,12 @@ public class SoundTriggerService extends SystemService {
|
||||
return mSoundTriggerHelper.getModuleProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int unloadKeyphraseModel(int keyphraseId) {
|
||||
if (!isInitialized()) return STATUS_ERROR;
|
||||
return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!isInitialized()) return;
|
||||
|
||||
@@ -760,6 +760,10 @@ public class VoiceInteractionManagerService extends SystemService {
|
||||
final long caller = Binder.clearCallingIdentity();
|
||||
boolean deleted = false;
|
||||
try {
|
||||
int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
|
||||
if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
|
||||
Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
|
||||
}
|
||||
deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
|
||||
return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
|
||||
} finally {
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
package="com.android.test.soundtrigger">
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCk" />
|
||||
<application>
|
||||
<activity
|
||||
android:name="TestSoundTriggerActivity"
|
||||
android:label="SoundTrigger Test Application"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@android:style/Theme.Material">
|
||||
<!--
|
||||
<intent-filter>
|
||||
|
||||
@@ -28,6 +28,8 @@ import android.media.soundtrigger.SoundTriggerManager;
|
||||
import android.text.Editable;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -54,6 +56,8 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
private TextView mDebugView = null;
|
||||
private int mSelectedModelId = 1;
|
||||
private ScrollView mScrollView = null;
|
||||
private PowerManager.WakeLock mScreenWakelock;
|
||||
private Handler mHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -66,6 +70,7 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
mDebugView.setMovementMethod(new ScrollingMovementMethod());
|
||||
mSoundTriggerUtil = new SoundTriggerUtil(this);
|
||||
mRandom = new Random();
|
||||
mHandler = new Handler();
|
||||
}
|
||||
|
||||
private void postMessage(String msg) {
|
||||
@@ -85,24 +90,43 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
});
|
||||
}
|
||||
|
||||
private UUID getSelectedUuid() {
|
||||
private synchronized UUID getSelectedUuid() {
|
||||
if (mSelectedModelId == 2) return mModelUuid2;
|
||||
if (mSelectedModelId == 3) return mModelUuid3;
|
||||
return mModelUuid1; // Default.
|
||||
}
|
||||
|
||||
private void setDetector(SoundTriggerDetector detector) {
|
||||
if (mSelectedModelId == 2) mDetector2 = detector;
|
||||
if (mSelectedModelId == 3) mDetector3 = detector;
|
||||
private synchronized void setDetector(SoundTriggerDetector detector) {
|
||||
if (mSelectedModelId == 2) {
|
||||
mDetector2 = detector;
|
||||
return;
|
||||
}
|
||||
if (mSelectedModelId == 3) {
|
||||
mDetector3 = detector;
|
||||
return;
|
||||
}
|
||||
mDetector1 = detector;
|
||||
}
|
||||
|
||||
private SoundTriggerDetector getDetector() {
|
||||
private synchronized SoundTriggerDetector getDetector() {
|
||||
if (mSelectedModelId == 2) return mDetector2;
|
||||
if (mSelectedModelId == 3) return mDetector3;
|
||||
return mDetector1;
|
||||
}
|
||||
|
||||
private void screenWakeup() {
|
||||
PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
|
||||
if (mScreenWakelock == null) {
|
||||
mScreenWakelock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
|
||||
}
|
||||
mScreenWakelock.acquire();
|
||||
}
|
||||
|
||||
private void screenRelease() {
|
||||
PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
|
||||
mScreenWakelock.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user clicks the enroll button.
|
||||
* Performs a fresh enrollment.
|
||||
@@ -139,7 +163,7 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid1);
|
||||
boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid);
|
||||
if (status) {
|
||||
Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid,
|
||||
Toast.LENGTH_SHORT)
|
||||
@@ -204,22 +228,28 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
public void onRadioButtonClicked(View view) {
|
||||
public synchronized void onRadioButtonClicked(View view) {
|
||||
// Is the button now checked?
|
||||
boolean checked = ((RadioButton) view).isChecked();
|
||||
// Check which radio button was clicked
|
||||
switch(view.getId()) {
|
||||
case R.id.model_one:
|
||||
if (checked) mSelectedModelId = 1;
|
||||
postMessage("Selected model one.");
|
||||
if (checked) {
|
||||
mSelectedModelId = 1;
|
||||
postMessage("Selected model one.");
|
||||
}
|
||||
break;
|
||||
case R.id.model_two:
|
||||
if (checked) mSelectedModelId = 2;
|
||||
postMessage("Selected model two.");
|
||||
if (checked) {
|
||||
mSelectedModelId = 2;
|
||||
postMessage("Selected model two.");
|
||||
}
|
||||
break;
|
||||
case R.id.model_three:
|
||||
if (checked) mSelectedModelId = 3;
|
||||
postMessage("Selected model three.");
|
||||
if (checked) {
|
||||
mSelectedModelId = 3;
|
||||
postMessage("Selected model three.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -232,6 +262,13 @@ public class TestSoundTriggerActivity extends Activity {
|
||||
|
||||
public void onDetected(SoundTriggerDetector.EventPayload event) {
|
||||
postMessage("onDetected(): " + eventPayloadToString(event));
|
||||
screenWakeup();
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
screenRelease();
|
||||
}
|
||||
}, 1000L);
|
||||
}
|
||||
|
||||
public void onError() {
|
||||
|
||||
Reference in New Issue
Block a user