Loading android/app/jni/com_android_bluetooth_vc.cpp +53 −37 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ #include <shared_mutex> #include "com_android_bluetooth.h" #include "./com_android_bluetooth.h" #include "hardware/bt_vc.h" using bluetooth::vc::ConnectionState; Loading @@ -47,7 +47,7 @@ class VolumeControlCallbacksImpl : public VolumeControlCallbacks { public: ~VolumeControlCallbacksImpl() = default; void OnConnectionState(ConnectionState state, const RawAddress& bd_addr) override { log::info("state:{}, addr: {}", int(state), bd_addr.ToRedactedStringForLogging()); log::info("state:{}, addr: {}", static_cast<int>(state), bd_addr.ToRedactedStringForLogging()); std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); Loading @@ -62,7 +62,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint)state, addr.get()); } Loading @@ -84,7 +85,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeStateChanged, (jint)volume, (jboolean)mute, (jint)flags, addr.get(), (jboolean)isAutonomous); } Loading Loading @@ -115,11 +117,12 @@ public: ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); if (!addr.get()) { log::error("Failed to new jbyteArray bd addr for onDeviceAvailable"); log::error("Failed to get addr for {}", bd_addr); return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDeviceAvailable, (jint)num_offsets, addr.get()); } Loading @@ -143,7 +146,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutVolumeOffsetChanged, (jint)ext_output_id, (jint)offset, addr.get()); } Loading @@ -165,7 +169,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutLocationChanged, (jint)ext_output_id, (jint)location, addr.get()); } Loading @@ -189,7 +194,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); jstring description = sCallbackEnv->NewStringUTF(descr.c_str()); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutDescriptionChanged, (jint)ext_output_id, description, addr.get()); Loading Loading @@ -225,7 +231,10 @@ static void initNative(JNIEnv* env, jobject object) { return; } sVolumeControlInterface = (VolumeControlInterface*)btInf->get_profile_interface(BT_PROFILE_VC_ID); sVolumeControlInterface = const_cast<VolumeControlInterface*>(reinterpret_cast<const VolumeControlInterface*>( btInf->get_profile_interface(BT_PROFILE_VC_ID))); if (sVolumeControlInterface == nullptr) { log::error("Failed to get Bluetooth Volume Control Interface"); return; Loading Loading @@ -270,7 +279,7 @@ static jboolean connectVolumeControlNative(JNIEnv* env, jobject /* object */, jb return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Connect(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -292,7 +301,7 @@ static jboolean disconnectVolumeControlNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Disconnect(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -310,7 +319,7 @@ static void setVolumeNative(JNIEnv* env, jobject /* object */, jbyteArray addres return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetVolume(*tmpraw, volume); env->ReleaseByteArrayElements(address, addr, 0); } Loading @@ -337,7 +346,7 @@ static void muteNative(JNIEnv* env, jobject /* object */, jbyteArray address) { return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Mute(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); } Loading @@ -362,7 +371,7 @@ static void unmuteNative(JNIEnv* env, jobject /* object */, jbyteArray address) return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Unmute(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); } Loading Loading @@ -390,7 +399,7 @@ static jboolean getExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject /* object return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutVolumeOffset(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -411,7 +420,7 @@ static jboolean setExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject /* object return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutVolumeOffset(*tmpraw, ext_output_id, offset); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -431,7 +440,7 @@ static jboolean getExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutLocation(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -451,7 +460,7 @@ static jboolean setExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutLocation(*tmpraw, ext_output_id, location); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -471,7 +480,7 @@ static jboolean getExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutDescription(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading Loading @@ -499,7 +508,7 @@ static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * env->ReleaseStringUTFChars(descr, value); } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutDescription(*tmpraw, ext_output_id, description); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -507,23 +516,30 @@ static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * int register_com_android_bluetooth_vc(JNIEnv* env) { const JNINativeMethod methods[] = { {"initNative", "()V", (void*)initNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"connectVolumeControlNative", "([B)Z", (void*)connectVolumeControlNative}, {"disconnectVolumeControlNative", "([B)Z", (void*)disconnectVolumeControlNative}, {"setVolumeNative", "([BI)V", (void*)setVolumeNative}, {"setGroupVolumeNative", "(II)V", (void*)setGroupVolumeNative}, {"muteNative", "([B)V", (void*)muteNative}, {"muteGroupNative", "(I)V", (void*)muteGroupNative}, {"unmuteNative", "([B)V", (void*)unmuteNative}, {"unmuteGroupNative", "(I)V", (void*)unmuteGroupNative}, {"getExtAudioOutVolumeOffsetNative", "([BI)Z", (void*)getExtAudioOutVolumeOffsetNative}, {"setExtAudioOutVolumeOffsetNative", "([BII)Z", (void*)setExtAudioOutVolumeOffsetNative}, {"getExtAudioOutLocationNative", "([BI)Z", (void*)getExtAudioOutLocationNative}, {"setExtAudioOutLocationNative", "([BII)Z", (void*)setExtAudioOutLocationNative}, {"getExtAudioOutDescriptionNative", "([BI)Z", (void*)getExtAudioOutDescriptionNative}, {"initNative", "()V", reinterpret_cast<void*>(initNative)}, {"cleanupNative", "()V", reinterpret_cast<void*>(cleanupNative)}, {"connectVolumeControlNative", "([B)Z", reinterpret_cast<void*>(connectVolumeControlNative)}, {"disconnectVolumeControlNative", "([B)Z", reinterpret_cast<void*>(disconnectVolumeControlNative)}, {"setVolumeNative", "([BI)V", reinterpret_cast<void*>(setVolumeNative)}, {"setGroupVolumeNative", "(II)V", reinterpret_cast<void*>(setGroupVolumeNative)}, {"muteNative", "([B)V", reinterpret_cast<void*>(muteNative)}, {"muteGroupNative", "(I)V", reinterpret_cast<void*>(muteGroupNative)}, {"unmuteNative", "([B)V", reinterpret_cast<void*>(unmuteNative)}, {"unmuteGroupNative", "(I)V", reinterpret_cast<void*>(unmuteGroupNative)}, {"getExtAudioOutVolumeOffsetNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutVolumeOffsetNative)}, {"setExtAudioOutVolumeOffsetNative", "([BII)Z", reinterpret_cast<void*>(setExtAudioOutVolumeOffsetNative)}, {"getExtAudioOutLocationNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutLocationNative)}, {"setExtAudioOutLocationNative", "([BII)Z", reinterpret_cast<void*>(setExtAudioOutLocationNative)}, {"getExtAudioOutDescriptionNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutDescriptionNative)}, {"setExtAudioOutDescriptionNative", "([BILjava/lang/String;)Z", (void*)setExtAudioOutDescriptionNative}, reinterpret_cast<void*>(setExtAudioOutDescriptionNative)}, }; const int result = REGISTER_NATIVE_METHODS( env, "com/android/bluetooth/vc/VolumeControlNativeInterface", methods); Loading system/bta/include/bta_vc_api.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <hardware/bt_vc.h> #include <string> #include "types/raw_address.h" class VolumeControl { Loading system/bta/vc/device.cc +34 −21 Original line number Diff line number Diff line Loading @@ -20,18 +20,18 @@ #include <map> #include <vector> #include "bta_gatt_api.h" #include "bta_gatt_queue.h" #include "devices.h" #include "gatt_api.h" #include "bta/include/bta_gatt_api.h" #include "bta/include/bta_gatt_queue.h" #include "bta/vc/devices.h" #include "internal_include/bt_trace.h" #include "os/log.h" #include "os/logging/log_adapter.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_types.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" using namespace bluetooth::vc::internal; using bluetooth::vc::internal::VolumeControlDevice; void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) { if (volume_state_handle != 0) { Loading Loading @@ -70,7 +70,7 @@ void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) { uint16_t VolumeControlDevice::find_ccc_handle(uint16_t chrc_handle) { const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(connection_id, chrc_handle); if (!p_char) { log::warn("no such handle=0x{:x}", chrc_handle); log::warn("{}, no such handle={:#x}", address, chrc_handle); return 0; } Loading Loading @@ -123,11 +123,15 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: if (chrc.uuid == kVolumeOffsetStateUuid) { offset.state_handle = chrc.value_handle; offset.state_ccc_handle = find_ccc_handle(chrc.value_handle); log::debug("{}, offset_state handle={:#x}, ccc {:#x}", address, offset.state_handle, offset.state_ccc_handle); } else if (chrc.uuid == kVolumeOffsetLocationUuid) { offset.audio_location_handle = chrc.value_handle; offset.audio_location_ccc_handle = find_ccc_handle(chrc.value_handle); offset.audio_location_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR; log::debug("{}, offset_audio_location handle={:#x}, ccc {:#x}", address, offset.audio_location_handle, offset.audio_location_ccc_handle); } else if (chrc.uuid == kVolumeOffsetControlPointUuid) { offset.control_point_handle = chrc.value_handle; Loading @@ -136,6 +140,8 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: offset.audio_descr_handle = chrc.value_handle; offset.audio_descr_ccc_handle = find_ccc_handle(chrc.value_handle); offset.audio_descr_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR; log::debug("{}, offset_audio_des handle={:#x}, ccc {:#x}", address, offset.audio_descr_handle, offset.audio_descr_ccc_handle); } else { log::warn("unknown characteristic={}", chrc.uuid); Loading @@ -150,9 +156,9 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: GATT_HANDLE_IS_VALID(offset.audio_descr_handle) /* audio_descr_ccc_handle is optional */) { audio_offsets.Add(offset); log::info("Offset added id=0x{:x}", offset.id); log::info("{}, offset added id={:#x}", address, offset.id); } else { log::warn("Ignoring offset handle=0x{:x}", service.handle); log::warn("{}, ignoring offset handle={:#x}", address, service.handle); } } Loading @@ -162,13 +168,13 @@ bool VolumeControlDevice::UpdateHandles(void) { bool vcs_found = false; const std::list<gatt::Service>* services = BTA_GATTC_GetServices(connection_id); if (services == nullptr) { log::error("No services found"); log::error("{}, no services found", address); return false; } for (auto const& service : *services) { if (service.uuid == kVolumeControlUuid) { log::info("Found VCS, handle=0x{:x}", service.handle); log::info("{}, found VCS, handle={:#x}", address, service.handle); vcs_found = set_volume_control_service_handles(service); if (!vcs_found) { break; Loading @@ -183,11 +189,11 @@ bool VolumeControlDevice::UpdateHandles(void) { } if (included.uuid == kVolumeOffsetUuid) { log::info("Found VOCS, handle=0x{:x}", service->handle); log::info("{}, found VOCS, handle={:#x}", address, service->handle); set_volume_offset_control_service_handles(*service); } else { log::warn("unknown service={}", service->uuid); log::warn("{}, unknown service={}", address, service->uuid); } } } Loading Loading @@ -228,11 +234,15 @@ void VolumeControlDevice::ControlPointOperation(uint8_t opcode, const std::vecto bool VolumeControlDevice::subscribe_for_notifications(tGATT_IF gatt_if, uint16_t handle, uint16_t ccc_handle, GATT_WRITE_OP_CB cb) { tGATT_STATUS status = BTA_GATTC_RegisterForNotifications(gatt_if, address, handle); log::debug("gatt_if:{}, {} , {:#x} : {:#x}", gatt_if, address, handle, ccc_handle); if (status != GATT_SUCCESS) { log::error("failed, status=0x{:x}", status); log::error("failed for {}, status={:#x}", address, status); return false; } log::debug("{} ok to proceed with writing descriptor {:#x}", address, ccc_handle); std::vector<uint8_t> value(2); uint8_t* ptr = value.data(); UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION); Loading Loading @@ -297,7 +307,6 @@ void VolumeControlDevice::EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_O if (GATT_HANDLE_IS_VALID(handles.second)) { subscribe_for_notifications(gatt_if, handles.first, handles.second, cccd_write_cb); } BtaGattQueue::ReadCharacteristic(connection_id, handles.first, chrc_read_cb, nullptr); } } Loading @@ -305,6 +314,9 @@ void VolumeControlDevice::EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_O bool VolumeControlDevice::VerifyReady(uint16_t handle) { handles_pending.erase(handle); device_ready = handles_pending.size() == 0; log::debug("{}, handles_pending size={}", address, handles_pending.size()); return device_ready; } Loading @@ -312,7 +324,7 @@ void VolumeControlDevice::GetExtAudioOutVolumeOffset(uint8_t ext_output_id, GATT void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -323,7 +335,7 @@ void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id, GATT_REA void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -333,7 +345,7 @@ void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id, GATT_REA void VolumeControlDevice::SetExtAudioOutLocation(uint8_t ext_output_id, uint32_t location) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -353,17 +365,18 @@ void VolumeControlDevice::GetExtAudioOutDescription(uint8_t ext_output_id, GATT_ void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_descr_handle, cb, cb_data); } void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id, std::string& descr) { void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id, const std::string& descr) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -382,7 +395,7 @@ void VolumeControlDevice::ExtAudioOutControlPointOperation(uint8_t ext_output_id GATT_WRITE_OP_CB cb, void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading system/bta/vc/devices.h +3 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <algorithm> #include <cstdint> #include <string> #include <unordered_set> #include <vector> Loading Loading @@ -79,9 +80,6 @@ public: ~VolumeControlDevice() = default; // TODO: remove inline std::string ToString() { return address.ToString(); } std::string ToStringForLogging() const override { return address.ToStringForLogging(); } std::string ToRedactedStringForLogging() const override { Loading Loading @@ -127,7 +125,7 @@ public: void SetExtAudioOutLocation(uint8_t ext_output_id, uint32_t location); void GetExtAudioOutLocation(uint8_t ext_output_id, GATT_READ_OP_CB cb, void* cb_data); void GetExtAudioOutDescription(uint8_t ext_output_id, GATT_READ_OP_CB cb, void* cb_data); void SetExtAudioOutDescription(uint8_t ext_output_id, std::string& descr); void SetExtAudioOutDescription(uint8_t ext_output_id, const std::string& descr); void ExtAudioOutControlPointOperation(uint8_t ext_output_id, uint8_t opcode, const std::vector<uint8_t>* arg, GATT_WRITE_OP_CB cb, void* cb_data); Loading Loading @@ -215,7 +213,7 @@ public: } } void ControlPointOperation(std::vector<RawAddress>& devices, uint8_t opcode, void ControlPointOperation(const std::vector<RawAddress>& devices, uint8_t opcode, const std::vector<uint8_t>* arg, GATT_WRITE_OP_CB cb, void* cb_data) { for (auto& addr : devices) { VolumeControlDevice* device = FindByAddress(addr); Loading system/bta/vc/devices_test.cc +5 −4 Original line number Diff line number Diff line Loading @@ -15,16 +15,17 @@ * limitations under the License. */ #include "devices.h" #include "bta/vc/devices.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <list> #include <map> #include "bta_gatt_api_mock.h" #include "bta_gatt_queue_mock.h" #include "btm_api_mock.h" #include "bta/test/common/bta_gatt_api_mock.h" #include "bta/test/common/bta_gatt_queue_mock.h" #include "bta/test/common/btm_api_mock.h" #include "gatt/database_builder.h" #include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" Loading Loading
android/app/jni/com_android_bluetooth_vc.cpp +53 −37 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ #include <shared_mutex> #include "com_android_bluetooth.h" #include "./com_android_bluetooth.h" #include "hardware/bt_vc.h" using bluetooth::vc::ConnectionState; Loading @@ -47,7 +47,7 @@ class VolumeControlCallbacksImpl : public VolumeControlCallbacks { public: ~VolumeControlCallbacksImpl() = default; void OnConnectionState(ConnectionState state, const RawAddress& bd_addr) override { log::info("state:{}, addr: {}", int(state), bd_addr.ToRedactedStringForLogging()); log::info("state:{}, addr: {}", static_cast<int>(state), bd_addr.ToRedactedStringForLogging()); std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); Loading @@ -62,7 +62,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint)state, addr.get()); } Loading @@ -84,7 +85,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeStateChanged, (jint)volume, (jboolean)mute, (jint)flags, addr.get(), (jboolean)isAutonomous); } Loading Loading @@ -115,11 +117,12 @@ public: ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); if (!addr.get()) { log::error("Failed to new jbyteArray bd addr for onDeviceAvailable"); log::error("Failed to get addr for {}", bd_addr); return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDeviceAvailable, (jint)num_offsets, addr.get()); } Loading @@ -143,7 +146,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutVolumeOffsetChanged, (jint)ext_output_id, (jint)offset, addr.get()); } Loading @@ -165,7 +169,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutLocationChanged, (jint)ext_output_id, (jint)location, addr.get()); } Loading @@ -189,7 +194,8 @@ public: return; } sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr); sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), reinterpret_cast<const jbyte*>(&bd_addr)); jstring description = sCallbackEnv->NewStringUTF(descr.c_str()); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExtAudioOutDescriptionChanged, (jint)ext_output_id, description, addr.get()); Loading Loading @@ -225,7 +231,10 @@ static void initNative(JNIEnv* env, jobject object) { return; } sVolumeControlInterface = (VolumeControlInterface*)btInf->get_profile_interface(BT_PROFILE_VC_ID); sVolumeControlInterface = const_cast<VolumeControlInterface*>(reinterpret_cast<const VolumeControlInterface*>( btInf->get_profile_interface(BT_PROFILE_VC_ID))); if (sVolumeControlInterface == nullptr) { log::error("Failed to get Bluetooth Volume Control Interface"); return; Loading Loading @@ -270,7 +279,7 @@ static jboolean connectVolumeControlNative(JNIEnv* env, jobject /* object */, jb return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Connect(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -292,7 +301,7 @@ static jboolean disconnectVolumeControlNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Disconnect(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -310,7 +319,7 @@ static void setVolumeNative(JNIEnv* env, jobject /* object */, jbyteArray addres return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetVolume(*tmpraw, volume); env->ReleaseByteArrayElements(address, addr, 0); } Loading @@ -337,7 +346,7 @@ static void muteNative(JNIEnv* env, jobject /* object */, jbyteArray address) { return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Mute(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); } Loading @@ -362,7 +371,7 @@ static void unmuteNative(JNIEnv* env, jobject /* object */, jbyteArray address) return; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->Unmute(*tmpraw); env->ReleaseByteArrayElements(address, addr, 0); } Loading Loading @@ -390,7 +399,7 @@ static jboolean getExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject /* object return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutVolumeOffset(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -411,7 +420,7 @@ static jboolean setExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject /* object return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutVolumeOffset(*tmpraw, ext_output_id, offset); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -431,7 +440,7 @@ static jboolean getExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutLocation(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -451,7 +460,7 @@ static jboolean setExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutLocation(*tmpraw, ext_output_id, location); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -471,7 +480,7 @@ static jboolean getExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * return JNI_FALSE; } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->GetExtAudioOutDescription(*tmpraw, ext_output_id); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading Loading @@ -499,7 +508,7 @@ static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * env->ReleaseStringUTFChars(descr, value); } RawAddress* tmpraw = (RawAddress*)addr; RawAddress* tmpraw = reinterpret_cast<RawAddress*>(addr); sVolumeControlInterface->SetExtAudioOutDescription(*tmpraw, ext_output_id, description); env->ReleaseByteArrayElements(address, addr, 0); return JNI_TRUE; Loading @@ -507,23 +516,30 @@ static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject /* object * int register_com_android_bluetooth_vc(JNIEnv* env) { const JNINativeMethod methods[] = { {"initNative", "()V", (void*)initNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"connectVolumeControlNative", "([B)Z", (void*)connectVolumeControlNative}, {"disconnectVolumeControlNative", "([B)Z", (void*)disconnectVolumeControlNative}, {"setVolumeNative", "([BI)V", (void*)setVolumeNative}, {"setGroupVolumeNative", "(II)V", (void*)setGroupVolumeNative}, {"muteNative", "([B)V", (void*)muteNative}, {"muteGroupNative", "(I)V", (void*)muteGroupNative}, {"unmuteNative", "([B)V", (void*)unmuteNative}, {"unmuteGroupNative", "(I)V", (void*)unmuteGroupNative}, {"getExtAudioOutVolumeOffsetNative", "([BI)Z", (void*)getExtAudioOutVolumeOffsetNative}, {"setExtAudioOutVolumeOffsetNative", "([BII)Z", (void*)setExtAudioOutVolumeOffsetNative}, {"getExtAudioOutLocationNative", "([BI)Z", (void*)getExtAudioOutLocationNative}, {"setExtAudioOutLocationNative", "([BII)Z", (void*)setExtAudioOutLocationNative}, {"getExtAudioOutDescriptionNative", "([BI)Z", (void*)getExtAudioOutDescriptionNative}, {"initNative", "()V", reinterpret_cast<void*>(initNative)}, {"cleanupNative", "()V", reinterpret_cast<void*>(cleanupNative)}, {"connectVolumeControlNative", "([B)Z", reinterpret_cast<void*>(connectVolumeControlNative)}, {"disconnectVolumeControlNative", "([B)Z", reinterpret_cast<void*>(disconnectVolumeControlNative)}, {"setVolumeNative", "([BI)V", reinterpret_cast<void*>(setVolumeNative)}, {"setGroupVolumeNative", "(II)V", reinterpret_cast<void*>(setGroupVolumeNative)}, {"muteNative", "([B)V", reinterpret_cast<void*>(muteNative)}, {"muteGroupNative", "(I)V", reinterpret_cast<void*>(muteGroupNative)}, {"unmuteNative", "([B)V", reinterpret_cast<void*>(unmuteNative)}, {"unmuteGroupNative", "(I)V", reinterpret_cast<void*>(unmuteGroupNative)}, {"getExtAudioOutVolumeOffsetNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutVolumeOffsetNative)}, {"setExtAudioOutVolumeOffsetNative", "([BII)Z", reinterpret_cast<void*>(setExtAudioOutVolumeOffsetNative)}, {"getExtAudioOutLocationNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutLocationNative)}, {"setExtAudioOutLocationNative", "([BII)Z", reinterpret_cast<void*>(setExtAudioOutLocationNative)}, {"getExtAudioOutDescriptionNative", "([BI)Z", reinterpret_cast<void*>(getExtAudioOutDescriptionNative)}, {"setExtAudioOutDescriptionNative", "([BILjava/lang/String;)Z", (void*)setExtAudioOutDescriptionNative}, reinterpret_cast<void*>(setExtAudioOutDescriptionNative)}, }; const int result = REGISTER_NATIVE_METHODS( env, "com/android/bluetooth/vc/VolumeControlNativeInterface", methods); Loading
system/bta/include/bta_vc_api.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <hardware/bt_vc.h> #include <string> #include "types/raw_address.h" class VolumeControl { Loading
system/bta/vc/device.cc +34 −21 Original line number Diff line number Diff line Loading @@ -20,18 +20,18 @@ #include <map> #include <vector> #include "bta_gatt_api.h" #include "bta_gatt_queue.h" #include "devices.h" #include "gatt_api.h" #include "bta/include/bta_gatt_api.h" #include "bta/include/bta_gatt_queue.h" #include "bta/vc/devices.h" #include "internal_include/bt_trace.h" #include "os/log.h" #include "os/logging/log_adapter.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_types.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" using namespace bluetooth::vc::internal; using bluetooth::vc::internal::VolumeControlDevice; void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) { if (volume_state_handle != 0) { Loading Loading @@ -70,7 +70,7 @@ void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) { uint16_t VolumeControlDevice::find_ccc_handle(uint16_t chrc_handle) { const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(connection_id, chrc_handle); if (!p_char) { log::warn("no such handle=0x{:x}", chrc_handle); log::warn("{}, no such handle={:#x}", address, chrc_handle); return 0; } Loading Loading @@ -123,11 +123,15 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: if (chrc.uuid == kVolumeOffsetStateUuid) { offset.state_handle = chrc.value_handle; offset.state_ccc_handle = find_ccc_handle(chrc.value_handle); log::debug("{}, offset_state handle={:#x}, ccc {:#x}", address, offset.state_handle, offset.state_ccc_handle); } else if (chrc.uuid == kVolumeOffsetLocationUuid) { offset.audio_location_handle = chrc.value_handle; offset.audio_location_ccc_handle = find_ccc_handle(chrc.value_handle); offset.audio_location_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR; log::debug("{}, offset_audio_location handle={:#x}, ccc {:#x}", address, offset.audio_location_handle, offset.audio_location_ccc_handle); } else if (chrc.uuid == kVolumeOffsetControlPointUuid) { offset.control_point_handle = chrc.value_handle; Loading @@ -136,6 +140,8 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: offset.audio_descr_handle = chrc.value_handle; offset.audio_descr_ccc_handle = find_ccc_handle(chrc.value_handle); offset.audio_descr_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR; log::debug("{}, offset_audio_des handle={:#x}, ccc {:#x}", address, offset.audio_descr_handle, offset.audio_descr_ccc_handle); } else { log::warn("unknown characteristic={}", chrc.uuid); Loading @@ -150,9 +156,9 @@ void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt:: GATT_HANDLE_IS_VALID(offset.audio_descr_handle) /* audio_descr_ccc_handle is optional */) { audio_offsets.Add(offset); log::info("Offset added id=0x{:x}", offset.id); log::info("{}, offset added id={:#x}", address, offset.id); } else { log::warn("Ignoring offset handle=0x{:x}", service.handle); log::warn("{}, ignoring offset handle={:#x}", address, service.handle); } } Loading @@ -162,13 +168,13 @@ bool VolumeControlDevice::UpdateHandles(void) { bool vcs_found = false; const std::list<gatt::Service>* services = BTA_GATTC_GetServices(connection_id); if (services == nullptr) { log::error("No services found"); log::error("{}, no services found", address); return false; } for (auto const& service : *services) { if (service.uuid == kVolumeControlUuid) { log::info("Found VCS, handle=0x{:x}", service.handle); log::info("{}, found VCS, handle={:#x}", address, service.handle); vcs_found = set_volume_control_service_handles(service); if (!vcs_found) { break; Loading @@ -183,11 +189,11 @@ bool VolumeControlDevice::UpdateHandles(void) { } if (included.uuid == kVolumeOffsetUuid) { log::info("Found VOCS, handle=0x{:x}", service->handle); log::info("{}, found VOCS, handle={:#x}", address, service->handle); set_volume_offset_control_service_handles(*service); } else { log::warn("unknown service={}", service->uuid); log::warn("{}, unknown service={}", address, service->uuid); } } } Loading Loading @@ -228,11 +234,15 @@ void VolumeControlDevice::ControlPointOperation(uint8_t opcode, const std::vecto bool VolumeControlDevice::subscribe_for_notifications(tGATT_IF gatt_if, uint16_t handle, uint16_t ccc_handle, GATT_WRITE_OP_CB cb) { tGATT_STATUS status = BTA_GATTC_RegisterForNotifications(gatt_if, address, handle); log::debug("gatt_if:{}, {} , {:#x} : {:#x}", gatt_if, address, handle, ccc_handle); if (status != GATT_SUCCESS) { log::error("failed, status=0x{:x}", status); log::error("failed for {}, status={:#x}", address, status); return false; } log::debug("{} ok to proceed with writing descriptor {:#x}", address, ccc_handle); std::vector<uint8_t> value(2); uint8_t* ptr = value.data(); UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION); Loading Loading @@ -297,7 +307,6 @@ void VolumeControlDevice::EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_O if (GATT_HANDLE_IS_VALID(handles.second)) { subscribe_for_notifications(gatt_if, handles.first, handles.second, cccd_write_cb); } BtaGattQueue::ReadCharacteristic(connection_id, handles.first, chrc_read_cb, nullptr); } } Loading @@ -305,6 +314,9 @@ void VolumeControlDevice::EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_O bool VolumeControlDevice::VerifyReady(uint16_t handle) { handles_pending.erase(handle); device_ready = handles_pending.size() == 0; log::debug("{}, handles_pending size={}", address, handles_pending.size()); return device_ready; } Loading @@ -312,7 +324,7 @@ void VolumeControlDevice::GetExtAudioOutVolumeOffset(uint8_t ext_output_id, GATT void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -323,7 +335,7 @@ void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id, GATT_REA void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -333,7 +345,7 @@ void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id, GATT_REA void VolumeControlDevice::SetExtAudioOutLocation(uint8_t ext_output_id, uint32_t location) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -353,17 +365,18 @@ void VolumeControlDevice::GetExtAudioOutDescription(uint8_t ext_output_id, GATT_ void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_descr_handle, cb, cb_data); } void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id, std::string& descr) { void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id, const std::string& descr) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading @@ -382,7 +395,7 @@ void VolumeControlDevice::ExtAudioOutControlPointOperation(uint8_t ext_output_id GATT_WRITE_OP_CB cb, void* cb_data) { VolumeOffset* offset = audio_offsets.FindById(ext_output_id); if (!offset) { log::error("no such offset!"); log::error("{}, no such offset={:#x}!", address, ext_output_id); return; } Loading
system/bta/vc/devices.h +3 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <algorithm> #include <cstdint> #include <string> #include <unordered_set> #include <vector> Loading Loading @@ -79,9 +80,6 @@ public: ~VolumeControlDevice() = default; // TODO: remove inline std::string ToString() { return address.ToString(); } std::string ToStringForLogging() const override { return address.ToStringForLogging(); } std::string ToRedactedStringForLogging() const override { Loading Loading @@ -127,7 +125,7 @@ public: void SetExtAudioOutLocation(uint8_t ext_output_id, uint32_t location); void GetExtAudioOutLocation(uint8_t ext_output_id, GATT_READ_OP_CB cb, void* cb_data); void GetExtAudioOutDescription(uint8_t ext_output_id, GATT_READ_OP_CB cb, void* cb_data); void SetExtAudioOutDescription(uint8_t ext_output_id, std::string& descr); void SetExtAudioOutDescription(uint8_t ext_output_id, const std::string& descr); void ExtAudioOutControlPointOperation(uint8_t ext_output_id, uint8_t opcode, const std::vector<uint8_t>* arg, GATT_WRITE_OP_CB cb, void* cb_data); Loading Loading @@ -215,7 +213,7 @@ public: } } void ControlPointOperation(std::vector<RawAddress>& devices, uint8_t opcode, void ControlPointOperation(const std::vector<RawAddress>& devices, uint8_t opcode, const std::vector<uint8_t>* arg, GATT_WRITE_OP_CB cb, void* cb_data) { for (auto& addr : devices) { VolumeControlDevice* device = FindByAddress(addr); Loading
system/bta/vc/devices_test.cc +5 −4 Original line number Diff line number Diff line Loading @@ -15,16 +15,17 @@ * limitations under the License. */ #include "devices.h" #include "bta/vc/devices.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <list> #include <map> #include "bta_gatt_api_mock.h" #include "bta_gatt_queue_mock.h" #include "btm_api_mock.h" #include "bta/test/common/bta_gatt_api_mock.h" #include "bta/test/common/bta_gatt_queue_mock.h" #include "bta/test/common/btm_api_mock.h" #include "gatt/database_builder.h" #include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" Loading