Loading tests/SoundTriggerTestApp/res/layout/main.xml +8 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,14 @@ android:text="@string/play_trigger" android:onClick="onPlayTriggerButtonClicked" android:padding="20dp" /> <Button android:id="@+id/get_state_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/get_model_state" android:onClick="onGetModelStateButtonClicked" android:padding="20dp" /> </LinearLayout> <LinearLayout Loading tests/SoundTriggerTestApp/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ <string name="start_recog">Start</string> <string name="stop_recog">Stop</string> <string name="play_trigger">Play Trigger Audio</string> <string name="get_model_state">Get State</string> <string name="capture">Capture Audio</string> <string name="stop_capture">Stop Capturing Audio</string> <string name="play_capture">Play Captured Audio</string> Loading tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java +8 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,14 @@ public class SoundTriggerTestActivity extends Activity implements SoundTriggerTe } } public synchronized void onGetModelStateButtonClicked(View v) { if (mService == null) { Log.e(TAG, "Can't get model state: not bound to SoundTriggerTestService"); } else { mService.getModelState(mSelectedModelUuid); } } public synchronized void onCaptureAudioCheckboxClicked(View v) { // See if we have the right permissions if (!mService.hasMicrophonePermission()) { Loading tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java +63 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioManager; Loading @@ -46,6 +48,7 @@ import java.util.Properties; import java.util.Random; import java.util.UUID; public class SoundTriggerTestService extends Service { private static final String TAG = "SoundTriggerTestSrv"; private static final String INTENT_ACTION = "com.android.intent.action.MANAGE_SOUND_TRIGGER"; Loading @@ -57,6 +60,8 @@ public class SoundTriggerTestService extends Service { private Random mRandom; private UserActivity mUserActivity; private static int captureCount; public interface UserActivity { void addModel(UUID modelUuid, String state); void setModelState(UUID modelUuid, String state); Loading Loading @@ -131,6 +136,8 @@ public class SoundTriggerTestService extends Service { } else if (command.equals("set_capture_timeout")) { setCaptureAudioTimeout(getModelUuidFromIntent(intent), intent.getIntExtra("timeout", 5000)); } else if (command.equals("get_model_state")) { getModelState(getModelUuidFromIntent(intent)); } else { Log.e(TAG, "Unknown command '" + command + "'"); } Loading Loading @@ -432,6 +439,17 @@ public class SoundTriggerTestService extends Service { return modelInfo != null && modelInfo.captureAudioTrack != null; } public synchronized void getModelState(UUID modelUuid) { ModelInfo modelInfo = mModelInfoMap.get(modelUuid); if (modelInfo == null) { postError("Could not find model for: " + modelUuid.toString()); return; } int status = mSoundTriggerUtil.getModelState(modelUuid); postMessage("GetModelState for: " + modelInfo.name + " returns: " + status); } private void loadModelsInDataDir() { // Load all the models in the data dir. boolean loadedModel = false; Loading Loading @@ -527,18 +545,29 @@ public class SoundTriggerTestService extends Service { } } private class CaptureAudioRecorder implements Runnable { private final ModelInfo mModelInfo; // EventPayload and RecognitionEvent are equivalant. Only one will be non-null. private final SoundTriggerDetector.EventPayload mEvent; private final RecognitionEvent mRecognitionEvent; public CaptureAudioRecorder(ModelInfo modelInfo, SoundTriggerDetector.EventPayload event) { mModelInfo = modelInfo; mEvent = event; mRecognitionEvent = null; } public CaptureAudioRecorder(ModelInfo modelInfo, RecognitionEvent event) { mModelInfo = modelInfo; mEvent = null; mRecognitionEvent = event; } @Override public void run() { AudioFormat format = mEvent.getCaptureAudioFormat(); AudioFormat format = getAudioFormat(); if (format == null) { postErrorToast("No audio format in recognition event."); return; Loading Loading @@ -600,18 +629,21 @@ public class SoundTriggerTestService extends Service { } audioRecord = new AudioRecord(attributes, format, bytesRequired, mEvent.getCaptureSession()); getCaptureSession()); byte[] buffer = new byte[bytesRequired]; // Create a file so we can save the output data there for analysis later. FileOutputStream fos = null; try { fos = new FileOutputStream( new File( File file = new File( getFilesDir() + File.separator + mModelInfo.name.replace(' ', '_') + "_capture_" + format.getChannelCount() + "ch_" + format.getSampleRate() + "hz_" + encoding + ".pcm")); + format.getSampleRate() + "hz_" + encoding + "_" + (++captureCount) + ".pcm"); Log.i(TAG, "Writing audio to: " + file); fos = new FileOutputStream(file); } catch (IOException e) { Log.e(TAG, "Failed to open output for saving PCM data", e); postErrorToast("Failed to open output for saving PCM data: " Loading @@ -635,6 +667,10 @@ public class SoundTriggerTestService extends Service { bytesRequired -= bytesRead; } audioRecord.stop(); if (fos != null) { fos.flush(); fos.close(); } } catch (Exception e) { Log.e(TAG, "Error recording trigger audio", e); postErrorToast("Error recording trigger audio: " + e.getMessage()); Loading @@ -651,6 +687,26 @@ public class SoundTriggerTestService extends Service { setModelState(mModelInfo, "Recording finished"); } } private AudioFormat getAudioFormat() { if (mEvent != null) { return mEvent.getCaptureAudioFormat(); } if (mRecognitionEvent != null) { return mRecognitionEvent.captureFormat; } return null; } private int getCaptureSession() { if (mEvent != null) { return mEvent.getCaptureSession(); } if (mRecognitionEvent != null) { return mRecognitionEvent.captureSession; } return 0; } } // Implementation of SoundTriggerDetector.Callback. Loading tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java +32 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.test.soundtrigger; import android.annotation.Nullable; import android.content.Context; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.soundtrigger.SoundTriggerDetector; import android.media.soundtrigger.SoundTriggerManager; import android.os.RemoteException; Loading @@ -27,6 +29,7 @@ import android.util.Log; import com.android.internal.app.ISoundTriggerService; import java.lang.reflect.Method; import java.lang.RuntimeException; import java.util.UUID; Loading @@ -50,13 +53,31 @@ public class SoundTriggerUtil { * The sound model must contain a valid UUID. * * @param soundModel The sound model to add/update. * @return The true if the model was loaded successfully, false otherwise. */ public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) { if (soundModel == null) { throw new RuntimeException("Bad sound model"); } mSoundTriggerManager.updateModel(soundModel); return true; // TODO: call loadSoundModel in the soundtrigger manager updateModel method // instead of here. It is needed to keep soundtrigger manager internal // state consistent. return mSoundTriggerManager .loadSoundModel(getGenericSoundModel(soundModel)) == 0; } private GenericSoundModel getGenericSoundModel( SoundTriggerManager.Model soundModel) { try { Method method = SoundTriggerManager.Model.class .getDeclaredMethod("getGenericSoundModel"); method.setAccessible(true); return (GenericSoundModel) method.invoke(soundModel); } catch (ReflectiveOperationException e) { Log.e(TAG, "Failed to getGenericSoundModel: " + soundModel, e); return null; } } /** Loading Loading @@ -92,6 +113,16 @@ public class SoundTriggerUtil { return true; } /** * Get the current model state * * @param modelId The model ID to look-up the sound model for. * @return 0 if the call succeeds, or an error code if it fails. */ public int getModelState(UUID modelId) { return mSoundTriggerManager.getModelState(modelId); } public SoundTriggerDetector createSoundTriggerDetector(UUID modelId, SoundTriggerDetector.Callback callback) { return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null); Loading Loading
tests/SoundTriggerTestApp/res/layout/main.xml +8 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,14 @@ android:text="@string/play_trigger" android:onClick="onPlayTriggerButtonClicked" android:padding="20dp" /> <Button android:id="@+id/get_state_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/get_model_state" android:onClick="onGetModelStateButtonClicked" android:padding="20dp" /> </LinearLayout> <LinearLayout Loading
tests/SoundTriggerTestApp/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ <string name="start_recog">Start</string> <string name="stop_recog">Stop</string> <string name="play_trigger">Play Trigger Audio</string> <string name="get_model_state">Get State</string> <string name="capture">Capture Audio</string> <string name="stop_capture">Stop Capturing Audio</string> <string name="play_capture">Play Captured Audio</string> Loading
tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java +8 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,14 @@ public class SoundTriggerTestActivity extends Activity implements SoundTriggerTe } } public synchronized void onGetModelStateButtonClicked(View v) { if (mService == null) { Log.e(TAG, "Can't get model state: not bound to SoundTriggerTestService"); } else { mService.getModelState(mSelectedModelUuid); } } public synchronized void onCaptureAudioCheckboxClicked(View v) { // See if we have the right permissions if (!mService.hasMicrophonePermission()) { Loading
tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java +63 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioManager; Loading @@ -46,6 +48,7 @@ import java.util.Properties; import java.util.Random; import java.util.UUID; public class SoundTriggerTestService extends Service { private static final String TAG = "SoundTriggerTestSrv"; private static final String INTENT_ACTION = "com.android.intent.action.MANAGE_SOUND_TRIGGER"; Loading @@ -57,6 +60,8 @@ public class SoundTriggerTestService extends Service { private Random mRandom; private UserActivity mUserActivity; private static int captureCount; public interface UserActivity { void addModel(UUID modelUuid, String state); void setModelState(UUID modelUuid, String state); Loading Loading @@ -131,6 +136,8 @@ public class SoundTriggerTestService extends Service { } else if (command.equals("set_capture_timeout")) { setCaptureAudioTimeout(getModelUuidFromIntent(intent), intent.getIntExtra("timeout", 5000)); } else if (command.equals("get_model_state")) { getModelState(getModelUuidFromIntent(intent)); } else { Log.e(TAG, "Unknown command '" + command + "'"); } Loading Loading @@ -432,6 +439,17 @@ public class SoundTriggerTestService extends Service { return modelInfo != null && modelInfo.captureAudioTrack != null; } public synchronized void getModelState(UUID modelUuid) { ModelInfo modelInfo = mModelInfoMap.get(modelUuid); if (modelInfo == null) { postError("Could not find model for: " + modelUuid.toString()); return; } int status = mSoundTriggerUtil.getModelState(modelUuid); postMessage("GetModelState for: " + modelInfo.name + " returns: " + status); } private void loadModelsInDataDir() { // Load all the models in the data dir. boolean loadedModel = false; Loading Loading @@ -527,18 +545,29 @@ public class SoundTriggerTestService extends Service { } } private class CaptureAudioRecorder implements Runnable { private final ModelInfo mModelInfo; // EventPayload and RecognitionEvent are equivalant. Only one will be non-null. private final SoundTriggerDetector.EventPayload mEvent; private final RecognitionEvent mRecognitionEvent; public CaptureAudioRecorder(ModelInfo modelInfo, SoundTriggerDetector.EventPayload event) { mModelInfo = modelInfo; mEvent = event; mRecognitionEvent = null; } public CaptureAudioRecorder(ModelInfo modelInfo, RecognitionEvent event) { mModelInfo = modelInfo; mEvent = null; mRecognitionEvent = event; } @Override public void run() { AudioFormat format = mEvent.getCaptureAudioFormat(); AudioFormat format = getAudioFormat(); if (format == null) { postErrorToast("No audio format in recognition event."); return; Loading Loading @@ -600,18 +629,21 @@ public class SoundTriggerTestService extends Service { } audioRecord = new AudioRecord(attributes, format, bytesRequired, mEvent.getCaptureSession()); getCaptureSession()); byte[] buffer = new byte[bytesRequired]; // Create a file so we can save the output data there for analysis later. FileOutputStream fos = null; try { fos = new FileOutputStream( new File( File file = new File( getFilesDir() + File.separator + mModelInfo.name.replace(' ', '_') + "_capture_" + format.getChannelCount() + "ch_" + format.getSampleRate() + "hz_" + encoding + ".pcm")); + format.getSampleRate() + "hz_" + encoding + "_" + (++captureCount) + ".pcm"); Log.i(TAG, "Writing audio to: " + file); fos = new FileOutputStream(file); } catch (IOException e) { Log.e(TAG, "Failed to open output for saving PCM data", e); postErrorToast("Failed to open output for saving PCM data: " Loading @@ -635,6 +667,10 @@ public class SoundTriggerTestService extends Service { bytesRequired -= bytesRead; } audioRecord.stop(); if (fos != null) { fos.flush(); fos.close(); } } catch (Exception e) { Log.e(TAG, "Error recording trigger audio", e); postErrorToast("Error recording trigger audio: " + e.getMessage()); Loading @@ -651,6 +687,26 @@ public class SoundTriggerTestService extends Service { setModelState(mModelInfo, "Recording finished"); } } private AudioFormat getAudioFormat() { if (mEvent != null) { return mEvent.getCaptureAudioFormat(); } if (mRecognitionEvent != null) { return mRecognitionEvent.captureFormat; } return null; } private int getCaptureSession() { if (mEvent != null) { return mEvent.getCaptureSession(); } if (mRecognitionEvent != null) { return mRecognitionEvent.captureSession; } return 0; } } // Implementation of SoundTriggerDetector.Callback. Loading
tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java +32 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.test.soundtrigger; import android.annotation.Nullable; import android.content.Context; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.soundtrigger.SoundTriggerDetector; import android.media.soundtrigger.SoundTriggerManager; import android.os.RemoteException; Loading @@ -27,6 +29,7 @@ import android.util.Log; import com.android.internal.app.ISoundTriggerService; import java.lang.reflect.Method; import java.lang.RuntimeException; import java.util.UUID; Loading @@ -50,13 +53,31 @@ public class SoundTriggerUtil { * The sound model must contain a valid UUID. * * @param soundModel The sound model to add/update. * @return The true if the model was loaded successfully, false otherwise. */ public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) { if (soundModel == null) { throw new RuntimeException("Bad sound model"); } mSoundTriggerManager.updateModel(soundModel); return true; // TODO: call loadSoundModel in the soundtrigger manager updateModel method // instead of here. It is needed to keep soundtrigger manager internal // state consistent. return mSoundTriggerManager .loadSoundModel(getGenericSoundModel(soundModel)) == 0; } private GenericSoundModel getGenericSoundModel( SoundTriggerManager.Model soundModel) { try { Method method = SoundTriggerManager.Model.class .getDeclaredMethod("getGenericSoundModel"); method.setAccessible(true); return (GenericSoundModel) method.invoke(soundModel); } catch (ReflectiveOperationException e) { Log.e(TAG, "Failed to getGenericSoundModel: " + soundModel, e); return null; } } /** Loading Loading @@ -92,6 +113,16 @@ public class SoundTriggerUtil { return true; } /** * Get the current model state * * @param modelId The model ID to look-up the sound model for. * @return 0 if the call succeeds, or an error code if it fails. */ public int getModelState(UUID modelId) { return mSoundTriggerManager.getModelState(modelId); } public SoundTriggerDetector createSoundTriggerDetector(UUID modelId, SoundTriggerDetector.Callback callback) { return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null); Loading