diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 6562f2282f..08e28ea597 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -529,7 +529,7 @@ android.hardware.soundtrigger - 2.3 + 2.3-4 ISoundTriggerHw default diff --git a/soundtrigger/2.4/Android.bp b/soundtrigger/2.4/Android.bp new file mode 100644 index 0000000000..38c32dff73 --- /dev/null +++ b/soundtrigger/2.4/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.soundtrigger@2.4", + root: "android.hardware", + srcs: [ + "ISoundTriggerHw.hal", + "ISoundTriggerHwCallback.hal", + "ISoundTriggerHwGlobalCallback.hal", + ], + interfaces: [ + "android.hardware.audio.common@2.0", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: true, +} diff --git a/soundtrigger/2.4/ISoundTriggerHw.hal b/soundtrigger/2.4/ISoundTriggerHw.hal new file mode 100644 index 0000000000..fd393036d8 --- /dev/null +++ b/soundtrigger/2.4/ISoundTriggerHw.hal @@ -0,0 +1,190 @@ +/* + * Copyright 2021 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.hardware.soundtrigger@2.4; + +import @2.0::SoundModelHandle; +import @2.1::ISoundTriggerHw.SoundModel; +import @2.1::ISoundTriggerHw.PhraseSoundModel; +import @2.3::ISoundTriggerHw; +import @2.3::RecognitionConfig; +import ISoundTriggerHwCallback; +import ISoundTriggerHwGlobalCallback; + +/** + * SoundTrigger HAL interface. Used for hardware recognition of hotwords + * and other sounds. + * + * Important notes about the threading model: + * ========================================== + * Both this interface and the corresponding callback interface use a synchronized calling + * convention. This model comes with some advantages, but also with some risks of deadlocks if the + * implementation does not handle this correctly. Please consider the following: + * - After stopRecognition() returns no more recognition events for that model may be sent. This + * implies that any queues holding such events must be flushed before the call returns and that + * may imply that callback from the HAL to the client are done while stopRecognition() is blocked. + * This is OK, and supported by the framework. + * - Similarly, the same relationship applies between unloadModel() and subsequent callbacks to + * modelUnloaded(). + * - Other than these two cases, calls into the HAL *MAY NOT* block on callbacks from the HAL, or + * else deadlock conditions may result, which may be handled by rebooting of the HAL process and + * cause service outages. + * + * Similarly, it is expected that a single call to startRecognition() generates at most one event + * (the model automatically becomes stopped when the event occurs, until explicitly started again) + * and that after a modelUnloaded() event no more events would be sent regarding the model. + * Note that a getModelState() call may generate a recognition event, but this event DOES NOT modify + * the model state - the model remains started. + * + * The HAL is expected to correctly handle a stopRecognition() call even after it sent an event + * indicating that recognition is stopped and an unloadModel() call even after it sent an event + * indicating that it has been unloaded. This is required in order to prevent race conditions + * between these calls. This also implies that model handles should generally not be reused until + * explicitly unloaded. To avoid the rare possibility of running out of handles, the framework will + * call unloadModel() on models that have been preemptively unloaded by the HAL. + * + * Due to the asynchronous nature of recognition events and preemptive model unloading, the HAL must + * correctly handle requests that would have been valid before an event has been delivered, but + * became moot as result of the event. Namely: + * - stopRecognition() may be called on a model that has already delivered an event and became + * inactive as a result. The HAL must return a successful return code in this case. + * - Furthermore, if a model is preemptively unloaded after it triggers (typically, this would + * happen when it is first aborted and immediately preemptively unloaded), stopRecognition() may + * be called on it. The HAL must return a successful return code in this case. + * - startRecognition() may be called on a model that has been preemptively unloaded. In this case, + * the HAL must return -EBUSY to indicate that the operation is temporarily unsuccessful. + * - unloadSoundModel() may be called on a model that has been preemptively unloaded. The HAL must + * return a successful return code in this case. + * + * Important notes about resource constraints and concurrency + * ========================================================= + * Up until this version, the framework would enforce concurrency constraints expressed by the + * Properties presented by the soundtrigger instance. These include constraints on the maximum + * amount of models that can be loaded at the same time and on running recognition while capturing + * from the microphone. + * This version changes the approach for how these constraints are modeled, both offering the HAL + * implementation more flexibility and simplifying the framework's job in enforcing these + * limitations. Note that there is no change for how the framework behaves with earlier versions, + * everything described below only applies to this version and onward. + * The way this is achieved is as following: + * - The framework will no longer enforce constraints on concurrent loading of models, as expressed + * in the Properties.maxSoundModels field (this property is merely a hint at this point and may be + * deprecated in the future. + * - The framework will no longer enforce constraints on concurrency of audio recording and + * soundtrigger operation, as expressed in the Properties.concurrentCapture field (this property + * is merely a hint at this point and may be deprecated in the future). + * - The framework will no longer enforce constraints on concurrent loading of models, as expressed + * in the Properties (these properties are merely hints at this point and may be deprecated in the + * future. + * - The HAL implementation is free to reject starting of any model at any time by having the + * respective start*() method return -EBUSY. + * - The HAL implementation is free to reject loading of any model at any time by having the + * respective load*() method return -EBUSY. + * - The HAL implementation is free to preemptively stop a previously started model at its own + * discretion (for example, if a higher priority use-case which cannot coexist with detection + * has been requested). The HAL must notify the framework of the preemption by sending a + * recognition event with an `ABORT` status. The implementation must NOT attempt to restart the + * recognition automatically when conditions change. + * - The HAL implementation is free to preemptively unload a previously loaded model at its own + * discretion (for example, if a higher-priority model is being loaded and the two cannot + * coexist). When doing so, it must first abort the detection if active (as per above) and then + * notify the framework of the unload using the newly added modelUnloaded callback. + * - When conditions change, such that a model that couldn't previously load or start or that had + * previously been preemptively stopped or unloaded, the HAL must notify the framework via the + * newly added tryAgain() callback. This callback is not a guarantee that any operation would now + * succeed, but merely a hint that retrying something that had previously failed, now MAY succeed. + * Until this callback arrives, the framework may assume that any operation that had previously + * failed or aborted would still fail if retried, so the implementation should not forget to + * deliver it. There are no guarantees regarding how the framework may respond to this event and + * the order in which it may choose to reload/restart its models. Typically, as result of this + * event the framework will make a single attempt per model to bring this model to its desired + * state (loaded, started). + */ +interface ISoundTriggerHw extends @2.3::ISoundTriggerHw { + /** + * This will get called at most once per every attachment to the service. + * + * All events not tied to a specific model should go through this callback. + */ + registerGlobalCallback(ISoundTriggerHwGlobalCallback callback); + + /** + * Load a sound model. Once loaded, recognition of this model can be + * started and stopped. + * The implementation returns a unique handle used by other functions + * (unloadSoundModel(), startRecognition*(), etc... + * + * Must have the exact same semantics as loadSoundModel from ISoundTriggerHw@2.3 except that the + * return values have changed and that there is no cookie provided (the implementation may pass + * any value to the callback, as it is ignored). + * + * @param soundModel A SoundModel structure describing the sound model + * to load. + * @param callback The callback interface on which the soundModelCallback*() + * method must be called upon completion and modelUnloaded() upon preempted unload. + * @return retval Operation completion status: 0 in case of success, + * -EBUSY in case the operation is temporarily unavailable (but possible in general). + * @return modelHandle A unique handle assigned by the HAL for use by the + * framework when controlling activity for this sound model. + */ + loadSoundModel_2_4(SoundModel soundModel, ISoundTriggerHwCallback callback) + generates (int32_t retval, SoundModelHandle modelHandle); + + /** + * Load a key phrase sound model. Once loaded, recognition of this model can + * be started and stopped. Only one active recognition per model at a time. + * The SoundTrigger service must handle concurrent recognition requests by + * different users/applications on the same model. + * The implementation returns a unique handle used by other functions + * (unloadSoundModel(), startRecognition*(), etc... + * + * Must have the exact same semantics as loadPhraseSoundModel from ISoundTriggerHw@2.3 except + * that the return values have changed and that there is no cookie provided (the implementation + * may pass any value to the callback, as it is ignored). + * + * @param soundModel A PhraseSoundModel structure describing the sound model + * to load. + * @param callback The callback interface on which the soundModelCallback*() + * method must be called upon completion and modelUnloaded() upon preempted unload. + * @return retval Operation completion status: 0 in case of success, + * -EBUSY in case the operation is temporarily unavailable (but possible in general). + * @return modelHandle A unique handle assigned by the HAL for use by the + * framework when controlling activity for this sound model. + */ + loadPhraseSoundModel_2_4(PhraseSoundModel soundModel, ISoundTriggerHwCallback callback) + generates (int32_t retval, SoundModelHandle modelHandle); + + /** + * Start recognition on a given model. Only one recognition active + * at a time per model. Once recognition succeeds or fails, the callback + * associated with the model handle is called. + * + * Must have the exact same semantics as startRecognition from ISoundTriggerHw@2.3 except that + * there are different expectations of the return value and that there is no cookie provided + * (the implementation may pass any value to the callback, as it is ignored). + * + * @param modelHandle the handle of the sound model to use for recognition + * @param config A RecognitionConfig structure containing attributes of the + * recognition to perform + * @param callback The callback interface on which the recognitionCallback() + * method must be called upon recognition. + * @return retval Operation completion status: 0 in case of success, + * -EBUSY in case the operation is temporarily unavailable (but possible in general), or in + * case model has been preemtively unloaded. + */ + startRecognition_2_4(SoundModelHandle modelHandle, RecognitionConfig config) + generates (int32_t retval); +}; diff --git a/soundtrigger/2.4/ISoundTriggerHwCallback.hal b/soundtrigger/2.4/ISoundTriggerHwCallback.hal new file mode 100644 index 0000000000..594deb09d3 --- /dev/null +++ b/soundtrigger/2.4/ISoundTriggerHwCallback.hal @@ -0,0 +1,34 @@ +/* + * Copyright 2021 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.hardware.soundtrigger@2.4; + +import @2.0::SoundModelHandle; +import @2.1::ISoundTriggerHwCallback; + +/** + * SoundTrigger HAL per-model Callback interface. + */ +interface ISoundTriggerHwCallback extends @2.1::ISoundTriggerHwCallback { + /** + * Callback method called by the HAL when a model has been unloaded at the HAL implementation's + * discretion. Only a stopped model may be unloaded. + * This event is NOT sent as part of an unload sequence initiated by the client. + * + * @param model The model handle. + */ + modelUnloaded(SoundModelHandle model); +}; diff --git a/soundtrigger/2.4/ISoundTriggerHwGlobalCallback.hal b/soundtrigger/2.4/ISoundTriggerHwGlobalCallback.hal new file mode 100644 index 0000000000..2f1a977a12 --- /dev/null +++ b/soundtrigger/2.4/ISoundTriggerHwGlobalCallback.hal @@ -0,0 +1,32 @@ +/* + * Copyright 2021 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.hardware.soundtrigger@2.4; + +/** + * SoundTrigger HAL callback interface for events not associated with a particular model. + */ +interface ISoundTriggerHwGlobalCallback { + /** + * Callback method called by the HAL whenever internal conditions have been made available, such + * that a call that would previously have failed with an -EBUSY status may now succeed. + * There is no guarantee that any call would succeed following this event. It is merely a hint + * to the client that it may retry. + * Conversely, any call that have failed previously with -EBUSY is guaranteed to fail again if + * retried, until this callback is delivered. + */ + onResourcesAvailable(); +}; diff --git a/soundtrigger/2.4/vts/functional/Android.bp b/soundtrigger/2.4/vts/functional/Android.bp new file mode 100644 index 0000000000..0e69bf4844 --- /dev/null +++ b/soundtrigger/2.4/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// Copyright (C) 2021 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. +// + +cc_test { + name: "VtsHalSoundtriggerV2_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalSoundtriggerV2_4TargetTest.cpp"], + static_libs: [ + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + "android.hardware.soundtrigger@2.4", + ], + test_suites: [ + "general-tests", + "vts", + ], +} diff --git a/soundtrigger/2.4/vts/functional/VtsHalSoundtriggerV2_4TargetTest.cpp b/soundtrigger/2.4/vts/functional/VtsHalSoundtriggerV2_4TargetTest.cpp new file mode 100644 index 0000000000..13d70058e1 --- /dev/null +++ b/soundtrigger/2.4/vts/functional/VtsHalSoundtriggerV2_4TargetTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 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. + */ + +#define LOG_TAG "SoundTriggerHidlHalTest" + +#include +#include +#include +#include +#include +#include +#include + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Status; +using ::android::hardware::soundtrigger::V2_4::ISoundTriggerHw; +using ::android::hardware::soundtrigger::V2_4::ISoundTriggerHwGlobalCallback; + +/** + * Test class holding the instance of the SoundTriggerHW service to test. + * The passed parameter is the registered name of the implementing service + * supplied by INSTANTIATE_TEST_SUITE_P() call. + */ +class SoundTriggerHidlTest : public testing::TestWithParam { +public: + void SetUp() override { + mSoundtrigger = ISoundTriggerHw::getService(GetParam()); + + ASSERT_NE(mSoundtrigger, nullptr); + LOG(INFO) << "Test is remote " << mSoundtrigger->isRemote(); + } + +protected: + sp mSoundtrigger; +}; + +/** + * Empty test is in place to ensure service is initialized. + * Due to the nature of SoundTrigger HAL providing an interface for + * proprietary or vendor specific implementations, limited testing on + * individual APIs is possible. + */ +TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {} + +class GlobalCallback : public ISoundTriggerHwGlobalCallback { + Return onResourcesAvailable() override { + return Status::ok(); + } +}; + +/** + * Test ISoundTriggerHw::registerGlobalCallback method + * + * Verifies that: + * - the implementation implements the method + * - the method returns no error + */ +TEST_P(SoundTriggerHidlTest, RegisterGlobalCallback) { + Return hidlReturn; + sp callback = new GlobalCallback(); + hidlReturn = mSoundtrigger->registerGlobalCallback(callback); + EXPECT_TRUE(hidlReturn.isOk()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundTriggerHidlTest); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, SoundTriggerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), + android::hardware::PrintInstanceNameToString);