Merge "SoundTriggerHelper: improve in call behavior" into rvc-dev am: b6c403b091
Change-Id: I189d17d48aa5306159d5ec021c2234cc3d78a32c
This commit is contained in:
@@ -40,6 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
|
|||||||
import android.hardware.soundtrigger.SoundTriggerModule;
|
import android.hardware.soundtrigger.SoundTriggerModule;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.DeadObjectException;
|
import android.os.DeadObjectException;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.ServiceType;
|
import android.os.PowerManager.ServiceType;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -113,6 +116,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
|
|
||||||
private PowerSaveModeListener mPowerSaveModeListener;
|
private PowerSaveModeListener mPowerSaveModeListener;
|
||||||
|
|
||||||
|
// Handler to process call state changes will delay to allow time for the audio
|
||||||
|
// and sound trigger HALs to process the end of call notifications
|
||||||
|
// before we re enable pending recognition requests.
|
||||||
|
private final Handler mHandler;
|
||||||
|
private static final int MSG_CALL_STATE_CHANGED = 0;
|
||||||
|
private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;
|
||||||
|
|
||||||
SoundTriggerHelper(Context context) {
|
SoundTriggerHelper(Context context) {
|
||||||
ArrayList <ModuleProperties> modules = new ArrayList<>();
|
ArrayList <ModuleProperties> modules = new ArrayList<>();
|
||||||
int status = SoundTrigger.listModules(modules);
|
int status = SoundTrigger.listModules(modules);
|
||||||
@@ -130,6 +140,31 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
// TODO: Figure out how to determine which module corresponds to the DSP hardware.
|
// TODO: Figure out how to determine which module corresponds to the DSP hardware.
|
||||||
mModuleProperties = modules.get(0);
|
mModuleProperties = modules.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Looper looper = Looper.myLooper();
|
||||||
|
if (looper == null) {
|
||||||
|
looper = Looper.getMainLooper();
|
||||||
|
}
|
||||||
|
if (looper != null) {
|
||||||
|
mHandler = new Handler(looper) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case MSG_CALL_STATE_CHANGED:
|
||||||
|
synchronized (mLock) {
|
||||||
|
onCallStateChangedLocked(
|
||||||
|
TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Slog.e(TAG, "unknown message in handler:" + msg.what);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
mHandler = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -227,6 +262,37 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int prepareForRecognition(ModelData modelData) {
|
||||||
|
if (mModule == null) {
|
||||||
|
mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
|
||||||
|
if (mModule == null) {
|
||||||
|
Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module");
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load the model if it is not loaded.
|
||||||
|
if (!modelData.isModelLoaded()) {
|
||||||
|
// Before we try and load this model, we should first make sure that any other
|
||||||
|
// models that don't have an active recognition/dead callback are unloaded. Since
|
||||||
|
// there is a finite limit on the number of models that the hardware may be able to
|
||||||
|
// have loaded, we want to make sure there's room for our model.
|
||||||
|
stopAndUnloadDeadModelsLocked();
|
||||||
|
int[] handle = new int[] { 0 };
|
||||||
|
int status = mModule.loadSoundModel(modelData.getSoundModel(), handle);
|
||||||
|
if (status != SoundTrigger.STATUS_OK) {
|
||||||
|
Slog.w(TAG, "prepareForRecognition: loadSoundModel failed with status: " + status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
modelData.setHandle(handle[0]);
|
||||||
|
modelData.setLoaded();
|
||||||
|
if (DBG) {
|
||||||
|
Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts recognition for the given sound model. A single routine for both keyphrase and
|
* Starts recognition for the given sound model. A single routine for both keyphrase and
|
||||||
* generic sound models.
|
* generic sound models.
|
||||||
@@ -248,12 +314,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
Slog.w(TAG, "Attempting startRecognition without the capability");
|
Slog.w(TAG, "Attempting startRecognition without the capability");
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
if (mModule == null) {
|
|
||||||
mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
|
IRecognitionStatusCallback oldCallback = modelData.getCallback();
|
||||||
if (mModule == null) {
|
if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
|
||||||
Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
|
Slog.w(TAG, "Canceling previous recognition for model id: "
|
||||||
return STATUS_ERROR;
|
+ modelData.getModelId());
|
||||||
|
try {
|
||||||
|
oldCallback.onError(STATUS_ERROR);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.w(TAG, "RemoteException in onDetectionStopped", e);
|
||||||
}
|
}
|
||||||
|
modelData.clearCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the existing SoundModel is different (for the same UUID for Generic and same
|
// If the existing SoundModel is different (for the same UUID for Generic and same
|
||||||
@@ -287,48 +358,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRecognitionStatusCallback oldCallback = modelData.getCallback();
|
|
||||||
if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
|
|
||||||
Slog.w(TAG, "Canceling previous recognition for model id: " +
|
|
||||||
modelData.getModelId());
|
|
||||||
try {
|
|
||||||
oldCallback.onError(STATUS_ERROR);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Slog.w(TAG, "RemoteException in onDetectionStopped", e);
|
|
||||||
}
|
|
||||||
modelData.clearCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the model if it is not loaded.
|
|
||||||
if (!modelData.isModelLoaded()) {
|
|
||||||
// Before we try and load this model, we should first make sure that any other
|
|
||||||
// models that don't have an active recognition/dead callback are unloaded. Since
|
|
||||||
// there is a finite limit on the number of models that the hardware may be able to
|
|
||||||
// have loaded, we want to make sure there's room for our model.
|
|
||||||
stopAndUnloadDeadModelsLocked();
|
|
||||||
int[] handle = new int[] { INVALID_VALUE };
|
|
||||||
int status = mModule.loadSoundModel(soundModel, handle);
|
|
||||||
if (status != SoundTrigger.STATUS_OK) {
|
|
||||||
Slog.w(TAG, "loadSoundModel call failed with " + status);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
if (handle[0] == INVALID_VALUE) {
|
|
||||||
Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
|
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
|
||||||
modelData.setHandle(handle[0]);
|
|
||||||
modelData.setLoaded();
|
|
||||||
Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
|
|
||||||
}
|
|
||||||
modelData.setCallback(callback);
|
modelData.setCallback(callback);
|
||||||
modelData.setRequested(true);
|
modelData.setRequested(true);
|
||||||
modelData.setRecognitionConfig(recognitionConfig);
|
modelData.setRecognitionConfig(recognitionConfig);
|
||||||
modelData.setSoundModel(soundModel);
|
modelData.setSoundModel(soundModel);
|
||||||
|
|
||||||
int status = startRecognitionLocked(modelData,
|
if (!isRecognitionAllowed()) {
|
||||||
|
initializeTelephonyAndPowerStateListeners();
|
||||||
|
return STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = prepareForRecognition(modelData);
|
||||||
|
if (status != STATUS_OK) {
|
||||||
|
Slog.w(TAG, "startRecognition failed to prepare model for recognition");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status = startRecognitionLocked(modelData,
|
||||||
false /* Don't notify for synchronous calls */);
|
false /* Don't notify for synchronous calls */);
|
||||||
|
|
||||||
// Initialize power save, call active state monitoring logic.
|
// Initialize power save, call active state monitoring logic.
|
||||||
if (status == STATUS_OK) {
|
if (status == STATUS_OK) {
|
||||||
initializeTelephonyAndPowerStateListeners();
|
initializeTelephonyAndPowerStateListeners();
|
||||||
}
|
}
|
||||||
@@ -398,7 +446,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
if (DBG) {
|
if (DBG) {
|
||||||
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
|
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
|
||||||
callback.asBinder());
|
callback.asBinder());
|
||||||
Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
|
Slog.d(TAG, "current callback="
|
||||||
|
+ ((modelData == null || modelData.getCallback() == null) ? "null" :
|
||||||
modelData.getCallback().asBinder()));
|
modelData.getCallback().asBinder()));
|
||||||
}
|
}
|
||||||
int status = stopRecognition(modelData, callback);
|
int status = stopRecognition(modelData, callback);
|
||||||
@@ -507,8 +556,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
|
MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
|
||||||
ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
|
ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
|
||||||
if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
|
if (mModule == null || modelData == null || !modelData.isModelLoaded()
|
||||||
!modelData.isKeyphraseModel()) {
|
|| !modelData.isKeyphraseModel()) {
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,6 +992,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
if (start) {
|
if (start) {
|
||||||
|
int status = prepareForRecognition(model);
|
||||||
|
if (status != STATUS_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
return startRecognitionLocked(model, notify);
|
return startRecognitionLocked(model, notify);
|
||||||
} else {
|
} else {
|
||||||
return stopRecognitionLocked(model, notify);
|
return stopRecognitionLocked(model, notify);
|
||||||
@@ -992,8 +1045,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onCallStateChanged(int state, String arg1) {
|
public void onCallStateChanged(int state, String arg1) {
|
||||||
if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
|
if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
|
||||||
synchronized (mLock) {
|
|
||||||
onCallStateChangedLocked(TelephonyManager.CALL_STATE_OFFHOOK == state);
|
if (mHandler != null) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mHandler.removeMessages(MSG_CALL_STATE_CHANGED);
|
||||||
|
Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0);
|
||||||
|
mHandler.sendMessageDelayed(
|
||||||
|
msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0
|
||||||
|
: CALL_INACTIVE_MSG_DELAY_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1216,9 +1276,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
// models.
|
// models.
|
||||||
private int startRecognitionLocked(ModelData modelData, boolean notify) {
|
private int startRecognitionLocked(ModelData modelData, boolean notify) {
|
||||||
IRecognitionStatusCallback callback = modelData.getCallback();
|
IRecognitionStatusCallback callback = modelData.getCallback();
|
||||||
int handle = modelData.getHandle();
|
|
||||||
RecognitionConfig config = modelData.getRecognitionConfig();
|
RecognitionConfig config = modelData.getRecognitionConfig();
|
||||||
if (callback == null || handle == INVALID_VALUE || config == null) {
|
if (callback == null || !modelData.isModelLoaded() || config == null) {
|
||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
Slog.w(TAG, "startRecognition: Bad data passed in.");
|
Slog.w(TAG, "startRecognition: Bad data passed in.");
|
||||||
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
|
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
|
||||||
@@ -1235,7 +1294,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
if (mModule == null) {
|
if (mModule == null) {
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
int status = mModule.startRecognition(handle, config);
|
int status = mModule.startRecognition(modelData.getHandle(), config);
|
||||||
if (status != SoundTrigger.STATUS_OK) {
|
if (status != SoundTrigger.STATUS_OK) {
|
||||||
Slog.w(TAG, "startRecognition failed with " + status);
|
Slog.w(TAG, "startRecognition failed with " + status);
|
||||||
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
|
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
|
||||||
@@ -1376,7 +1435,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
|
|
||||||
// Model handle is an integer used by the HAL as an identifier for sound
|
// Model handle is an integer used by the HAL as an identifier for sound
|
||||||
// models.
|
// models.
|
||||||
private int mModelHandle = INVALID_VALUE;
|
private int mModelHandle;
|
||||||
|
|
||||||
// The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel.
|
// The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel.
|
||||||
private SoundModel mSoundModel = null;
|
private SoundModel mSoundModel = null;
|
||||||
@@ -1436,7 +1495,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
|||||||
|
|
||||||
synchronized void clearState() {
|
synchronized void clearState() {
|
||||||
mModelState = MODEL_NOTLOADED;
|
mModelState = MODEL_NOTLOADED;
|
||||||
mModelHandle = INVALID_VALUE;
|
|
||||||
mRecognitionConfig = null;
|
mRecognitionConfig = null;
|
||||||
mRequested = false;
|
mRequested = false;
|
||||||
mCallback = null;
|
mCallback = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user