| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h" |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/containers/queue.h" |
| #include "base/logging.h" |
| #include "base/memory/weak_ptr.h" |
| #include "chromecast/device/bluetooth/le/remote_characteristic.h" |
| #include "chromecast/device/bluetooth/le/remote_descriptor.h" |
| #include "chromecast/public/bluetooth/gatt.h" |
| #include "device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.h" |
| #include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h" |
| #include "device/bluetooth/cast/bluetooth_utils.h" |
| #include "device/bluetooth/public/cpp/bluetooth_uuid.h" |
| |
| namespace device { |
| namespace { |
| |
| BluetoothGattCharacteristic::Permissions ConvertPermissions( |
| chromecast::bluetooth_v2_shlib::Gatt::Permissions input) { |
| BluetoothGattCharacteristic::Permissions output = |
| BluetoothGattCharacteristic::PERMISSION_NONE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_READ) |
| output |= BluetoothGattCharacteristic::PERMISSION_READ; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_READ_ENCRYPTED) |
| output |= BluetoothGattCharacteristic::PERMISSION_READ_ENCRYPTED; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_WRITE) |
| output |= BluetoothGattCharacteristic::PERMISSION_WRITE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_WRITE_ENCRYPTED) |
| output |= BluetoothGattCharacteristic::PERMISSION_WRITE_ENCRYPTED; |
| |
| // NOTE(slan): Determine the proper mapping for these. |
| // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_READ_ENCRYPTED_MITM) |
| // output |= BluetoothGattCharacteristic::PERMISSION_READ_ENCRYPTED_MITM; |
| // if (input & |
| // chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_ENCRYPTED_MITM) |
| // output |= BluetoothGattCharacteristic::PERMISSION_WRITE_ENCRYPTED_MITM; |
| // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_SIGNED) |
| // output |= BluetoothGattCharacteristic::PERMISSION_WRITE_SIGNED; |
| // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_SIGNED_MITM) |
| // output |= BluetoothGattCharacteristic::PERMISSION_WRITE_SIGNED_MITM; |
| |
| return output; |
| } |
| |
| BluetoothGattCharacteristic::Properties ConvertProperties( |
| chromecast::bluetooth_v2_shlib::Gatt::Properties input) { |
| BluetoothGattCharacteristic::Properties output = |
| BluetoothGattCharacteristic::PROPERTY_NONE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_BROADCAST) |
| output |= BluetoothGattCharacteristic::PROPERTY_BROADCAST; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_READ) |
| output |= BluetoothGattCharacteristic::PROPERTY_READ; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_WRITE_NO_RESPONSE) |
| output |= BluetoothGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_WRITE) |
| output |= BluetoothGattCharacteristic::PROPERTY_WRITE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_NOTIFY) |
| output |= BluetoothGattCharacteristic::PROPERTY_NOTIFY; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE) |
| output |= BluetoothGattCharacteristic::PROPERTY_INDICATE; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_SIGNED_WRITE) |
| output |= BluetoothGattCharacteristic::PROPERTY_AUTHENTICATED_SIGNED_WRITES; |
| if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_EXTENDED_PROPS) |
| output |= BluetoothGattCharacteristic::PROPERTY_EXTENDED_PROPERTIES; |
| |
| return output; |
| } |
| |
| // Called back when subscribing or unsubscribing to a remote characteristic. |
| // If |success| is true, run |callback|. Otherwise run |error_callback|. |
| void OnSubscribeOrUnsubscribe( |
| base::OnceClosure callback, |
| BluetoothGattCharacteristic::ErrorCallback error_callback, |
| bool success) { |
| if (success) |
| std::move(callback).Run(); |
| else |
| std::move(error_callback).Run(BluetoothGattService::GATT_ERROR_FAILED); |
| } |
| |
| } // namespace |
| |
| BluetoothRemoteGattCharacteristicCast::BluetoothRemoteGattCharacteristicCast( |
| BluetoothRemoteGattServiceCast* service, |
| scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic) |
| : service_(service), |
| remote_characteristic_(std::move(characteristic)), |
| weak_factory_(this) { |
| auto descriptors = remote_characteristic_->GetDescriptors(); |
| descriptors_.reserve(descriptors.size()); |
| for (const auto& descriptor : descriptors) { |
| AddDescriptor( |
| std::make_unique<BluetoothRemoteGattDescriptorCast>(this, descriptor)); |
| } |
| } |
| |
| BluetoothRemoteGattCharacteristicCast:: |
| ~BluetoothRemoteGattCharacteristicCast() {} |
| |
| std::string BluetoothRemoteGattCharacteristicCast::GetIdentifier() const { |
| return GetUUID().canonical_value(); |
| } |
| |
| BluetoothUUID BluetoothRemoteGattCharacteristicCast::GetUUID() const { |
| return UuidToBluetoothUUID(remote_characteristic_->uuid()); |
| } |
| |
| BluetoothGattCharacteristic::Properties |
| BluetoothRemoteGattCharacteristicCast::GetProperties() const { |
| return ConvertProperties(remote_characteristic_->properties()); |
| } |
| |
| BluetoothGattCharacteristic::Permissions |
| BluetoothRemoteGattCharacteristicCast::GetPermissions() const { |
| return ConvertPermissions(remote_characteristic_->permissions()); |
| } |
| |
| const std::vector<uint8_t>& BluetoothRemoteGattCharacteristicCast::GetValue() |
| const { |
| return value_; |
| } |
| |
| BluetoothRemoteGattService* BluetoothRemoteGattCharacteristicCast::GetService() |
| const { |
| return service_; |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::ReadRemoteCharacteristic( |
| ValueCallback callback) { |
| remote_characteristic_->Read(base::BindOnce( |
| &BluetoothRemoteGattCharacteristicCast::OnReadRemoteCharacteristic, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::WriteRemoteCharacteristic( |
| const std::vector<uint8_t>& value, |
| WriteType write_type, |
| base::OnceClosure callback, |
| ErrorCallback error_callback) { |
| using ChromecastWriteType = chromecast::bluetooth_v2_shlib::Gatt::WriteType; |
| |
| ChromecastWriteType chromecast_write_type; |
| switch (write_type) { |
| case WriteType::kWithResponse: |
| chromecast_write_type = ChromecastWriteType::WRITE_TYPE_DEFAULT; |
| break; |
| case WriteType::kWithoutResponse: |
| chromecast_write_type = ChromecastWriteType::WRITE_TYPE_NO_RESPONSE; |
| break; |
| } |
| |
| remote_characteristic_->WriteAuth( |
| chromecast::bluetooth_v2_shlib::Gatt::Client::AUTH_REQ_NONE, |
| chromecast_write_type, value, |
| base::BindOnce( |
| &BluetoothRemoteGattCharacteristicCast::OnWriteRemoteCharacteristic, |
| weak_factory_.GetWeakPtr(), value, std::move(callback), |
| std::move(error_callback))); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::DeprecatedWriteRemoteCharacteristic( |
| const std::vector<uint8_t>& value, |
| base::OnceClosure callback, |
| ErrorCallback error_callback) { |
| remote_characteristic_->Write( |
| value, |
| base::BindOnce( |
| &BluetoothRemoteGattCharacteristicCast::OnWriteRemoteCharacteristic, |
| weak_factory_.GetWeakPtr(), value, std::move(callback), |
| std::move(error_callback))); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::SubscribeToNotifications( |
| [[maybe_unused]] BluetoothRemoteGattDescriptor* ccc_descriptor, |
| base::OnceClosure callback, |
| ErrorCallback error_callback) { |
| DVLOG(2) << __func__ << " " << GetIdentifier(); |
| |
| // |remote_characteristic_| exposes a method which writes the CCCD after |
| // subscribing the GATT client to the notification. This is syntactically |
| // nicer and saves us a thread-hop, so we ignore |ccc_descriptor|. |
| |
| remote_characteristic_->SetRegisterNotification( |
| true, base::BindOnce(&OnSubscribeOrUnsubscribe, std::move(callback), |
| std::move(error_callback))); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::UnsubscribeFromNotifications( |
| [[maybe_unused]] BluetoothRemoteGattDescriptor* ccc_descriptor, |
| base::OnceClosure callback, |
| ErrorCallback error_callback) { |
| DVLOG(2) << __func__ << " " << GetIdentifier(); |
| |
| // |remote_characteristic_| exposes a method which writes the CCCD after |
| // unsubscribing the GATT client from the notification. This is syntactically |
| // nicer and saves us a thread-hop, so we ignore |ccc_descriptor|. |
| |
| remote_characteristic_->SetRegisterNotification( |
| false, base::BindOnce(&OnSubscribeOrUnsubscribe, std::move(callback), |
| std::move(error_callback))); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::OnReadRemoteCharacteristic( |
| ValueCallback callback, |
| bool success, |
| const std::vector<uint8_t>& result) { |
| if (success) { |
| value_ = result; |
| std::move(callback).Run(/*error_code=*/absl::nullopt, result); |
| return; |
| } |
| std::move(callback).Run(BluetoothGattService::GATT_ERROR_FAILED, |
| /*value=*/std::vector<uint8_t>()); |
| } |
| |
| void BluetoothRemoteGattCharacteristicCast::OnWriteRemoteCharacteristic( |
| const std::vector<uint8_t>& written_value, |
| base::OnceClosure callback, |
| ErrorCallback error_callback, |
| bool success) { |
| if (success) { |
| value_ = written_value; |
| std::move(callback).Run(); |
| return; |
| } |
| std::move(error_callback).Run(BluetoothGattService::GATT_ERROR_FAILED); |
| } |
| |
| } // namespace device |