Add additional conversion to ST for testing

Testing ST requires converting AIDL types back to API to pass
to the test client.

Add equals to RecognitionConfig.

Bug: 271330425
Test: atest ConversionUtilTest
Change-Id: I98336ac664a1a264835110a34d20b73f430d5de8
This commit is contained in:
Atneya Nair
2023-03-01 14:57:55 -08:00
parent 123492f470
commit 21c80c8ec7
3 changed files with 135 additions and 1 deletions

View File

@@ -34,10 +34,12 @@ import android.media.soundtrigger.RecognitionMode;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.os.SharedMemory;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale;
import java.util.UUID;
/** @hide */
@@ -140,6 +142,14 @@ public class ConversionUtil {
return aidlPhrase;
}
public static SoundTrigger.Keyphrase aidl2apiPhrase(Phrase aidlPhrase) {
return new SoundTrigger.Keyphrase(aidlPhrase.id,
aidl2apiRecognitionModes(aidlPhrase.recognitionModes),
new Locale.Builder().setLanguageTag(aidlPhrase.locale).build(),
aidlPhrase.text,
Arrays.copyOf(aidlPhrase.users, aidlPhrase.users.length));
}
public static RecognitionConfig api2aidlRecognitionConfig(
SoundTrigger.RecognitionConfig apiConfig) {
RecognitionConfig aidlConfig = new RecognitionConfig();
@@ -156,6 +166,21 @@ public class ConversionUtil {
return aidlConfig;
}
public static SoundTrigger.RecognitionConfig aidl2apiRecognitionConfig(
RecognitionConfig aidlConfig) {
var keyphrases =
new SoundTrigger.KeyphraseRecognitionExtra[aidlConfig.phraseRecognitionExtras.length];
int i = 0;
for (var extras : aidlConfig.phraseRecognitionExtras) {
keyphrases[i++] = aidl2apiPhraseRecognitionExtra(extras);
}
return new SoundTrigger.RecognitionConfig(aidlConfig.captureRequested,
false /** allowMultipleTriggers **/,
keyphrases,
Arrays.copyOf(aidlConfig.data, aidlConfig.data.length),
aidl2apiAudioCapabilities(aidlConfig.audioCapabilities));
}
public static PhraseRecognitionExtra api2aidlPhraseRecognitionExtra(
SoundTrigger.KeyphraseRecognitionExtra apiExtra) {
PhraseRecognitionExtra aidlExtra = new PhraseRecognitionExtra();
@@ -281,7 +306,7 @@ public class ConversionUtil {
return result;
}
private static @Nullable ParcelFileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
public static @Nullable ParcelFileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
if (data.length == 0) {
return null;
}
@@ -298,4 +323,19 @@ public class ConversionUtil {
throw new RuntimeException(e);
}
}
public static byte[] sharedMemoryToByteArray(@Nullable ParcelFileDescriptor pfd, int size) {
if (pfd == null || size == 0) {
return new byte[0];
}
try (SharedMemory mem = SharedMemory.fromFileDescriptor(pfd)) {
ByteBuffer buffer = mem.mapReadOnly();
byte[] data = new byte[(size > mem.getSize()) ? mem.getSize() : size];
buffer.get(data);
mem.unmap(buffer);
return data;
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1493,6 +1493,45 @@ public class SoundTrigger {
+ Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data)
+ ", audioCapabilities=" + Integer.toHexString(audioCapabilities) + "]";
}
@Override
public final boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof RecognitionConfig))
return false;
RecognitionConfig other = (RecognitionConfig) obj;
if (captureRequested != other.captureRequested) {
return false;
}
if (allowMultipleTriggers != other.allowMultipleTriggers) {
return false;
}
if (!Arrays.equals(keyphrases, other.keyphrases)) {
return false;
}
if (!Arrays.equals(data, other.data)) {
return false;
}
if (audioCapabilities != other.audioCapabilities) {
return false;
}
return true;
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (captureRequested ? 1 : 0);
result = prime * result + (allowMultipleTriggers ? 1 : 0);
result = prime * result + Arrays.hashCode(keyphrases);
result = prime * result + Arrays.hashCode(data);
result = prime * result + audioCapabilities;
return result;
}
}
/**

View File

@@ -17,17 +17,32 @@
package com.android.server.soundtrigger_middleware;
import static android.hardware.soundtrigger.ConversionUtil.aidl2apiAudioFormatWithDefault;
import static android.hardware.soundtrigger.ConversionUtil.aidl2apiPhrase;
import static android.hardware.soundtrigger.ConversionUtil.aidl2apiRecognitionConfig;
import static android.hardware.soundtrigger.ConversionUtil.api2aidlPhrase;
import static android.hardware.soundtrigger.ConversionUtil.api2aidlRecognitionConfig;
import static android.hardware.soundtrigger.ConversionUtil.byteArrayToSharedMemory;
import static android.hardware.soundtrigger.ConversionUtil.sharedMemoryToByteArray;
import static android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
import static android.hardware.soundtrigger.SoundTrigger.RECOGNITION_MODE_GENERIC;
import static android.hardware.soundtrigger.SoundTrigger.RECOGNITION_MODE_USER_AUTHENTICATION;
import static android.hardware.soundtrigger.SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
import static android.hardware.soundtrigger.SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.hardware.audio.common.V2_0.Uuid;
import android.hardware.soundtrigger.SoundTrigger;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
public class ConversionUtilTest {
private static final String TAG = "ConversionUtilTest";
@@ -57,4 +72,44 @@ public class ConversionUtilTest {
);
assertNotNull(format);
}
@Test
public void testRecognitionConfigRoundTrip() {
final int flags = SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION
| SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
final var data = new byte[] {0x11, 0x22};
final var keyphrases = new SoundTrigger.KeyphraseRecognitionExtra[2];
keyphrases[0] = new SoundTrigger.KeyphraseRecognitionExtra(99,
RECOGNITION_MODE_VOICE_TRIGGER | RECOGNITION_MODE_USER_IDENTIFICATION, 13,
new ConfidenceLevel[] {new ConfidenceLevel(9999, 50),
new ConfidenceLevel(5000, 80)});
keyphrases[1] = new SoundTrigger.KeyphraseRecognitionExtra(101,
RECOGNITION_MODE_GENERIC, 8, new ConfidenceLevel[] {
new ConfidenceLevel(7777, 30),
new ConfidenceLevel(2222, 60)});
var apiconfig = new SoundTrigger.RecognitionConfig(true, false /** must be false **/,
keyphrases, data, flags);
assertEquals(apiconfig, aidl2apiRecognitionConfig(api2aidlRecognitionConfig(apiconfig)));
}
@Test
public void testByteArraySharedMemRoundTrip() {
final var data = new byte[] { 0x11, 0x22, 0x33, 0x44,
(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef };
assertArrayEquals(data, sharedMemoryToByteArray(byteArrayToSharedMemory(data, "name"),
10000000));
}
@Test
public void testPhraseRoundTrip() {
final var users = new int[] {10001, 10002};
final var apiphrase = new SoundTrigger.Keyphrase(17 /** id **/,
RECOGNITION_MODE_VOICE_TRIGGER | RECOGNITION_MODE_USER_AUTHENTICATION,
Locale.forLanguageTag("no_NO"),
"Hello Android", /** keyphrase **/
users);
assertEquals(apiphrase, aidl2apiPhrase(api2aidlPhrase(apiphrase)));
}
}