Merge "Add PER_DISPLAY_MAX_BRIGHTNESS VHAL property." into main
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index a3f0de9..56b7926 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -51,9 +51,7 @@
DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
- IDLE -> ERROR [label="←IStreamCallback.onError"];
- DRAINING -> ERROR [label="←IStreamCallback.onError"];
- TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> ERROR [label="←IStreamCallback.onError"];
ANY_STATE -> CLOSED [label="→IStream*.close"];
CLOSED -> F;
}
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 7306b47..77629a9 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -55,5 +55,10 @@
{
"name": "VehicleHalProtoMessageConverterTest"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "VehicleHalProtoMessageConverterTest"
+ }
]
}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index 8f1c7d1..c4f93c4 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -45,3 +45,24 @@
sub_dir: "automotive/vhalconfig/",
vendor: true,
}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalDefaultProperties_JSON",
+ filename_from_src: true,
+ src: "DefaultProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalTestProperties_JSON",
+ filename_from_src: true,
+ src: "TestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+ filename_from_src: true,
+ src: "VendorClusterTestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 664c877..9f002dd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -56,6 +56,8 @@
defaults: [
"VehicleHalDefaults",
],
+ // Need root to use vendor lib: libgrpc++.
+ require_root: true,
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index fd1d1ca..7a8da59 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,7 +22,7 @@
"aprotoc",
"protoc-gen-grpc-cpp-plugin",
],
- cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_opt=generate_mock_code=true --grpc_out=$(genDir) --cpp_out=$(genDir)",
srcs: [
"proto/VehicleServer.proto",
":libprotobuf-internal-protos",
@@ -31,6 +31,7 @@
out: [
"VehicleServer.pb.h",
"VehicleServer.grpc.pb.h",
+ "VehicleServer_mock.grpc.pb.h",
],
visibility: ["//visibility:private"],
}
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 0742283..f44573a 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -39,6 +39,13 @@
mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
mValuePollingThread([this] { ValuePollingLoop(); }) {}
+// Only used for unit testing.
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
+ : mServiceAddr(""),
+ mGrpcChannel(nullptr),
+ mGrpcStub(std::move(stub)),
+ mValuePollingThread([] {}) {}
+
GRPCVehicleHardware::~GRPCVehicleHardware() {
{
std::lock_guard lck(mShutdownMutex);
@@ -181,6 +188,43 @@
return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
}
+aidlvhal::StatusCode GRPCVehicleHardware::subscribe(aidlvhal::SubscribeOptions options) {
+ proto::SubscribeRequest request;
+ ::grpc::ClientContext context;
+ proto::VehicleHalCallStatus protoStatus;
+ proto_msg_converter::aidlToProto(options, request.mutable_options());
+ auto grpc_status = mGrpcStub->Subscribe(&context, request, &protoStatus);
+ if (!grpc_status.ok()) {
+ if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+ // This is a legacy sever. It should handle updateSampleRate.
+ LOG(INFO) << __func__ << ": GRPC Subscribe is not supported by the server";
+ return aidlvhal::StatusCode::OK;
+ }
+ LOG(ERROR) << __func__ << ": GRPC Subscribe Failed: " << grpc_status.error_message();
+ return aidlvhal::StatusCode::INTERNAL_ERROR;
+ }
+ return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+ proto::UnsubscribeRequest request;
+ ::grpc::ClientContext context;
+ proto::VehicleHalCallStatus protoStatus;
+ request.set_prop_id(propId);
+ request.set_area_id(areaId);
+ auto grpc_status = mGrpcStub->Unsubscribe(&context, request, &protoStatus);
+ if (!grpc_status.ok()) {
+ if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+ // This is a legacy sever. Ignore unsubscribe request.
+ LOG(INFO) << __func__ << ": GRPC Unsubscribe is not supported by the server";
+ return aidlvhal::StatusCode::OK;
+ }
+ LOG(ERROR) << __func__ << ": GRPC Unsubscribe Failed: " << grpc_status.error_message();
+ return aidlvhal::StatusCode::INTERNAL_ERROR;
+ }
+ return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
float sampleRate) {
::grpc::ClientContext context;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index ddd620e..9750f62 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -43,6 +43,9 @@
public:
explicit GRPCVehicleHardware(std::string service_addr);
+ // Only used for unit testing.
+ explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
+
~GRPCVehicleHardware();
// Get all the property configs.
@@ -80,6 +83,10 @@
aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId,
float sampleRate) override;
+ aidlvhal::StatusCode subscribe(aidlvhal::SubscribeOptions options) override;
+
+ aidlvhal::StatusCode unsubscribe(int32_t propId, int32_t areaId) override;
+
bool waitForConnected(std::chrono::milliseconds waitTime);
protected:
@@ -91,7 +98,7 @@
std::string mServiceAddr;
std::shared_ptr<::grpc::Channel> mGrpcChannel;
- std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
+ std::unique_ptr<proto::VehicleServer::StubInterface> mGrpcStub;
std::thread mValuePollingThread;
std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index af3dd59..a6abfa3 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -164,6 +164,27 @@
return ::grpc::Status::OK;
}
+::grpc::Status GrpcVehicleProxyServer::Subscribe(::grpc::ServerContext* context,
+ const proto::SubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) {
+ const auto& protoSubscribeOptions = request->options();
+ aidlvhal::SubscribeOptions aidlSubscribeOptions = {};
+ proto_msg_converter::protoToAidl(protoSubscribeOptions, &aidlSubscribeOptions);
+ const auto status_code = mHardware->subscribe(aidlSubscribeOptions);
+ status->set_status_code(static_cast<proto::StatusCode>(status_code));
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleProxyServer::Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) {
+ int32_t propId = request->prop_id();
+ int32_t areaId = request->area_id();
+ const auto status_code = mHardware->unsubscribe(propId, areaId);
+ status->set_status_code(static_cast<proto::StatusCode>(status_code));
+ return ::grpc::Status::OK;
+}
+
::grpc::Status GrpcVehicleProxyServer::CheckHealth(::grpc::ServerContext* context,
const ::google::protobuf::Empty*,
proto::VehicleHalCallStatus* status) {
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index 3596354..dd9e2aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -57,6 +57,13 @@
const proto::UpdateSampleRateRequest* request,
proto::VehicleHalCallStatus* status) override;
+ ::grpc::Status Subscribe(::grpc::ServerContext* context, const proto::SubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) override;
+
+ ::grpc::Status Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) override;
+
::grpc::Status CheckHealth(::grpc::ServerContext* context, const ::google::protobuf::Empty*,
proto::VehicleHalCallStatus* status) override;
diff --git a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
index 22b11d8..732957f 100644
--- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
+++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
@@ -20,7 +20,9 @@
import "android/hardware/automotive/vehicle/DumpOptions.proto";
import "android/hardware/automotive/vehicle/DumpResult.proto";
+import "android/hardware/automotive/vehicle/SubscribeRequest.proto";
import "android/hardware/automotive/vehicle/StatusCode.proto";
+import "android/hardware/automotive/vehicle/UnsubscribeRequest.proto";
import "android/hardware/automotive/vehicle/VehiclePropConfig.proto";
import "android/hardware/automotive/vehicle/VehiclePropValue.proto";
import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto";
@@ -40,4 +42,8 @@
rpc Dump(DumpOptions) returns (DumpResult) {}
rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {}
+
+ rpc Subscribe(SubscribeRequest) returns (VehicleHalCallStatus) {}
+
+ rpc Unsubscribe(UnsubscribeRequest) returns (VehicleHalCallStatus) {}
}
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index f578021..3bd7e0e 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -15,6 +15,7 @@
#include "GRPCVehicleHardware.h"
#include "VehicleServer.grpc.pb.h"
#include "VehicleServer.pb.h"
+#include "VehicleServer_mock.grpc.pb.h"
#include <gmock/gmock.h>
#include <grpc++/grpc++.h>
@@ -26,6 +27,17 @@
namespace android::hardware::automotive::vehicle::virtualization {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+
+using proto::MockVehicleServerStub;
+
const std::string kFakeServerAddr = "0.0.0.0:54321";
class FakeVehicleServer : public proto::VehicleServer::Service {
@@ -91,4 +103,131 @@
}
}
+class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+ protected:
+ NiceMock<MockVehicleServerStub>* mGrpcStub;
+ std::unique_ptr<GRPCVehicleHardware> mHardware;
+
+ void SetUp() override {
+ auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+ ;
+ mGrpcStub = stub.get();
+ mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+ }
+
+ void TearDown() override { mHardware.reset(); }
+};
+
+MATCHER_P(RepeatedInt32Eq, expected_values, "") {
+ return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::OK);
+ proto::SubscribeRequest actualRequest;
+
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+ Return(::grpc::Status::OK)));
+
+ aidlvhal::SubscribeOptions options = {.propId = 1,
+ .areaIds = {1, 2, 3, 4},
+ .sampleRate = 1.234,
+ .resolution = 0.01,
+ .enableVariableUpdateRate = true};
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+ const auto& protoOptions = actualRequest.options();
+ EXPECT_EQ(protoOptions.prop_id(), 1);
+ EXPECT_THAT(protoOptions.area_ids(), RepeatedInt32Eq(std::vector<int32_t>({1, 2, 3, 4})));
+ EXPECT_FLOAT_EQ(protoOptions.sample_rate(), 1.234);
+ EXPECT_FLOAT_EQ(protoOptions.resolution(), 0.01);
+ EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
+ Return(::grpc::Status::OK)));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::OK);
+ proto::UnsubscribeRequest actualRequest;
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+ Return(::grpc::Status::OK)));
+
+ int32_t propId = 1;
+ int32_t areaId = 2;
+ auto status = mHardware->unsubscribe(propId, areaId);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+ EXPECT_EQ(actualRequest.prop_id(), propId);
+ EXPECT_EQ(actualRequest.area_id(), areaId);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
+ Return(::grpc::Status::OK)));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
index 49e6fc9..ca5c2d5 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
@@ -30,6 +30,13 @@
namespace android::hardware::automotive::vehicle::virtualization {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
const std::string kFakeServerAddr = "0.0.0.0:54321";
class VehicleHardwareForTest : public IVehicleHardware {
@@ -39,38 +46,30 @@
mOnProp = std::move(callback);
}
- void onPropertyEvent(
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> values) {
+ void onPropertyEvent(std::vector<aidlvhal::VehiclePropValue> values) {
if (mOnProp) {
(*mOnProp)(std::move(values));
}
}
// Functions that we do not care.
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
- getAllPropertyConfigs() const override {
- return {};
- }
+ std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override { return {}; }
- aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+ aidlvhal::StatusCode setValues(
std::shared_ptr<const SetValuesCallback> callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
- requests) override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+ const std::vector<aidlvhal::SetValueRequest>& requests) override {
+ return aidlvhal::StatusCode::OK;
}
- aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+ aidlvhal::StatusCode getValues(
std::shared_ptr<const GetValuesCallback> callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
- requests) const override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+ const std::vector<aidlvhal::GetValueRequest>& requests) const override {
+ return aidlvhal::StatusCode::OK;
}
DumpResult dump(const std::vector<std::string>& options) override { return {}; }
- aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
- }
+ aidlvhal::StatusCode checkHealth() override { return aidlvhal::StatusCode::OK; }
void registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) override {}
@@ -79,6 +78,35 @@
std::unique_ptr<const PropertyChangeCallback> mOnProp;
};
+class MockVehicleHardware : public IVehicleHardware {
+ public:
+ // Mock methods from IVehicleHardware
+ MOCK_METHOD(std::vector<aidlvhal::VehiclePropConfig>, getAllPropertyConfigs, (),
+ (const, override));
+
+ MOCK_METHOD((aidlvhal::StatusCode), setValues,
+ (std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<aidlvhal::SetValueRequest>& requests),
+ (override));
+
+ MOCK_METHOD((aidlvhal::StatusCode), getValues,
+ (std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<aidlvhal::GetValueRequest>& requests),
+ (const, override));
+
+ MOCK_METHOD(DumpResult, dump, (const std::vector<std::string>& options), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, checkHealth, (), (override));
+ MOCK_METHOD(void, registerOnPropertyChangeEvent,
+ (std::unique_ptr<const PropertyChangeCallback> callback), (override));
+ MOCK_METHOD(void, registerOnPropertySetErrorEvent,
+ (std::unique_ptr<const PropertySetErrorCallback> callback), (override));
+ MOCK_METHOD(std::chrono::nanoseconds, getPropertyOnChangeEventBatchingWindow, (), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, subscribe, (aidlvhal::SubscribeOptions options), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, unsubscribe, (int32_t propId, int32_t areaId), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, updateSampleRate,
+ (int32_t propId, int32_t areaId, float sampleRate), (override));
+};
+
TEST(GRPCVehicleProxyServerUnitTest, ClientConnectDisconnect) {
auto testHardware = std::make_unique<VehicleHardwareForTest>();
// HACK: manipulate the underlying hardware via raw pointer for testing.
@@ -144,4 +172,70 @@
vehicleServer->Shutdown().Wait();
}
+TEST(GRPCVehicleProxyServerUnitTest, Subscribe) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::SubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+ aidlvhal::SubscribeOptions aidlOptions;
+ request.mutable_options()->set_prop_id(1);
+ request.mutable_options()->add_area_ids(2);
+ request.mutable_options()->set_sample_rate(1.234);
+ request.mutable_options()->set_resolution(0.01);
+ request.mutable_options()->set_enable_variable_update_rate(true);
+
+ EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+ .WillOnce(DoAll(SaveArg<0>(&aidlOptions), Return(aidlvhal::StatusCode::OK)));
+
+ auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+ EXPECT_EQ(aidlOptions.propId, 1);
+ EXPECT_EQ(aidlOptions.areaIds, std::vector<int32_t>{2});
+ EXPECT_FLOAT_EQ(aidlOptions.sampleRate, 1.234);
+ EXPECT_FLOAT_EQ(aidlOptions.resolution, 0.01);
+ EXPECT_TRUE(aidlOptions.enableVariableUpdateRate);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, SubscribeNotAvailable) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::SubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+
+ EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+ .WillOnce(Return(aidlvhal::StatusCode::NOT_AVAILABLE));
+
+ auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::NOT_AVAILABLE);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, Unsubscribe) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::UnsubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+ request.set_prop_id(1);
+ request.set_area_id(2);
+
+ EXPECT_CALL(*mockHardwarePtr, unsubscribe(1, 2)).WillOnce(Return(aidlvhal::StatusCode::OK));
+
+ auto grpcStatus = server.Unsubscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index d10aa3e..94c09aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -42,23 +42,21 @@
host_supported: true,
}
-cc_test {
+cc_test_host {
name: "VehicleHalProtoMessageConverterTest",
srcs: [
"test/*.cpp",
],
vendor: true,
defaults: ["VehicleHalDefaults"],
- shared_libs: [
- "libprotobuf-cpp-full",
- "libjsoncpp",
- ],
static_libs: [
"VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalProtoMessageConverter",
"VehicleHalProtos",
"VehicleHalUtils",
"libgtest",
+ "libprotobuf-cpp-full",
+ "libjsoncpp",
],
data: [
":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
index 1c26fe8..25c07ef 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
@@ -18,6 +18,7 @@
#define android_hardware_automotive_vehicle_aidl_impl_grpc_utils_proto_message_converter_include_ProtoMessageConverter_H_
#include <VehicleHalTypes.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
#include <android/hardware/automotive/vehicle/VehicleAreaConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -46,6 +47,12 @@
void protoToAidl(
const ::android::hardware::automotive::vehicle::proto::VehiclePropValue& inProtoVal,
::aidl::android::hardware::automotive::vehicle::VehiclePropValue* outAidlVal);
+// Convert AIDL SubscribeOptions to Protobuf SubscribeOptions.
+void aidlToProto(const ::aidl::android::hardware::automotive::vehicle::SubscribeOptions& in,
+ ::android::hardware::automotive::vehicle::proto::SubscribeOptions* out);
+// Convert Protobuf SubscribeOptions to AIDL SubscribeOptions.
+void protoToAidl(const ::android::hardware::automotive::vehicle::proto::SubscribeOptions& in,
+ ::aidl::android::hardware::automotive::vehicle::SubscribeOptions* out);
} // namespace proto_msg_converter
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
index 1ea0df4..c40004a 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
@@ -152,6 +152,24 @@
COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, float_values, out, value.floatValues);
}
+void aidlToProto(const aidl_vehicle::SubscribeOptions& in, proto::SubscribeOptions* out) {
+ out->set_prop_id(in.propId);
+ for (int areaId : in.areaIds) {
+ out->add_area_ids(areaId);
+ }
+ out->set_sample_rate(in.sampleRate);
+ out->set_resolution(in.resolution);
+ out->set_enable_variable_update_rate(in.enableVariableUpdateRate);
+}
+
+void protoToAidl(const proto::SubscribeOptions& in, aidl_vehicle::SubscribeOptions* out) {
+ out->propId = in.prop_id();
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, area_ids, out, areaIds);
+ out->sampleRate = in.sample_rate();
+ out->resolution = in.resolution();
+ out->enableVariableUpdateRate = in.enable_variable_update_rate();
+}
+
#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index 308be46..2efda5b 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -22,6 +22,7 @@
#include <android-base/file.h>
#include <android-base/format.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
#include <gtest/gtest.h>
@@ -114,6 +115,21 @@
return ::fmt::format("property_{:d}", info.param.prop);
});
+TEST_F(PropValueConversionTest, testConvertSubscribeOption) {
+ proto::SubscribeOptions protoOptions;
+ aidl_vehicle::SubscribeOptions aidlOptions = {.propId = 1,
+ .areaIds = {1, 2},
+ .sampleRate = 1.234,
+ .resolution = 0.01,
+ .enableVariableUpdateRate = true};
+ aidl_vehicle::SubscribeOptions outputOptions;
+
+ aidlToProto(aidlOptions, &protoOptions);
+ protoToAidl(protoOptions, &outputOptions);
+
+ EXPECT_EQ(aidlOptions, outputOptions);
+}
+
} // namespace proto_msg_converter
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index 56fad7e..b2edf75 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -50,6 +50,9 @@
"android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.h",
"android/hardware/automotive/vehicle/VehiclePropValue.pb.h",
"android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.h",
+ "android/hardware/automotive/vehicle/SubscribeOptions.pb.h",
+ "android/hardware/automotive/vehicle/SubscribeRequest.pb.h",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.h",
],
}
@@ -74,6 +77,9 @@
"android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.cc",
"android/hardware/automotive/vehicle/VehiclePropValue.pb.cc",
"android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.cc",
+ "android/hardware/automotive/vehicle/SubscribeOptions.pb.cc",
+ "android/hardware/automotive/vehicle/SubscribeRequest.pb.cc",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.cc",
],
}
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
new file mode 100644
index 0000000..3fc6581
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message SubscribeOptions {
+ int32 prop_id = 1;
+ repeated int32 area_ids = 2;
+ float sample_rate = 3;
+ float resolution = 4;
+ bool enable_variable_update_rate = 5;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
new file mode 100644
index 0000000..4ce6335
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+import "android/hardware/automotive/vehicle/SubscribeOptions.proto";
+
+message SubscribeRequest {
+ SubscribeOptions options = 1;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
new file mode 100644
index 0000000..314fbf0
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message UnsubscribeRequest {
+ int32 prop_id = 1;
+ int32 area_id = 2;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 250b30c..fa2a310 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -42,10 +42,11 @@
namespace automotive {
namespace vehicle {
-class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehicle::BnVehicle {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+class DefaultVehicleHal final : public aidlvhal::BnVehicle {
public:
- using CallbackType =
- std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+ using CallbackType = std::shared_ptr<aidlvhal::IVehicleCallback>;
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
@@ -54,26 +55,16 @@
~DefaultVehicleHal();
- ndk::ScopedAStatus getAllPropConfigs(
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus getValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
- override;
- ndk::ScopedAStatus setValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
- override;
- ndk::ScopedAStatus getPropConfigs(
- const std::vector<int32_t>& props,
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus subscribe(
- const CallbackType& callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options,
- int32_t maxSharedMemoryFileCount) override;
+ ndk::ScopedAStatus getAllPropConfigs(aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus getValues(const CallbackType& callback,
+ const aidlvhal::GetValueRequests& requests) override;
+ ndk::ScopedAStatus setValues(const CallbackType& callback,
+ const aidlvhal::SetValueRequests& requests) override;
+ ndk::ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
+ aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus subscribe(const CallbackType& callback,
+ const std::vector<aidlvhal::SubscribeOptions>& options,
+ int32_t maxSharedMemoryFileCount) override;
ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
const std::vector<int32_t>& propIds) override;
ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
@@ -86,12 +77,8 @@
// friend class for unit testing.
friend class DefaultVehicleHalTest;
- using GetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::GetValueResult,
- aidl::android::hardware::automotive::vehicle::GetValueResults>;
- using SetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
- aidl::android::hardware::automotive::vehicle::SetValueResults>;
+ using GetValuesClient = GetSetValuesClient<aidlvhal::GetValueResult, aidlvhal::GetValueResults>;
+ using SetValuesClient = GetSetValuesClient<aidlvhal::SetValueResult, aidlvhal::SetValueResults>;
// A wrapper for binder lifecycle operations to enable stubbing for test.
class BinderLifecycleInterface {
@@ -137,28 +124,27 @@
bool mShouldRefreshPropertyConfigs;
std::unique_ptr<IVehicleHardware> mVehicleHardware;
- // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
- // lock guard them.
- std::unordered_map<int32_t, aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
- mConfigsByPropId;
- // Only modified in constructor, so thread-safe.
- std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile;
// PendingRequestPool is thread-safe.
std::shared_ptr<PendingRequestPool> mPendingRequestPool;
// SubscriptionManager is thread-safe.
std::shared_ptr<SubscriptionManager> mSubscriptionManager;
// ConcurrentQueue is thread-safe.
- std::shared_ptr<ConcurrentQueue<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
- mBatchedEventQueue;
+ std::shared_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>> mBatchedEventQueue;
// BatchingConsumer is thread-safe.
- std::shared_ptr<
- BatchingConsumer<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+ std::shared_ptr<BatchingConsumer<aidlvhal::VehiclePropValue>>
mPropertyChangeEventsBatchingConsumer;
// Only set once during initialization.
std::chrono::nanoseconds mEventBatchingWindow;
// Only used for testing.
int32_t mTestInterfaceVersion = 0;
+ // mConfigsByPropId and mConfigFile is lazy initialized.
+ mutable std::mutex mConfigInitLock;
+ mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+ mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
+ GUARDED_BY(mConfigInitLock);
+ mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+
std::mutex mLock;
std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
GUARDED_BY(mLock);
@@ -182,32 +168,23 @@
// A thread to handle onBinderDied or onBinderUnlinked event.
std::thread mOnBinderDiedUnlinkedHandlerThread;
- android::base::Result<void> checkProperty(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+ android::base::Result<void> checkProperty(const aidlvhal::VehiclePropValue& propValue);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
- requests);
+ const std::vector<aidlvhal::GetValueRequest>& requests);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
- requests);
- VhalResult<void> checkSubscribeOptions(
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options);
+ const std::vector<aidlvhal::SetValueRequest>& requests);
+ VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
- VhalResult<void> checkPermissionHelper(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
- aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess accessToTest) const;
+ VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
+ aidlvhal::VehiclePropertyAccess accessToTest) const;
- VhalResult<void> checkReadPermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkReadPermission(const aidlvhal::VehiclePropValue& value) const;
- VhalResult<void> checkWritePermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
- android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
- getConfig(int32_t propId) const;
+ android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
void onBinderDiedWithContext(const AIBinder* clientId);
@@ -219,7 +196,7 @@
bool checkDumpPermission();
- bool getAllPropConfigsFromHardware();
+ bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
// The looping handler function to process all onBinderDied or onBinderUnlinked events in
// mBinderEvents.
@@ -228,19 +205,19 @@
size_t countSubscribeClients();
// Handles the property change events in batch.
- void handleBatchedPropertyEvents(
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- batchedEvents);
+ void handleBatchedPropertyEvents(std::vector<aidlvhal::VehiclePropValue>&& batchedEvents);
- int32_t getVhalInterfaceVersion();
+ int32_t getVhalInterfaceVersion() const;
+
+ // Gets mConfigsByPropId, lazy init it if necessary.
+ const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
+ // Gets mConfigFile, lazy init it if necessary.
+ const ndk::ScopedFileDescriptor* getConfigFile() const;
// Puts the property change events into a queue so that they can handled in batch.
static void batchPropertyChangeEvent(
- const std::weak_ptr<ConcurrentQueue<
- aidl::android::hardware::automotive::vehicle::VehiclePropValue>>&
- batchedEventQueue,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ const std::weak_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>>& batchedEventQueue,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
// Gets or creates a {@code T} object for the client to or from {@code clients}.
template <class T>
@@ -248,10 +225,8 @@
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
- static void onPropertyChangeEvent(
- const std::weak_ptr<SubscriptionManager>& subscriptionManager,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ static void onPropertyChangeEvent(const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
static void onPropertySetErrorEvent(
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index a29861f..9dc039d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -24,6 +24,7 @@
#include <VehicleUtils.h>
#include <VersionForVehicleProperty.h>
+#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android/binder_ibinder.h>
@@ -71,6 +72,7 @@
using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
std::string toString(const std::unordered_set<int64_t>& values) {
std::string str = "";
@@ -103,10 +105,7 @@
: mVehicleHardware(std::move(vehicleHardware)),
mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
mTestInterfaceVersion(testInterfaceVersion) {
- if (!getAllPropConfigsFromHardware()) {
- return;
- }
-
+ ALOGD("DefaultVehicleHal init");
IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
mEventBatchingWindow = mVehicleHardware->getPropertyOnChangeEventBatchingWindow();
@@ -319,16 +318,18 @@
mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
}
-int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() const {
if (mTestInterfaceVersion != 0) {
return mTestInterfaceVersion;
}
int32_t myVersion = 0;
- getInterfaceVersion(&myVersion);
+ // getInterfaceVersion is in-reality a const method.
+ const_cast<DefaultVehicleHal*>(this)->getInterfaceVersion(&myVersion);
return myVersion;
}
-bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
+bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
+ ALOGD("Get all property configs from hardware");
auto configs = mVehicleHardware->getAllPropertyConfigs();
std::vector<VehiclePropConfig> filteredConfigs;
int32_t myVersion = getVhalInterfaceVersion();
@@ -373,22 +374,46 @@
return true;
}
+const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigFile.get();
+}
+
+const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
+ const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigsByPropId;
+}
+
ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
- if (mConfigFile != nullptr) {
+ const ScopedFileDescriptor* configFile = getConfigFile();
+ const auto& configsByPropId = getConfigsByPropId();
+ if (configFile != nullptr) {
output->payloads.clear();
- output->sharedMemoryFd.set(dup(mConfigFile->get()));
+ output->sharedMemoryFd.set(dup(configFile->get()));
return ScopedAStatus::ok();
}
- output->payloads.reserve(mConfigsByPropId.size());
- for (const auto& [_, config] : mConfigsByPropId) {
+ output->payloads.reserve(configsByPropId.size());
+ for (const auto& [_, config] : configsByPropId) {
output->payloads.push_back(config);
}
return ScopedAStatus::ok();
}
Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
- auto it = mConfigsByPropId.find(propId);
- if (it == mConfigsByPropId.end()) {
+ const auto& configsByPropId = getConfigsByPropId();
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return Error() << "no config for property, ID: " << propId;
}
return &(it->second);
@@ -634,9 +659,11 @@
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
VehiclePropConfigs* output) {
std::vector<VehiclePropConfig> configs;
+ const auto& configsByPropId = getConfigsByPropId();
for (int32_t prop : props) {
- if (mConfigsByPropId.find(prop) != mConfigsByPropId.end()) {
- configs.push_back(mConfigsByPropId[prop]);
+ auto it = configsByPropId.find(prop);
+ if (it != configsByPropId.end()) {
+ configs.push_back(it->second);
} else {
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
toInt(StatusCode::INVALID_ARG),
@@ -665,13 +692,15 @@
VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
const std::vector<SubscribeOptions>& options) {
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
- if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return StatusError(StatusCode::INVALID_ARG)
<< StringPrintf("no config for property, ID: %" PRId32, propId);
}
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = it->second;
std::vector<VehicleAreaConfig> areaConfigs;
if (option.areaIds.empty()) {
areaConfigs = config.areaConfigs;
@@ -744,10 +773,11 @@
}
std::vector<SubscribeOptions> onChangeSubscriptions;
std::vector<SubscribeOptions> continuousSubscriptions;
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
// We have already validate config exists.
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = configsByPropId.at(propId);
SubscribeOptions optionCopy = option;
// If areaIds is empty, subscribe to all areas.
@@ -871,7 +901,7 @@
(areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
return StatusError(StatusCode::ACCESS_DENIED)
<< StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
- propId, accessToTest);
+ propId, static_cast<int32_t>(accessToTest));
}
return {};
}
@@ -936,17 +966,19 @@
}
DumpResult result = mVehicleHardware->dump(options);
if (result.refreshPropertyConfigs) {
- getAllPropConfigsFromHardware();
+ std::scoped_lock lockGuard(mConfigInitLock);
+ getAllPropConfigsFromHardwareLocked();
}
dprintf(fd, "%s", (result.buffer + "\n").c_str());
if (!result.callerShouldDumpState) {
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
+ const auto& configsByPropId = getConfigsByPropId();
{
std::scoped_lock<std::mutex> lockGuard(mLock);
dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
- dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+ dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index f8818fd..f273c7a 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -105,3 +105,25 @@
latest_android_hardware_bluetooth_audio + "-ndk",
],
}
+
+cc_defaults {
+ name: "latest_android_hardware_bluetooth_audio_ndk_android_shared",
+ target: {
+ android: {
+ shared_libs: [
+ latest_android_hardware_bluetooth_audio + "-ndk",
+ ],
+ },
+ },
+}
+
+cc_defaults {
+ name: "latest_android_hardware_bluetooth_audio_ndk_android_static",
+ target: {
+ android: {
+ static_libs: [
+ latest_android_hardware_bluetooth_audio + "-ndk",
+ ],
+ },
+ },
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index dc36ac0..2a2cab0 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -184,12 +184,13 @@
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
std::vector<CodecInfo> db_codec_info =
BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type);
- if (!db_codec_info.empty()) {
- auto& provider_info = _aidl_return->emplace();
- provider_info.name = kLeAudioOffloadProviderName;
- provider_info.codecInfos = db_codec_info;
- return ndk::ScopedAStatus::ok();
- }
+ // Return provider info supports without checking db_codec_info
+ // This help with various flow implementation for multidirectional support.
+ auto& provider_info = _aidl_return->emplace();
+ provider_info.supportsMultidirectionalCapabilities = true;
+ provider_info.name = kLeAudioOffloadProviderName;
+ provider_info.codecInfos = db_codec_info;
+ return ndk::ScopedAStatus::ok();
}
if (session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index a692d84..5002a1a 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -165,8 +165,8 @@
return cfg_codec == req_codec;
}
-bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
- AudioContext setting_context,
+bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
+ AudioContext& setting_context,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
// If has no metadata, assume match
if (!capabilities.metadata.has_value()) return true;
@@ -178,7 +178,11 @@
auto& context = metadata.value()
.get<MetadataLtv::Tag::preferredAudioContexts>()
.values;
- if (setting_context.bitmask & context.bitmask) return true;
+ if (setting_context.bitmask & context.bitmask) {
+ // New mask with matched capability
+ setting_context.bitmask &= context.bitmask;
+ return true;
+ }
}
}
@@ -189,8 +193,12 @@
CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
capability_freq) {
- for (auto [freq, bitmask] : freq_to_support_bitmask_map)
- if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+ auto p = freq_to_support_bitmask_map.find(cfg_freq);
+ if (p != freq_to_support_bitmask_map.end()) {
+ if (capability_freq.bitmask & p->second) {
+ return true;
+ }
+ }
return false;
}
@@ -198,9 +206,11 @@
CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
capability_fduration) {
- for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
- if (cfg_fduration == fduration)
- return (capability_fduration.bitmask & bitmask);
+ auto p = fduration_to_support_fduration_map.find(cfg_fduration);
+ if (p != fduration_to_support_fduration_map.end())
+ if (capability_fduration.bitmask & p->second) {
+ return true;
+ }
return false;
}
@@ -240,50 +250,67 @@
for (auto& codec_capability : codec_capabilities) {
auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
- // Cannot find tag for the capability:
- if (cfg == cfg_tag_map.end()) return false;
+ // If capability has this tag, but our configuration doesn't
+ // Then we will assume it is matched
+ if (cfg == cfg_tag_map.end()) {
+ continue;
+ }
- // Matching logic for sampling frequency
- if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
- if (!isMatchedSamplingFreq(
- cfg->second
- .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedSamplingFrequencies>()))
- return false;
- } else if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
- if (!isMatchedFrameDuration(
- cfg->second
- .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedFrameDurations>()))
- return false;
- } else if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
- if (!isMatchedAudioChannel(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedAudioChannelCounts>()))
- return false;
- } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
- supportedMaxCodecFramesPerSDU) {
- if (!isMatchedCodecFramesPerSDU(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedMaxCodecFramesPerSDU>()))
- return false;
- } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
- supportedOctetsPerCodecFrame) {
- if (!isMatchedOctetsPerCodecFrame(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedOctetsPerCodecFrame>()))
- return false;
+ switch (codec_capability.getTag()) {
+ case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
+ if (!isMatchedSamplingFreq(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedSamplingFrequencies>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
+ if (!isMatchedFrameDuration(
+ cfg->second
+ .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedFrameDurations>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
+ if (!isMatchedAudioChannel(
+ cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+ audioChannelAllocation>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedAudioChannelCounts>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
+ if (!isMatchedCodecFramesPerSDU(
+ cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+ codecFrameBlocksPerSDU>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedMaxCodecFramesPerSDU>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
+ if (!isMatchedOctetsPerCodecFrame(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedOctetsPerCodecFrame>())) {
+ return false;
+ }
+ break;
+ }
}
}
@@ -298,11 +325,16 @@
if (requirement_cfg.codecId.has_value()) {
if (!setting_cfg.codecId.has_value()) return false;
if (!isMatchedValidCodec(setting_cfg.codecId.value(),
- requirement_cfg.codecId.value()))
+ requirement_cfg.codecId.value())) {
return false;
+ }
}
- if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+ if (requirement_cfg.targetLatency ==
+ LeAudioAseConfiguration::TargetLatency::UNDEFINED ||
+ setting_cfg.targetLatency != requirement_cfg.targetLatency) {
+ return false;
+ }
// Ignore PHY requirement
// Check all codec configuration
@@ -314,9 +346,13 @@
for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
// Directly compare CodecSpecificConfigurationLtv
auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
- if (cfg == cfg_tag_map.end()) return false;
+ if (cfg == cfg_tag_map.end()) {
+ return false;
+ }
- if (cfg->second != requirement_cfg) return false;
+ if (cfg->second != requirement_cfg) {
+ return false;
+ }
}
// Ignore vendor configuration and metadata requirement
@@ -326,10 +362,13 @@
bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
LeAudioBisConfiguration bis_cfg,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
- if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false;
- if (!isCapabilitiesMatchedCodecConfiguration(
- bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities))
+ if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
return false;
+ }
+ if (!isCapabilitiesMatchedCodecConfiguration(
+ bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
+ return false;
+ }
return true;
}
@@ -357,31 +396,35 @@
}
void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
- std::vector<std::optional<AseDirectionConfiguration>>&
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
direction_configurations,
- const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
- requirements,
- std::vector<std::optional<AseDirectionConfiguration>>&
+ const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
valid_direction_configurations) {
- for (auto direction_configuration : direction_configurations) {
- if (!requirements.has_value()) {
- // If there's no requirement, all are valid
- valid_direction_configurations.push_back(direction_configuration);
- continue;
- }
- if (!direction_configuration.has_value()) continue;
-
- for (auto& requirement : requirements.value()) {
- if (!requirement.has_value()) continue;
+ if (!valid_direction_configurations.has_value()) {
+ valid_direction_configurations =
+ std::vector<std::optional<AseDirectionConfiguration>>();
+ }
+ // For every requirement, find the matched ase configuration
+ if (!direction_configurations.has_value()) return;
+ for (auto& requirement : requirements) {
+ if (!requirement.has_value()) continue;
+ for (auto direction_configuration : direction_configurations.value()) {
+ if (!direction_configuration.has_value()) continue;
if (!isMatchedAseConfiguration(
direction_configuration.value().aseConfiguration,
requirement.value().aseConfiguration))
continue;
// Valid if match any requirement.
- valid_direction_configurations.push_back(direction_configuration);
+ valid_direction_configurations.value().push_back(direction_configuration);
break;
}
}
+ // Ensure that each requirement will have one direction configurations
+ if (valid_direction_configurations.value().empty() ||
+ (valid_direction_configurations.value().size() != requirements.size())) {
+ valid_direction_configurations = std::nullopt;
+ }
}
/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
@@ -392,8 +435,18 @@
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
uint8_t direction) {
+ // Create a new LeAudioAseConfigurationSetting and return
+ // For other direction will contain all settings
+ LeAudioAseConfigurationSetting filtered_setting{
+ .audioContext = setting.audioContext,
+ .sinkAseConfiguration = setting.sinkAseConfiguration,
+ .sourceAseConfiguration = setting.sourceAseConfiguration,
+ .flags = setting.flags,
+ .packing = setting.packing,
+ };
// Try to match context in metadata.
- if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
+ if (!filterCapabilitiesMatchedContext(filtered_setting.audioContext,
+ capabilities))
return std::nullopt;
// Get a list of all matched AseDirectionConfiguration
@@ -401,28 +454,30 @@
std::vector<std::optional<AseDirectionConfiguration>>*
direction_configuration = nullptr;
if (direction == kLeAudioDirectionSink) {
- if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
- direction_configuration = &setting.sinkAseConfiguration.value();
+ if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
+ direction_configuration = &filtered_setting.sinkAseConfiguration.value();
} else {
- if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
- direction_configuration = &setting.sourceAseConfiguration.value();
+ if (!filtered_setting.sourceAseConfiguration.has_value())
+ return std::nullopt;
+ direction_configuration = &filtered_setting.sourceAseConfiguration.value();
}
std::vector<std::optional<AseDirectionConfiguration>>
valid_direction_configuration;
filterCapabilitiesAseDirectionConfiguration(
*direction_configuration, capabilities, valid_direction_configuration);
- if (valid_direction_configuration.empty()) return std::nullopt;
+
+ // No valid configuration for this direction
+ if (valid_direction_configuration.empty()) {
+ return std::nullopt;
+ }
// Create a new LeAudioAseConfigurationSetting and return
- LeAudioAseConfigurationSetting filtered_setting;
- filtered_setting.audioContext = setting.audioContext;
- filtered_setting.packing = setting.packing;
+ // For other direction will contain all settings
if (direction == kLeAudioDirectionSink) {
filtered_setting.sinkAseConfiguration = valid_direction_configuration;
} else {
filtered_setting.sourceAseConfiguration = valid_direction_configuration;
}
- filtered_setting.flags = setting.flags;
return filtered_setting;
}
@@ -436,41 +491,49 @@
const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
requirement) {
// Try to match context in metadata.
- if (setting.audioContext != requirement.audioContext) return std::nullopt;
+ if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
+ requirement.audioContext.bitmask)
+ return std::nullopt;
+
+ // Further filter setting's context
+ setting.audioContext.bitmask &= requirement.audioContext.bitmask;
// Check requirement for the correct direction
const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
direction_requirement;
std::vector<std::optional<AseDirectionConfiguration>>*
direction_configuration;
- if (setting.sinkAseConfiguration.has_value()) {
- direction_configuration = &setting.sinkAseConfiguration.value();
- direction_requirement = &requirement.sinkAseRequirement;
- } else {
- direction_configuration = &setting.sourceAseConfiguration.value();
- direction_requirement = &requirement.sourceAseRequirement;
+
+ // Create a new LeAudioAseConfigurationSetting to return
+ LeAudioAseConfigurationSetting filtered_setting{
+ .audioContext = setting.audioContext,
+ .packing = setting.packing,
+ .flags = setting.flags,
+ };
+
+ if (requirement.sinkAseRequirement.has_value()) {
+ filterRequirementAseDirectionConfiguration(
+ setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
+ filtered_setting.sinkAseConfiguration);
+ if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
}
- std::vector<std::optional<AseDirectionConfiguration>>
- valid_direction_configuration;
- filterRequirementAseDirectionConfiguration(*direction_configuration,
- *direction_requirement,
- valid_direction_configuration);
- if (valid_direction_configuration.empty()) return std::nullopt;
-
- // Create a new LeAudioAseConfigurationSetting and return
- LeAudioAseConfigurationSetting filtered_setting;
- filtered_setting.audioContext = setting.audioContext;
- filtered_setting.packing = setting.packing;
- if (setting.sinkAseConfiguration.has_value())
- filtered_setting.sinkAseConfiguration = valid_direction_configuration;
- else
- filtered_setting.sourceAseConfiguration = valid_direction_configuration;
- filtered_setting.flags = setting.flags;
+ if (requirement.sourceAseRequirement.has_value()) {
+ filterRequirementAseDirectionConfiguration(
+ setting.sourceAseConfiguration,
+ requirement.sourceAseRequirement.value(),
+ filtered_setting.sourceAseConfiguration);
+ if (!filtered_setting.sourceAseConfiguration.has_value())
+ return std::nullopt;
+ }
return filtered_setting;
}
+// For each requirement, a valid ASE configuration will satify:
+// - matched with any sink capability (if presented)
+// - OR matched with any source capability (if presented)
+// - and the setting need to pass the requirement
ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
const std::optional<std::vector<
std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
@@ -487,46 +550,81 @@
ase_configuration_settings =
BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
- // Currently won't handle case where both sink and source capabilities
- // are passed in. Only handle one of them.
- const std::optional<std::vector<
- std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
- in_remoteAudioCapabilities;
- uint8_t direction = 0;
- if (in_remoteSinkAudioCapabilities.has_value()) {
- direction = kLeAudioDirectionSink;
- in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
- } else {
- direction = kLeAudioDirectionSource;
- in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+ if (!in_remoteSinkAudioCapabilities.has_value() &&
+ !in_remoteSourceAudioCapabilities.has_value()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ // Each setting consist of source and sink AseDirectionConfiguration vector
+ // Filter every sink capability
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
- capability_matched_ase_configuration_settings;
- // Matching with remote capabilities
- for (auto& setting : ase_configuration_settings) {
- for (auto& capability : in_remoteAudioCapabilities->value()) {
- if (!capability.has_value()) continue;
- auto filtered_ase_configuration_setting =
- getCapabilitiesMatchedAseConfigurationSettings(
- setting, capability.value(), direction);
- if (filtered_ase_configuration_setting.has_value()) {
- capability_matched_ase_configuration_settings.push_back(
- filtered_ase_configuration_setting.value());
+ matched_ase_configuration_settings;
+
+ if (in_remoteSinkAudioCapabilities.has_value()) {
+ // Matching each setting with any remote capabilities
+ for (auto& setting : ase_configuration_settings) {
+ for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_ase_configuration_setting =
+ getCapabilitiesMatchedAseConfigurationSettings(
+ setting, capability.value(), kLeAudioDirectionSink);
+ if (filtered_ase_configuration_setting.has_value()) {
+ matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ }
}
}
}
- // Matching with requirements
+ // Combine filter every source capability
+ if (in_remoteSourceAudioCapabilities.has_value()) {
+ // Matching each setting with any remote capabilities
+ for (auto& setting : ase_configuration_settings) {
+ for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_ase_configuration_setting =
+ getCapabilitiesMatchedAseConfigurationSettings(
+ setting, capability.value(), kLeAudioDirectionSource);
+ if (filtered_ase_configuration_setting.has_value()) {
+ // Put into the same list
+ // possibly duplicated, filtered by requirement later
+ matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ }
+ }
+ }
+ }
+
+ if (matched_ase_configuration_settings.empty()) {
+ LOG(WARNING) << __func__ << ": No setting matched the capability";
+ return ndk::ScopedAStatus::ok();
+ }
+ // Each requirement will match with a valid setting
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
- for (auto& setting : capability_matched_ase_configuration_settings) {
- for (auto& requirement : in_requirements) {
+ for (auto& requirement : in_requirements) {
+ LOG(INFO) << __func__ << ": Trying to match for the requirement "
+ << requirement.toString();
+ bool is_matched = false;
+
+ for (auto& setting : matched_ase_configuration_settings) {
auto filtered_ase_configuration_setting =
getRequirementMatchedAseConfigurationSettings(setting, requirement);
if (filtered_ase_configuration_setting.has_value()) {
result.push_back(filtered_ase_configuration_setting.value());
+ LOG(INFO) << __func__ << ": Result = "
+ << filtered_ase_configuration_setting.value().toString();
+ // Found a matched setting, ignore other settings
+ is_matched = true;
+ break;
}
}
+ if (!is_matched) {
+ // If cannot satisfy this requirement, return an empty result
+ LOG(WARNING) << __func__ << ": Cannot match the requirement "
+ << requirement.toString();
+ result.clear();
+ break;
+ }
}
*_aidl_return = result;
@@ -537,41 +635,45 @@
LeAudioAseQosConfiguration setting_qos,
AseQosDirectionRequirement requirement_qos) {
if (setting_qos.retransmissionNum !=
- requirement_qos.preferredRetransmissionNum)
+ requirement_qos.preferredRetransmissionNum) {
return false;
- if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs)
+ }
+ if (setting_qos.maxTransportLatencyMs >
+ requirement_qos.maxTransportLatencyMs) {
return false;
+ }
// Ignore other parameters, as they are not populated in the setting_qos
return true;
}
-ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
- const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
- in_qosRequirement,
- IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
- IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
- // Get all configuration settings
- std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
- ase_configuration_settings =
- BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
+ return ((qosRequirement.maxTransportLatencyMs > 0) &&
+ (qosRequirement.presentationDelayMaxUs > 0) &&
+ (qosRequirement.presentationDelayMaxUs >=
+ qosRequirement.presentationDelayMinUs));
+}
- // Direction QoS matching
- // Only handle one direction input case
- uint8_t direction = 0;
+std::optional<LeAudioAseQosConfiguration>
+LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
+ uint8_t direction,
+ const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+ qosRequirement,
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings) {
std::optional<AseQosDirectionRequirement> direction_qos_requirement =
std::nullopt;
- if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
- direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value();
- direction = kLeAudioDirectionSink;
- } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
- direction_qos_requirement =
- in_qosRequirement.sourceAseQosRequirement.value();
- direction = kLeAudioDirectionSource;
+
+ // Get the correct direction
+ if (direction == kLeAudioDirectionSink) {
+ direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
+ } else {
+ direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
}
for (auto& setting : ase_configuration_settings) {
// Context matching
- if (setting.audioContext != in_qosRequirement.audioContext) continue;
+ if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
+ qosRequirement.audioContext.bitmask)
+ continue;
// Match configuration flags
// Currently configuration flags are not populated, ignore.
@@ -592,10 +694,7 @@
if (!cfg.has_value()) continue;
// If no requirement, return the first QoS
if (!direction_qos_requirement.has_value()) {
- result.sinkQosConfiguration = cfg.value().qosConfiguration;
- result.sourceQosConfiguration = cfg.value().qosConfiguration;
- *_aidl_return = result;
- return ndk::ScopedAStatus::ok();
+ return cfg.value().qosConfiguration;
}
// If has requirement, return the first matched QoS
@@ -607,17 +706,41 @@
direction_qos_requirement.value().aseConfiguration) &&
isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
direction_qos_requirement.value())) {
- if (direction == kLeAudioDirectionSink)
- result.sinkQosConfiguration = cfg.value().qosConfiguration;
- else
- result.sourceQosConfiguration = cfg.value().qosConfiguration;
- *_aidl_return = result;
- return ndk::ScopedAStatus::ok();
+ return cfg.value().qosConfiguration;
}
}
}
- // No match, return empty QoS
+ return std::nullopt;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
+ const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+ in_qosRequirement,
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+
+ // Get all configuration settings
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+ ase_configuration_settings =
+ BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+ // Direction QoS matching
+ // Only handle one direction input case
+ if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
+ if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ result.sinkQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSink, in_qosRequirement, ase_configuration_settings);
+ }
+ if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
+ if (!isValidQosRequirement(
+ in_qosRequirement.sourceAseQosRequirement.value()))
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ result.sourceQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSource, in_qosRequirement, ase_configuration_settings);
+ }
+
*_aidl_return = result;
return ndk::ScopedAStatus::ok();
};
@@ -649,9 +772,13 @@
BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
broadcast_settings.clear();
+
+ // Default value for unmapped fields
CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
default_allocation.bitmask =
CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+ CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
+ default_frame.value = 2;
for (auto& codec_info : db_codec_info) {
if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
@@ -669,15 +796,20 @@
octets.value = transport.bitdepth[0];
bis_cfg.codecConfiguration = {
- sampling_freq_map[transport.samplingFrequencyHz[0]], octets,
- frame_duration_map[transport.frameDurationUs[0]], default_allocation};
+ sampling_freq_map[transport.samplingFrequencyHz[0]],
+ octets,
+ frame_duration_map[transport.frameDurationUs[0]],
+ default_allocation,
+ default_frame,
+ };
// Add information to structure
IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
- sub_bis_cfg.numBis = 1;
+ sub_bis_cfg.numBis = 2;
sub_bis_cfg.bisConfiguration = bis_cfg;
IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
- sub_cfg.bisConfigurations = {sub_bis_cfg};
+ // Populate the same sub config
+ sub_cfg.bisConfigurations = {sub_bis_cfg, sub_bis_cfg};
setting.subgroupsConfigurations = {sub_cfg};
broadcast_settings.push_back(setting);
@@ -721,6 +853,36 @@
return filtered_setting;
}
+bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
+ AudioContext setting_context,
+ LeAudioBroadcastSubgroupConfiguration configuration) {
+ // Find any valid context metadata in the bisConfigurations
+ // assuming the bis configuration in the same bis subgroup
+ // will have the same context metadata
+ std::optional<AudioContext> config_context = std::nullopt;
+
+ for (auto& p : configuration.bisConfigurations)
+ if (p.bisConfiguration.metadata.has_value()) {
+ bool is_context_found = false;
+ for (auto& metadata : p.bisConfiguration.metadata.value()) {
+ if (!metadata.has_value()) continue;
+ if (metadata.value().getTag() ==
+ MetadataLtv::Tag::preferredAudioContexts) {
+ config_context = metadata.value()
+ .get<MetadataLtv::Tag::preferredAudioContexts>()
+ .values;
+ is_context_found = true;
+ break;
+ }
+ }
+ if (is_context_found) break;
+ }
+
+ // Not found context metadata in any of the bis configuration, assume matched
+ if (!config_context.has_value()) return true;
+ return (setting_context.bitmask & config_context.value().bitmask);
+}
+
ndk::ScopedAStatus
LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
const std::optional<std::vector<
@@ -729,23 +891,28 @@
const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
in_requirement,
LeAudioBroadcastConfigurationSetting* _aidl_return) {
- getBroadcastSettings();
- _aidl_return = nullptr;
+ if (in_requirement.subgroupConfigurationRequirements.empty()) {
+ LOG(WARNING) << __func__ << ": Empty requirement";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
- // Match and filter capability
+ // Broadcast setting are from provider info
+ // We will allow empty capability input, match all settings with requirements.
+ getBroadcastSettings();
std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
if (!in_remoteSinkAudioCapabilities.has_value()) {
- LOG(WARNING) << __func__ << ": Empty capability";
- return ndk::ScopedAStatus::ok();
- }
- for (auto& setting : broadcast_settings) {
- for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
- if (!capability.has_value()) continue;
- auto filtered_setting =
- getCapabilitiesMatchedBroadcastConfigurationSettings(
- setting, capability.value());
- if (filtered_setting.has_value())
- filtered_settings.push_back(filtered_setting.value());
+ LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
+ filtered_settings = broadcast_settings;
+ } else {
+ for (auto& setting : broadcast_settings) {
+ for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_setting =
+ getCapabilitiesMatchedBroadcastConfigurationSettings(
+ setting, capability.value());
+ if (filtered_setting.has_value())
+ filtered_settings.push_back(filtered_setting.value());
+ }
}
}
@@ -754,36 +921,52 @@
return ndk::ScopedAStatus::ok();
}
- // Match and return the first matched requirement
if (in_requirement.subgroupConfigurationRequirements.empty()) {
LOG(INFO) << __func__ << ": Empty requirement";
*_aidl_return = filtered_settings[0];
return ndk::ScopedAStatus::ok();
}
+ // For each subgroup config requirement, find a suitable subgroup config.
+ // Gather these suitable subgroup config in an array.
+ // If the setting can satisfy all requirement, we can return the setting
+ // with the filtered array.
for (auto& setting : filtered_settings) {
- // Further filter out bis configuration
- LeAudioBroadcastConfigurationSetting filtered_setting(setting);
- filtered_setting.subgroupsConfigurations.clear();
- for (auto& sub_cfg : setting.subgroupsConfigurations) {
- bool isMatched = false;
- for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+ LeAudioBroadcastConfigurationSetting matched_setting(setting);
+ matched_setting.subgroupsConfigurations.clear();
+ auto total_num_bis = 0;
+
+ bool matched_all_requirement = true;
+
+ for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+ bool is_matched = false;
+ for (auto& sub_cfg : setting.subgroupsConfigurations) {
+ // Match the context
+ if (!isSubgroupConfigurationMatchedContext(sub_req.audioContext,
+ sub_cfg))
+ continue;
// Matching number of BIS
if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
continue;
- // Currently will ignore quality and context hint.
- isMatched = true;
+ // Currently will ignore quality matching.
+ matched_setting.subgroupsConfigurations.push_back(sub_cfg);
+ total_num_bis += sub_cfg.bisConfigurations.size();
+ is_matched = true;
break;
}
- if (isMatched)
- filtered_setting.subgroupsConfigurations.push_back(sub_cfg);
+ // There is an unmatched requirement, this setting cannot be used
+ if (!is_matched) {
+ matched_all_requirement = false;
+ break;
+ }
}
- // Return the first match
- if (!filtered_setting.subgroupsConfigurations.empty()) {
- LOG(INFO) << __func__ << ": Matched requirement";
- *_aidl_return = filtered_setting;
- return ndk::ScopedAStatus::ok();
- }
+
+ if (!matched_all_requirement) continue;
+
+ matched_setting.numBis = total_num_bis;
+ // Return the filtered setting if all requirement satified
+ *_aidl_return = matched_setting;
+ return ndk::ScopedAStatus::ok();
}
LOG(WARNING) << __func__ << ": Cannot match any requirement";
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 2785e7f..06cd405 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -96,8 +96,8 @@
// Private matching function definitions
bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
- bool isCapabilitiesMatchedContext(
- AudioContext setting_context,
+ bool filterCapabilitiesMatchedContext(
+ AudioContext& setting_context,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
bool isMatchedSamplingFreq(
CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
@@ -134,11 +134,10 @@
std::vector<std::optional<AseDirectionConfiguration>>&
valid_direction_configurations);
void filterRequirementAseDirectionConfiguration(
- std::vector<std::optional<AseDirectionConfiguration>>&
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
direction_configurations,
- const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
- requirements,
- std::vector<std::optional<AseDirectionConfiguration>>&
+ const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
valid_direction_configurations);
std::optional<LeAudioAseConfigurationSetting>
getCapabilitiesMatchedAseConfigurationSettings(
@@ -157,6 +156,14 @@
LeAudioBroadcastConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
void getBroadcastSettings();
+ std::optional<LeAudioAseQosConfiguration> getDirectionQosConfiguration(
+ uint8_t direction,
+ const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+ qosRequirement,
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings);
+ bool isSubgroupConfigurationMatchedContext(
+ AudioContext requirement_context,
+ LeAudioBroadcastSubgroupConfiguration configuration);
};
class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index c313fb7..ec63831 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -58,6 +58,7 @@
using aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv;
using aidl::android::hardware::bluetooth::audio::CodecSpecificConfigurationLtv;
using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::ConfigurationFlags;
using aidl::android::hardware::bluetooth::audio::HfpConfiguration;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
@@ -68,6 +69,7 @@
using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioAseConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioBisConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
using aidl::android::hardware::bluetooth::audio::
LeAudioCodecCapabilitiesSetting;
@@ -105,12 +107,24 @@
LeAudioAseConfigurationSetting::AseDirectionConfiguration;
using AseQosDirectionRequirement = IBluetoothAudioProvider::
LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement;
using LeAudioAseQosConfiguration =
IBluetoothAudioProvider::LeAudioAseQosConfiguration;
using LeAudioDeviceCapabilities =
IBluetoothAudioProvider::LeAudioDeviceCapabilities;
using LeAudioConfigurationRequirement =
IBluetoothAudioProvider::LeAudioConfigurationRequirement;
+using LeAudioBroadcastConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement;
+using LeAudioBroadcastSubgroupConfiguration =
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration;
+using LeAudioBroadcastSubgroupConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfigurationRequirement;
+using LeAudioBroadcastConfigurationSetting =
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting;
+using LeAudioSubgroupBisConfiguration =
+ IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration;
// Constants
@@ -2228,6 +2242,37 @@
BluetoothAudioProviderFactoryAidl::TearDown();
}
+ bool IsMultidirectionalCapabilitiesEnabled() {
+ if (!temp_provider_info_.has_value()) return false;
+
+ return temp_provider_info_.value().supportsMultidirectionalCapabilities;
+ }
+
+ bool IsAsymmetricConfigurationAllowed() {
+ if (!temp_provider_info_.has_value()) return false;
+ if (temp_provider_info_.value().codecInfos.empty()) return false;
+
+ for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+ if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio) {
+ return false;
+ }
+
+ auto flags =
+ codec_info.transport.get<CodecInfo::Transport::leAudio>().flags;
+
+ if (!flags) {
+ continue;
+ }
+
+ if (flags->bitmask &
+ ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
bool IsOffloadOutputSupported() {
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
@@ -2284,27 +2329,31 @@
return media_audio_context;
}
- LeAudioDeviceCapabilities GetDefaultRemoteCapability() {
+ LeAudioDeviceCapabilities GetDefaultRemoteSinkCapability() {
// Create a capability
LeAudioDeviceCapabilities capability;
capability.codecId = CodecId::Core::LC3;
auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
- pref_context_metadata.values = GetAudioContext(AudioContext::MEDIA);
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+ AudioContext::GAME);
capability.metadata = {pref_context_metadata};
auto sampling_rate =
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
auto frame_duration =
CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
frame_duration.bitmask =
- CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500;
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
octets.min = 0;
- octets.max = 60;
+ octets.max = 120;
auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
frames.value = 2;
capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
@@ -2312,29 +2361,394 @@
return capability;
}
- LeAudioConfigurationRequirement GetDefaultRequirement(
- bool is_source_requriement) {
+ LeAudioDeviceCapabilities GetDefaultRemoteSourceCapability() {
+ // Create a capability
+ LeAudioDeviceCapabilities capability;
+
+ capability.codecId = CodecId::Core::LC3;
+
+ auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::LIVE_AUDIO |
+ AudioContext::CONVERSATIONAL | AudioContext::GAME);
+ capability.metadata = {pref_context_metadata};
+
+ auto sampling_rate =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+ sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
+ auto frame_duration =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+ frame_duration.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+ auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+ octets.min = 0;
+ octets.max = 120;
+ auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+ frames.value = 2;
+ capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+ octets, frames};
+ return capability;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+ const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+ CodecSpecificConfigurationLtv::Tag tag) {
+ for (const auto ltv : configurationLtvs) {
+ if (ltv.getTag() == tag) {
+ return ltv;
+ }
+ }
+ return std::nullopt;
+ }
+
+ bool IsAseRequirementSatisfiedWithUnknownChannelCount(
+ const std::vector<std::optional<AseDirectionRequirement>>&
+ ase_requirements,
+ const std::vector<std::optional<AseDirectionConfiguration>>&
+ ase_configurations) {
+ /* This is mandatory to match sample freq, allocation however, when in the
+ * device group there is only one device which supports left and right
+ * allocation, and channel count is hidden from the BT stack, the BT stack
+ * will send single requirement but it can receive two configurations if the
+ * channel count is 1.
+ */
+
+ int num_of_ase_requirements = 0;
+ for (const auto& ase_req : ase_requirements) {
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (required_allocation_ltv == std::nullopt) {
+ continue;
+ }
+ int required_allocation =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+ num_of_ase_requirements += std::bitset<32>(required_allocation).count();
+ }
+
+ int num_of_satisfied_ase_requirements = 0;
+ for (const auto& ase_req : ase_requirements) {
+ if (!ase_req) {
+ continue;
+ }
+ auto required_sample_freq_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+ /* Allocation and sample freq shall be always in the requirement */
+ if (!required_sample_freq_ltv || !required_allocation_ltv) {
+ return false;
+ }
+
+ int required_allocation =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+
+ for (const auto& ase_conf : ase_configurations) {
+ if (!ase_conf) {
+ continue;
+ }
+ auto config_sample_freq_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto config_allocation_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (config_sample_freq_ltv == std::nullopt ||
+ config_allocation_ltv == std::nullopt) {
+ return false;
+ }
+
+ int configured_allocation = config_allocation_ltv
+ ->get<CodecSpecificConfigurationLtv::
+ Tag::audioChannelAllocation>()
+ .bitmask;
+
+ if (config_sample_freq_ltv == required_sample_freq_ltv &&
+ (required_allocation & configured_allocation)) {
+ num_of_satisfied_ase_requirements +=
+ std::bitset<32>(configured_allocation).count();
+ }
+ }
+ }
+
+ return (num_of_satisfied_ase_requirements == num_of_ase_requirements);
+ }
+
+ bool IsAseRequirementSatisfied(
+ const std::vector<std::optional<AseDirectionRequirement>>&
+ ase_requirements,
+ const std::vector<std::optional<AseDirectionConfiguration>>&
+ ase_configurations) {
+ // This is mandatory to match sample freq, allocation
+ int num_of_satisfied_ase_requirements = 0;
+
+ int required_allocations = 0;
+ for (const auto& ase_req : ase_requirements) {
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (required_allocation_ltv == std::nullopt) {
+ continue;
+ }
+
+ int allocations =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+ required_allocations += std::bitset<32>(allocations).count();
+ }
+
+ if (ase_requirements.size() != required_allocations) {
+ /* If more than one allication is requested in the requirement, then use
+ * different verifier */
+ return IsAseRequirementSatisfiedWithUnknownChannelCount(
+ ase_requirements, ase_configurations);
+ }
+
+ for (const auto& ase_req : ase_requirements) {
+ if (!ase_req) {
+ continue;
+ }
+ auto required_sample_freq_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+ /* Allocation and sample freq shall be always in the requirement */
+ if (!required_sample_freq_ltv || !required_allocation_ltv) {
+ return false;
+ }
+
+ for (const auto& ase_conf : ase_configurations) {
+ if (!ase_conf) {
+ continue;
+ }
+ auto config_sample_freq_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto config_allocation_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (config_sample_freq_ltv == std::nullopt ||
+ config_allocation_ltv == std::nullopt) {
+ return false;
+ }
+
+ if (config_sample_freq_ltv == required_sample_freq_ltv &&
+ config_allocation_ltv == required_allocation_ltv) {
+ num_of_satisfied_ase_requirements++;
+ break;
+ }
+ }
+ }
+
+ return (num_of_satisfied_ase_requirements == ase_requirements.size());
+ }
+
+ void VerifyIfRequirementsSatisfied(
+ const std::vector<LeAudioConfigurationRequirement>& requirements,
+ const std::vector<LeAudioAseConfigurationSetting>& configurations) {
+ if (requirements.empty() && configurations.empty()) {
+ return;
+ }
+
+ /* It might happen that vendor lib will provide same configuration for
+ * multiple contexts and it should be accepted
+ */
+
+ int num_of_requirements = 0;
+ for (const auto& req : requirements) {
+ num_of_requirements += std::bitset<32>(req.audioContext.bitmask).count();
+ }
+
+ int num_of_configurations = 0;
+ for (const auto& conf : configurations) {
+ num_of_configurations +=
+ std::bitset<32>(conf.audioContext.bitmask).count();
+ }
+
+ ASSERT_EQ(num_of_requirements, num_of_configurations);
+
+ int num_of_satisfied_requirements = 0;
+ for (const auto& req : requirements) {
+ for (const auto& conf : configurations) {
+ if ((req.audioContext.bitmask & conf.audioContext.bitmask) !=
+ req.audioContext.bitmask) {
+ continue;
+ }
+
+ if (req.sinkAseRequirement && req.sourceAseRequirement) {
+ if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
+ continue;
+ }
+
+ if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+ *conf.sinkAseConfiguration) ||
+ !IsAseRequirementSatisfied(*req.sourceAseRequirement,
+ *conf.sourceAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+
+ break;
+ } else if (req.sinkAseRequirement) {
+ if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+ *conf.sinkAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+ break;
+ } else if (req.sourceAseRequirement) {
+ if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
+ *conf.sourceAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+ break;
+ }
+ }
+ }
+ ASSERT_EQ(num_of_satisfied_requirements, num_of_requirements);
+ }
+
+ LeAudioConfigurationRequirement GetUnicastDefaultRequirement(
+ int32_t context_bits, bool is_sink_requirement,
+ bool is_source_requriement,
+ CodecSpecificConfigurationLtv::SamplingFrequency freq =
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000) {
// Create a requirements
LeAudioConfigurationRequirement requirement;
- requirement.audioContext = GetAudioContext(AudioContext::MEDIA);
+ requirement.audioContext = GetAudioContext(context_bits);
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
auto direction_ase_requriement = AseDirectionRequirement();
direction_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
direction_ase_requriement.aseConfiguration.targetLatency =
LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
- // Mismatch sampling frequency
direction_ase_requriement.aseConfiguration.codecConfiguration = {
- CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
- CodecSpecificConfigurationLtv::FrameDuration::US7500,
+ freq, CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation
+
};
+ if (is_sink_requirement)
+ requirement.sinkAseRequirement = {direction_ase_requriement};
+
if (is_source_requriement)
requirement.sourceAseRequirement = {direction_ase_requriement};
- else
- requirement.sinkAseRequirement = {direction_ase_requriement};
+
return requirement;
}
+ LeAudioConfigurationRequirement GetUnicastGameRequirement(bool asymmetric) {
+ // Create a requirements
+ LeAudioConfigurationRequirement requirement;
+ requirement.audioContext = GetAudioContext(AudioContext::GAME);
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto sink_ase_requriement = AseDirectionRequirement();
+ sink_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+ sink_ase_requriement.aseConfiguration.targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+ sink_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+
+ auto source_ase_requriement = AseDirectionRequirement();
+ source_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+ source_ase_requriement.aseConfiguration.targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+ if (asymmetric) {
+ source_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+ } else {
+ source_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+ }
+
+ requirement.sinkAseRequirement = {sink_ase_requriement};
+ requirement.sourceAseRequirement = {source_ase_requriement};
+
+ return requirement;
+ }
+
+ LeAudioAseQosConfigurationRequirement GetQosRequirements(
+ bool is_sink_requirement, bool is_source_requriement, bool valid = true) {
+ LeAudioAseQosConfigurationRequirement qosRequirement;
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ AseQosDirectionRequirement directionalRequirement = {
+ .framing = IBluetoothAudioProvider::Framing::UNFRAMED,
+ .preferredRetransmissionNum = 2,
+ .maxTransportLatencyMs = 10,
+ .presentationDelayMinUs = 40000,
+ .presentationDelayMaxUs = 40000,
+ .aseConfiguration =
+ {
+ .targetLatency = LeAudioAseConfiguration::TargetLatency::
+ BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ allocation},
+ },
+ };
+
+ if (!valid) {
+ // clear some required values;
+ directionalRequirement.maxTransportLatencyMs = 0;
+ directionalRequirement.presentationDelayMaxUs = 0;
+ }
+
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ if (is_source_requriement && is_sink_requirement) {
+ qosRequirement.sourceAseQosRequirement = directionalRequirement;
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ } else if (is_source_requriement) {
+ qosRequirement.sourceAseQosRequirement = directionalRequirement;
+ qosRequirement.sinkAseQosRequirement = std::nullopt;
+ } else if (is_sink_requirement) {
+ qosRequirement.sourceAseQosRequirement = std::nullopt;
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ }
+
+ return qosRequirement;
+ }
+
std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
@@ -2460,6 +2874,11 @@
AudioContext::NOTIFICATIONS, AudioContext::RINGTONE_ALERTS,
AudioContext::ALERTS, AudioContext::EMERGENCY_ALARM,
};
+
+ AudioContext bidirectional_contexts = {
+ .bitmask = AudioContext::CONVERSATIONAL | AudioContext::GAME |
+ AudioContext::VOICE_ASSISTANTS | AudioContext::LIVE_AUDIO,
+ };
};
/**
@@ -2511,6 +2930,40 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+
+ // Check empty capability for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability_Multidirectiona) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
std::vector<LeAudioConfigurationRequirement> empty_requirement;
std::vector<LeAudioAseConfigurationSetting> configurations;
@@ -2536,50 +2989,388 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
- std::vector<std::optional<LeAudioDeviceCapabilities>> capabilities = {
- GetDefaultRemoteCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ auto not_supported_sampling_rate_by_remote =
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025;
// Check empty capability for source direction
std::vector<LeAudioAseConfigurationSetting> configurations;
std::vector<LeAudioConfigurationRequirement> source_requirements = {
- GetDefaultRequirement(true)};
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /*sink */,
+ true /* source */,
+ not_supported_sampling_rate_by_remote)};
auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
- std::nullopt, capabilities, source_requirements, &configurations);
+ std::nullopt, source_capabilities, source_requirements, &configurations);
ASSERT_TRUE(aidl_retval.isOk());
ASSERT_TRUE(configurations.empty());
// Check empty capability for sink direction
std::vector<LeAudioConfigurationRequirement> sink_requirements = {
- GetDefaultRequirement(false)};
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /*sink */,
+ false /* source */,
+ not_supported_sampling_rate_by_remote)};
aidl_retval = audio_provider_->getLeAudioAseConfiguration(
- capabilities, std::nullopt, source_requirements, &configurations);
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
ASSERT_TRUE(aidl_retval.isOk());
ASSERT_TRUE(configurations.empty());
}
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetAseConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Should not ask for Source on ENCODING session if Multidiretional not
+ // supported
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check capability for remote sink direction
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ // Check multiple capability for remote sink direction
+ std::vector<LeAudioConfigurationRequirement> multi_sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, multi_sink_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+
+ // Check multiple context types in a single requirement.
+ std::vector<LeAudioConfigurationRequirement> multi_context_sink_requirements =
+ {GetUnicastDefaultRequirement(
+ AudioContext::MEDIA | AudioContext::SOUND_EFFECTS, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, multi_context_sink_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Verify source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+ // Verify sink configuration is received
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, combined_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetAsymmetricAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ if (!IsAsymmetricConfigurationAllowed()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ std::vector<LeAudioConfigurationRequirement> asymmetric_requirements = {
+ GetUnicastGameRequirement(true /* Asymmetric */)};
+
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, asymmetric_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(asymmetric_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetQoSConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement requirement =
+ GetQosRequirements(true, true);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ bool is_supported = false;
+ for (auto bitmask : all_context_bitmasks) {
+ requirement.audioContext = GetAudioContext(bitmask);
+ bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+
+ if (is_bidirectional) {
+ requirement.sourceAseQosRequirement = requirement.sinkAseQosRequirement;
+ } else {
+ requirement.sourceAseQosRequirement = std::nullopt;
+ }
+
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval =
+ audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ }
+
+ is_supported = true;
+ if (result.sinkQosConfiguration.has_value()) {
+ if (is_bidirectional) {
+ ASSERT_TRUE(result.sourceQosConfiguration.has_value());
+ } else {
+ ASSERT_FALSE(result.sourceQosConfiguration.has_value());
+ }
+ QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+ }
+ }
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetQoSConfiguration_InvalidRequirements) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement invalid_requirement =
+ GetQosRequirements(true /* sink */, false /* source */,
+ false /* valid */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ for (auto bitmask : all_context_bitmasks) {
+ invalid_requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+ invalid_requirement, &result);
+ ASSERT_FALSE(aidl_retval.isOk());
+ }
+}
+
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetQoSConfiguration) {
if (GetProviderFactoryInterfaceVersion() <
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+ requirement = GetQosRequirements(true /* sink */, false /* source */);
+
std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
QoSConfigurations;
+ bool is_supported = false;
for (auto bitmask : all_context_bitmasks) {
requirement.audioContext = GetAudioContext(bitmask);
IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
auto aidl_retval =
audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
- ASSERT_TRUE(aidl_retval.isOk());
- if (result.sinkQosConfiguration.has_value())
- QoSConfigurations.push_back(result.sinkQosConfiguration.value());
- if (result.sourceQosConfiguration.has_value())
- QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.sinkQosConfiguration.has_value()) {
+ QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+ }
+ }
}
- // QoS Configurations should not be empty, as we searched for all contexts
- ASSERT_FALSE(QoSConfigurations.empty());
+
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetDataPathConfiguration_Multidirectional) {
+ IBluetoothAudioProvider::StreamConfig sink_requirement;
+ IBluetoothAudioProvider::StreamConfig source_requirement;
+ std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
+ DataPathConfigurations;
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ bool is_supported = false;
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto streamMap = LeAudioConfiguration::StreamMap();
+
+ // Use some mandatory configuration
+ streamMap.streamHandle = 0x0001;
+ streamMap.audioChannelAllocation = 0x03;
+ streamMap.aseConfiguration = {
+ .targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+ };
+
+ // Bidirectional
+ sink_requirement.streamMap = {streamMap};
+ source_requirement.streamMap = {streamMap};
+
+ for (auto bitmask : all_context_bitmasks) {
+ sink_requirement.audioContext = GetAudioContext(bitmask);
+ source_requirement.audioContext = sink_requirement.audioContext;
+
+ IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
+ ::ndk::ScopedAStatus aidl_retval;
+
+ bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+ if (is_bidirectional) {
+ aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+ sink_requirement, source_requirement, &result);
+ } else {
+ aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+ sink_requirement, std::nullopt, &result);
+ }
+
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.outputConfig.has_value()) {
+ if (is_bidirectional) {
+ ASSERT_TRUE(result.inputConfig.has_value());
+ } else {
+ ASSERT_TRUE(!result.inputConfig.has_value());
+ }
+ DataPathConfigurations.push_back(result.outputConfig.value());
+ }
+ }
+ }
+
+ if (is_supported) {
+ // Datapath Configurations should not be empty, as we searched for all
+ // contexts
+ ASSERT_FALSE(DataPathConfigurations.empty());
+ }
}
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
@@ -2589,26 +3380,45 @@
GTEST_SKIP();
}
IBluetoothAudioProvider::StreamConfig sink_requirement;
- IBluetoothAudioProvider::StreamConfig source_requirement;
std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
DataPathConfigurations;
bool is_supported = false;
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto streamMap = LeAudioConfiguration::StreamMap();
+
+ // Use some mandatory configuration
+ streamMap.streamHandle = 0x0001;
+ streamMap.audioChannelAllocation = 0x03;
+ streamMap.aseConfiguration = {
+ .targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+ };
+
+ sink_requirement.streamMap = {streamMap};
for (auto bitmask : all_context_bitmasks) {
sink_requirement.audioContext = GetAudioContext(bitmask);
- source_requirement.audioContext = GetAudioContext(bitmask);
IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
auto aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
- sink_requirement, source_requirement, &result);
+ sink_requirement, std::nullopt, &result);
+
if (!aidl_retval.isOk()) {
- // If not OK, then it could be not supported, as it is an optional feature
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
} else {
is_supported = true;
- if (result.inputConfig.has_value())
- DataPathConfigurations.push_back(result.inputConfig.value());
- if (result.inputConfig.has_value())
- DataPathConfigurations.push_back(result.inputConfig.value());
+ if (result.outputConfig.has_value()) {
+ DataPathConfigurations.push_back(result.outputConfig.value());
+ }
}
}
@@ -2655,10 +3465,9 @@
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
- * Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
- DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
+ StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadOutputSupported()) {
GTEST_SKIP();
}
@@ -2678,8 +3487,8 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start session with invalid configuration
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
@@ -2758,8 +3567,8 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start session with invalid configuration
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
@@ -2879,10 +3688,9 @@
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
- * Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
- DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
+ StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadInputSupported()) {
GTEST_SKIP();
}
@@ -2903,12 +3711,229 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start with invalid configuration as it might be unknown on
+ // start
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check success for source direction (Input == DecodingSession == remote
+ // source)
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check failure for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check empty capability for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetAseConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Check source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+
+ // Check error result when requesting sink on DECODING session
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Check source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+ // Check empty capability for sink direction
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, combined_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetQoSConfiguration_InvalidRequirements) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement invalid_requirement =
+ GetQosRequirements(false /* sink */, true /* source */,
+ false /* valid */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ for (auto bitmask : all_context_bitmasks) {
+ invalid_requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+ invalid_requirement, &result);
+ ASSERT_FALSE(aidl_retval.isOk());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetQoSConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+ requirement = GetQosRequirements(false /* sink */, true /* source */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ bool is_supported = false;
+ for (auto bitmask : all_context_bitmasks) {
+ requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval =
+ audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.sourceQosConfiguration.has_value()) {
+ QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+ }
+ }
+ }
+
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
/**
* openProvider LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH
*/
@@ -3058,6 +4083,146 @@
return le_audio_codec_configs;
}
+ AudioContext GetAudioContext(int32_t bitmask) {
+ AudioContext media_audio_context;
+ media_audio_context.bitmask = bitmask;
+ return media_audio_context;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+ const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+ CodecSpecificConfigurationLtv::Tag tag) {
+ for (const auto ltv : configurationLtvs) {
+ if (ltv.getTag() == tag) {
+ return ltv;
+ }
+ }
+ return std::nullopt;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
+ GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
+ auto sample_freq_ltv = GetConfigurationLtv(
+ bis_conf.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ if (!sample_freq_ltv) {
+ return std::nullopt;
+ }
+ return (*sample_freq_ltv)
+ .get<CodecSpecificConfigurationLtv::samplingFrequency>();
+ }
+
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+ GetSubgroupSampleFreqs(
+ const LeAudioBroadcastSubgroupConfiguration& subgroup_conf) {
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> result = {};
+
+ for (const auto& bis_conf : subgroup_conf.bisConfigurations) {
+ auto sample_freq = GetBisSampleFreq(bis_conf.bisConfiguration);
+ if (sample_freq) {
+ result.push_back(*sample_freq);
+ }
+ }
+ return result;
+ }
+
+ void VerifyBroadcastConfiguration(
+ const LeAudioBroadcastConfigurationRequirement& requirements,
+ const LeAudioBroadcastConfigurationSetting& configuration,
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+ expectedSampleFreqs = {}) {
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> sampleFreqs =
+ {};
+
+ int number_of_requested_bises = 0;
+ for (const auto& subgroup_req :
+ requirements.subgroupConfigurationRequirements) {
+ number_of_requested_bises += subgroup_req.bisNumPerSubgroup;
+ }
+
+ if (!expectedSampleFreqs.empty()) {
+ for (const auto& subgroup_conf : configuration.subgroupsConfigurations) {
+ auto result = GetSubgroupSampleFreqs(subgroup_conf);
+ sampleFreqs.insert(sampleFreqs.end(), result.begin(), result.end());
+ }
+ }
+
+ ASSERT_EQ(number_of_requested_bises, configuration.numBis);
+ ASSERT_EQ(requirements.subgroupConfigurationRequirements.size(),
+ configuration.subgroupsConfigurations.size());
+
+ if (expectedSampleFreqs.empty()) {
+ return;
+ }
+
+ std::sort(sampleFreqs.begin(), sampleFreqs.end());
+ std::sort(expectedSampleFreqs.begin(), expectedSampleFreqs.end());
+
+ ASSERT_EQ(sampleFreqs, expectedSampleFreqs);
+ }
+
+ LeAudioDeviceCapabilities GetDefaultBroadcastSinkCapability() {
+ // Create a capability
+ LeAudioDeviceCapabilities capability;
+
+ capability.codecId = CodecId::Core::LC3;
+
+ auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+ AudioContext::GAME);
+ capability.metadata = {pref_context_metadata};
+
+ auto sampling_rate =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+ sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000 |
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000;
+ auto frame_duration =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+ frame_duration.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+ auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+ octets.min = 0;
+ octets.max = 120;
+ auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+ frames.value = 2;
+ capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+ octets, frames};
+ return capability;
+ }
+
+ LeAudioBroadcastConfigurationRequirement GetBroadcastRequirement(
+ bool standard_quality, bool high_quality) {
+ LeAudioBroadcastConfigurationRequirement requirement;
+
+ AudioContext media_audio_context;
+ media_audio_context.bitmask = AudioContext::MEDIA;
+
+ LeAudioBroadcastSubgroupConfigurationRequirement
+ standard_quality_requirement = {
+ .audioContext = media_audio_context,
+ .quality = IBluetoothAudioProvider::BroadcastQuality::STANDARD,
+ .bisNumPerSubgroup = 2};
+
+ LeAudioBroadcastSubgroupConfigurationRequirement high_quality_requirement =
+ {.audioContext = media_audio_context,
+ .quality = IBluetoothAudioProvider::BroadcastQuality::HIGH,
+ .bisNumPerSubgroup = 2};
+
+ if (standard_quality) {
+ requirement.subgroupConfigurationRequirements.push_back(
+ standard_quality_requirement);
+ }
+
+ if (high_quality) {
+ requirement.subgroupConfigurationRequirements.push_back(
+ high_quality_requirement);
+ }
+ return requirement;
+ }
+
std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
if (!supported) {
@@ -3164,18 +4329,93 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
empty_requirement;
- IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting* configuration =
- new IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting();
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
// Check empty capability for source direction
auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
- empty_capability, empty_requirement, configuration);
+ empty_capability, empty_requirement, &configuration);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+ GetBroadcastConfigurationEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+ one_subgroup_requirement =
+ GetBroadcastRequirement(true /* standard*/, false /* high */);
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+ empty_capability, one_subgroup_requirement, &configuration);
ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_NE(configuration.numBis, 0);
+ ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+ VerifyBroadcastConfiguration(one_subgroup_requirement, configuration);
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+ two_subgroup_requirement =
+ GetBroadcastRequirement(true /* standard*/, true /* high */);
+
+ // Check empty capability for source direction
+ aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+ empty_capability, two_subgroup_requirement, &configuration);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_NE(configuration.numBis, 0);
+ ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+ VerifyBroadcastConfiguration(two_subgroup_requirement, configuration);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+ GetBroadcastConfigurationNonEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> capability = {
+ GetDefaultBroadcastSinkCapability()};
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+ requirement =
+ GetBroadcastRequirement(true /* standard*/, true /* high */);
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+ capability, requirement, &configuration);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_NE(configuration.numBis, 0);
+ ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+ VerifyBroadcastConfiguration(requirement, configuration);
}
/**
@@ -3186,7 +4426,7 @@
TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
StartAndEndLeAudioBroadcastSessionWithPossibleBroadcastConfig) {
if (!IsBroadcastOffloadSupported()) {
- return;
+ GTEST_SKIP();
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(true /* supported */);
@@ -3225,7 +4465,7 @@
BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
DISABLED_StartAndEndLeAudioBroadcastSessionWithInvalidAudioConfiguration) {
if (!IsBroadcastOffloadSupported()) {
- return;
+ GTEST_SKIP();
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(false /* supported */);
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
index 4c1500a..13e2116 100644
--- a/bluetooth/audio/flags/btaudiohal.aconfig
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -7,3 +7,10 @@
description: "Flag for DSA Over LEA"
bug: "270987427"
}
+
+flag {
+ name: "leaudio_report_broadcast_ac_to_hal"
+ namespace: "pixel_bluetooth"
+ description: "Flag for reporting lea broadcast audio config to HAL"
+ bug: "321168976"
+}
\ No newline at end of file
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 779a90f..1661362 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,6 +90,9 @@
cc_test {
name: "BluetoothLeAudioCodecsProviderTest",
+ defaults: [
+ "latest_android_hardware_bluetooth_audio_ndk_shared",
+ ],
srcs: [
"aidl_session/BluetoothLeAudioCodecsProvider.cpp",
"aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
@@ -100,7 +103,6 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.bluetooth.audio-V4-ndk",
"libxml2",
],
test_suites: [
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 67ba93c..d0f2a26 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -121,18 +121,41 @@
void BluetoothAudioSession::ReportAudioConfigChanged(
const AudioConfiguration& audio_config) {
- if (session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
- session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
- return;
- }
-
std::lock_guard<std::recursive_mutex> guard(mutex_);
- if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
- LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
- << toString(session_type_);
- return;
+ if (com::android::btaudio::hal::flags::leaudio_report_broadcast_ac_to_hal()) {
+ if (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else if (session_type_ ==
+ SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ LOG(ERROR) << __func__ << " invalid SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ if (session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return;
+ }
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
}
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 336d15d..6a45987 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -33,6 +33,7 @@
#include <string.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
#include <fmq/MessageQueue.h>
#include <log/log.h>
#include <sync/sync.h>
@@ -649,7 +650,8 @@
*outLength = static_cast<uint16_t>(val & length_mask);
if (mDataRead + *outLength > mDataSize) {
- ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+ ALOGE("command %s has invalid command length %" PRIu16,
+ toString(*outCommand).c_str(), *outLength);
// undo the read() above
mDataRead--;
return false;