2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "bluetooth/bluetooth_le_adapter.h"
19 #include "common/logger.h"
20 #include "common/tools.h"
22 #include "bluetooth/bluetooth_instance.h"
23 #include "bluetooth/bluetooth_le_device.h"
24 #include "bluetooth/bluetooth_privilege.h"
25 #include "bluetooth/bluetooth_util.h"
26 using common::optional;
33 const std::string kData = "data";
34 const std::string kUuid = "uuid";
35 const std::string kUuids = "uuids";
36 const std::string kSolicitationUuids = "solicitationuuids";
37 const std::string kServiceData = "serviceData";
39 class ParsedDataHolder {
41 ParsedDataHolder() : valid_(false) {
44 virtual ~ParsedDataHolder() {
63 HexData() : length_(0) {
66 void Parse(const std::string& d) {
68 const char* p_data = d.c_str();
69 int size = d.length();
70 if (size > 2 && (d.find("0x", 0) == 0 || d.find("0X", 0) == 0)) {
75 pointer_.reset(new char[length_]);
76 common::tools::HexToBin(p_data, size, (unsigned char*)pointer(), length_);
79 const char* pointer() const {
80 return pointer_.get();
88 std::unique_ptr<char[]> pointer_;
92 class BluetoothLEServiceData : public ParsedDataHolder {
94 const UUID& uuid() const {
98 const HexData& data() const {
102 static optional<BluetoothLEServiceData> Construct(const picojson::value& service_data_obj) {
105 const auto& data = service_data_obj.get(kData);
106 const auto& uuid_str = service_data_obj.get(kUuid);
107 if (!data.is<std::string>() || !uuid_str.is<std::string>()) {
108 LoggerE("Invalid data type in service data");
112 auto uuid = UUID::create(uuid_str.get<std::string>());
117 return BluetoothLEServiceData{std::move(*uuid), data.get<std::string>()};
121 BluetoothLEServiceData(UUID&& uuid, const std::string& data_str) : uuid_{std::move(uuid)} {
122 ScopeLogger("UUID: %s, data_str: %s", uuid_.uuid_128_bit.c_str(), data_str.c_str());
124 data_.Parse(data_str);
133 class BluetoothLEManufacturerData : public ParsedDataHolder {
135 const std::string& id() const {
139 const HexData& data() const {
143 static bool Construct(const picojson::value& obj, BluetoothLEManufacturerData* out) {
145 if (!obj.is<picojson::object>() || !ParseId(obj, out) || !ParseData(obj, out)) {
155 static bool ParseId(const picojson::value& obj, BluetoothLEManufacturerData* out) {
157 const auto& id = obj.get("id");
158 if (id.is<std::string>()) {
159 out->id_ = id.get<std::string>();
167 static bool ParseData(const picojson::value& obj, BluetoothLEManufacturerData* out) {
170 const auto& val_data = obj.get("data");
172 if (val_data.is<std::string>()) {
173 out->data_.Parse(val_data.get<std::string>());
184 class BluetoothLEAdvertiseData : public ParsedDataHolder {
186 BluetoothLEAdvertiseData()
187 : ParsedDataHolder(),
188 include_name_(false),
189 appearance_(0), // 0 means unknown
190 include_tx_power_level_(false) {
194 bool include_name() const {
195 return include_name_;
198 const std::vector<UUID>& service_uuids() const {
199 return service_uuids_;
202 const std::vector<UUID>& solicitation_uuids() const {
203 return solicitation_uuids_;
206 int appearance() const {
210 bool include_tx_power_level() const {
211 return include_tx_power_level_;
214 const std::vector<BluetoothLEServiceData>& service_data() const {
215 return service_data_;
218 const BluetoothLEManufacturerData& manufacturer_data() const {
219 return manufacturer_data_;
222 static bool Construct(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
224 if (!obj.is<picojson::object>() || !ParseIncludeName(obj, out) ||
225 !ParseServiceUUIDs(obj, out) || !ParseSolicitationUUIDs(obj, out) ||
226 !ParseAppearance(obj, out) || !ParseIncludeTxPowerLevel(obj, out) ||
227 !ParseServiceData(obj, out) || !ParseManufacturerData(obj, out)) {
237 static bool ParseIncludeName(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
239 const auto& include_name = obj.get("includeName");
240 if (include_name.is<bool>()) {
241 out->include_name_ = include_name.get<bool>();
242 } else if (!include_name.is<picojson::null>()) {
249 static bool ParseServiceUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
251 const auto& service_uuids = obj.get(kUuids);
252 if (service_uuids.is<picojson::array>()) {
253 for (const auto& uuid : service_uuids.get<picojson::array>()) {
254 if (!uuid.is<std::string>()) {
255 LoggerE("uuid is not a string");
259 auto uuid_obj = UUID::create(uuid.get<std::string>());
261 out->service_uuids_.push_back(*uuid_obj);
266 } else if (!service_uuids.is<picojson::null>()) {
267 LoggerE("Invalid service_uuids type");
274 static bool ParseSolicitationUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
276 const auto& solicitation_uuids = obj.get(kSolicitationUuids);
277 if (solicitation_uuids.is<picojson::array>()) {
278 for (const auto& uuid : solicitation_uuids.get<picojson::array>()) {
279 if (!uuid.is<std::string>()) {
280 LoggerE("uuid is not a string");
284 auto uuid_obj = UUID::create(uuid.get<std::string>());
286 out->solicitation_uuids_.push_back(*uuid_obj);
291 } else if (!solicitation_uuids.is<picojson::null>()) {
298 static bool ParseAppearance(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
300 const auto& appearance = obj.get("appearance");
301 if (appearance.is<double>()) {
302 out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
303 } else if (!appearance.is<picojson::null>()) {
310 static bool ParseIncludeTxPowerLevel(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
312 const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
313 if (include_tx_power_level.is<bool>()) {
314 out->include_tx_power_level_ = include_tx_power_level.get<bool>();
315 } else if (!include_tx_power_level.is<picojson::null>()) {
322 static bool ParseServiceData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
325 const auto& service_data_obj = obj.get(kServiceData);
326 if (service_data_obj.is<picojson::null>()) {
328 } else if (!service_data_obj.is<picojson::object>()) {
333 * Currently, only advertising of a single service data object is supported
334 * by the Web API. In the future, support for advertising arrays of those
337 * TODO: if supported, parse here the whole array of service data instances.
339 auto service_data = BluetoothLEServiceData::Construct(service_data_obj);
344 out->service_data_.emplace_back(std::move(*service_data));
348 static bool ParseManufacturerData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
350 const auto& manufacturer_data = obj.get("manufacturerData");
351 BluetoothLEManufacturerData data;
352 if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
353 out->manufacturer_data_ = std::move(data);
354 } else if (!manufacturer_data.is<picojson::null>()) {
362 std::vector<UUID> service_uuids_;
363 std::vector<UUID> solicitation_uuids_;
365 bool include_tx_power_level_;
366 std::vector<BluetoothLEServiceData> service_data_;
367 BluetoothLEManufacturerData manufacturer_data_;
372 bool ToBool(bt_adapter_le_state_e state) {
373 return (BT_ADAPTER_LE_ENABLED == state) ? true : false;
377 const std::string kAction = "action";
379 const std::string kOnScanSuccess = "onsuccess";
380 const std::string kOnScanError = "onerror";
381 const std::string kScanEvent = "BluetoothLEScanCallback";
383 const std::string kOnAdvertiseState = "onstate";
384 const std::string kOnAdvertiseError = "onerror";
385 const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
389 using common::ErrorCode;
390 using common::PlatformResult;
391 using common::tools::ReportError;
392 using common::tools::ReportSuccess;
394 BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
395 : instance_(instance), enabled_(false), scanning_(false), bt_advertiser_(nullptr) {
398 bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
400 int ret = bt_adapter_le_get_state(&le_state);
402 if (BT_ERROR_NONE == ret) {
403 enabled_ = ToBool(le_state);
405 ret = bt_adapter_le_set_state_changed_cb(OnStateChanged, this);
406 if (BT_ERROR_NONE != ret) {
407 LoggerE("Failed to register BTLE state changed listener.");
410 LoggerE("Failed to obtain current state of BTLE.");
414 BluetoothLEAdapter::~BluetoothLEAdapter() {
416 bt_adapter_le_unset_state_changed_cb();
418 bt_adapter_le_stop_scan();
420 if (bt_advertiser_) {
421 bt_adapter_le_stop_advertising(bt_advertiser_);
422 bt_adapter_le_destroy_advertiser(bt_advertiser_);
426 void BluetoothLEAdapter::StartScan(const picojson::value& data, picojson::object& out) {
428 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
431 int ret = bt_adapter_le_start_scan(OnScanResult, this);
433 if (BT_ERROR_NONE != ret) {
434 if (BT_ERROR_NOW_IN_PROGRESS == ret) {
435 LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Scan already in progress"),
436 &out, ("Scan in progress %d (%s)", ret, get_error_message(ret)));
438 // other errors are reported asynchronously
439 picojson::value value = picojson::value(picojson::object());
440 picojson::object* data_obj = &value.get<picojson::object>();
441 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
442 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to start scan"), data_obj,
443 ("Failed to start scan: %d (%s)", ret, get_error_message(ret)));
444 instance_.FireEvent(kScanEvent, value);
452 void BluetoothLEAdapter::StopScan(const picojson::value& data, picojson::object& out) {
454 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
457 int ret = bt_adapter_le_stop_scan();
459 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
460 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop scan"), &out,
461 ("Failed to stop scan: %d (%s)", ret, get_error_message(ret)));
468 void BluetoothLEAdapter::IsScanning(picojson::object& out) {
472 int ret = bt_adapter_le_is_discovering(&is_scanning);
474 if (BT_ERROR_NONE != ret) {
476 PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to check for scanning in progress"), &out,
477 ("Failed to check for scanning in progress: %d (%s)", ret, get_error_message(ret)));
479 scanning_ = is_scanning;
480 ReportSuccess(picojson::value(is_scanning), out);
484 void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
486 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
489 const auto& json_advertise_data = data.get("advertiseData");
490 const auto& json_packet_type = data.get("packetType");
491 const auto& json_mode = data.get("mode");
492 const auto& json_connectable = data.get("connectable");
494 if (!json_advertise_data.is<picojson::object>() || !json_packet_type.is<std::string>() ||
495 !json_mode.is<std::string>() || !json_connectable.is<bool>()) {
496 LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"),
501 BluetoothLEAdvertiseData advertise_data;
502 if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
504 PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
508 bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
510 const auto& str_packet_type = json_packet_type.get<std::string>();
511 if ("ADVERTISE" == str_packet_type) {
512 packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
513 } else if ("SCAN_RESPONSE" == str_packet_type) {
514 packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
517 PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out,
518 ("Wrong packet_type: %s", str_packet_type.c_str()));
523 bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
525 const auto& str_mode = json_mode.get<std::string>();
526 if ("BALANCED" == str_mode) {
527 mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
528 } else if ("LOW_LATENCY" == str_mode) {
529 mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
530 } else if ("LOW_ENERGY" == str_mode) {
531 mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
533 LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"),
534 &out, ("Wrong mode: %s", str_mode.c_str()));
539 if (nullptr != bt_advertiser_) {
540 LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"),
545 bt_advertiser_h advertiser = nullptr;
547 int ret = bt_adapter_le_create_advertiser(&advertiser);
548 if (BT_ERROR_NONE != ret) {
550 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
551 ("bt_adapter_le_create_advertiser() failed with: %d, (%s)", ret, get_error_message(ret)));
555 std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type, int (*)(bt_advertiser_h)>
556 advertiser_ptr(advertiser,
557 &bt_adapter_le_destroy_advertiser); // automatically release the memory
559 // configure advertiser
560 if (advertise_data.include_name()) {
561 ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
562 advertise_data.include_name());
563 if (BT_ERROR_NONE != ret) {
564 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
565 ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
566 get_error_message(ret)));
571 for (const auto& uuid : advertise_data.service_uuids()) {
573 * This native function accepts 16 or 128 bit UUIDs.
574 * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
577 * The documentation of Native Bluetooth API says, this function advertises 128-bit UUIDs,
578 * that have 32-bit equivalents in the full 128-bit form.
579 * However, as of the day of writing this comment, packets advertised
580 * by the device contain these UUIDs in their 32-bit formats,
581 * i.e. AD fields with 0x04 («Incomplete List of 32-bit Service Class UUIDs») type.
582 * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
584 ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
585 uuid.uuid_128_bit.c_str());
586 if (BT_ERROR_NONE != ret) {
587 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
588 ("bt_adapter_le_add_advertising_service_uuid() failed with: %d (%s)", ret,
589 get_error_message(ret)));
594 for (const auto& uuid : advertise_data.solicitation_uuids()) {
596 * This native function accepts 16 or 128 bit UUIDs.
597 * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
600 * The documentation of Native Bluetooth API says, it advertises 128-bit UUIDs,
601 * that have 32-bit equivalents in the full 128-bit form.
602 * However, as of the day of writing this comment, packets advertised
603 * by the device contain these UUIDs in their 32-bit formats,
604 * i.e. AD fields with 0x1F («List of 32-bit Service Solicitation UUIDs») type.
605 * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
607 ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, packet_type,
608 uuid.uuid_128_bit.c_str());
609 if (BT_ERROR_NONE != ret) {
611 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
612 ("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d (%s)", ret,
613 get_error_message(ret)));
618 ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
619 advertise_data.appearance());
620 if (BT_ERROR_NONE != ret) {
621 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
622 ("bt_adapter_le_set_advertising_appearance() failed with: %d (%s)", ret,
623 get_error_message(ret)));
627 if (advertise_data.include_tx_power_level()) {
628 ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
629 advertise_data.include_tx_power_level());
630 if (BT_ERROR_NONE != ret) {
631 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
632 ("bt_adapter_le_set_advertising_tx_power_level() failed with: %d (%s)", ret,
633 get_error_message(ret)));
638 if (advertise_data.service_data().empty()) {
639 LoggerD("service data is empty");
641 for (const auto& service_data_obj : advertise_data.service_data()) {
642 ret = bt_adapter_le_add_advertising_service_data(
643 advertiser, packet_type, service_data_obj.uuid().ShortestPossibleFormat().c_str(),
644 service_data_obj.data().pointer(), service_data_obj.data().length());
645 if (BT_ERROR_NONE != ret) {
646 std::string error_message = "Failed to create advertiser";
647 if (BT_ERROR_QUOTA_EXCEEDED == ret && !service_data_obj.uuid().To16Bit()) {
649 "Failed to start advertising: only 16 bit values of BluetoothLEServiceData::uuid are "
653 LogAndReportError(util::GetBluetoothError(ret, error_message), &out,
654 ("bt_adapter_le_add_advertising_service_data() failed with: %d (%s)", ret,
655 get_error_message(ret)));
661 const auto& manufacturer_data = advertise_data.manufacturer_data();
662 if (manufacturer_data.id().empty() && nullptr == manufacturer_data.data().pointer()) {
663 LoggerD("manufacturerData is empty");
665 if (manufacturer_data.valid()) {
666 ret = bt_adapter_le_add_advertising_manufacturer_data(
667 advertiser, packet_type, atoi(manufacturer_data.id().c_str()),
668 manufacturer_data.data().pointer(), manufacturer_data.data().length());
669 if (BT_ERROR_NONE != ret) {
670 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
671 ("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d (%s)",
672 ret, get_error_message(ret)));
678 ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
679 if (BT_ERROR_NONE != ret) {
681 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
682 ("bt_adapter_le_set_advertising_mode() failed with: %d (%s)", ret, get_error_message(ret)));
686 ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
687 if (BT_ERROR_NONE != ret) {
688 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
689 ("bt_adapter_le_set_advertising_connectable() failed with: %d (%s)", ret,
690 get_error_message(ret)));
694 // advertiser is ready, let's start advertising
695 ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
696 if (BT_ERROR_NONE != ret) {
697 if (BT_ERROR_NOW_IN_PROGRESS == ret) {
699 PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out,
700 ("bt_adapter_le_start_advertising_new error: %d (%s)", ret, get_error_message(ret)));
704 LogAndReportError(util::GetBluetoothError(ret, "Failed to start advertising"), &out,
705 ("bt_adapter_le_start_advertising_new() failed with: %d (%s)", ret,
706 get_error_message(ret)));
710 // everything went well, we want to store the pointer, so unique_ptr should no longer manage the
712 bt_advertiser_ = advertiser_ptr.release();
716 void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
718 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
721 if (nullptr != bt_advertiser_) {
722 int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
723 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
725 PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out,
726 ("bt_adapter_le_stop_advertising() failed with: %d (%s)", ret, get_error_message(ret)));
730 bt_advertiser_ = nullptr;
732 LoggerD("Advertising is not in progress");
738 void BluetoothLEAdapter::OnStateChanged(int result, bt_adapter_le_state_e adapter_le_state,
742 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
745 LoggerE("user_data is NULL");
749 adapter->enabled_ = ToBool(adapter_le_state);
752 void BluetoothLEAdapter::OnScanResult(int result, bt_adapter_le_device_scan_result_info_s* info,
754 ScopeLogger("result: %d, info: %p, data: %p", result, info, user_data);
756 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
759 LoggerE("user_data is NULL");
763 picojson::value value = picojson::value(picojson::object());
764 picojson::object* data_obj = &value.get<picojson::object>();
766 if (BT_ERROR_NONE != result) {
767 LogAndReportError(util::GetBluetoothError(result, "Error during scanning"), data_obj,
768 ("Error during scanning: %d (%s)", result, get_error_message(result)));
769 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
771 // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
772 if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
774 LoggerD("Device found");
775 picojson::value data{picojson::object{}};
776 const auto& ret = BluetoothLEDevice::ToJson(info, &data.get<picojson::object>());
778 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanSuccess)));
779 data_obj->insert(std::make_pair(kData, data));
781 LogAndReportError(ret, data_obj, ("Failed to parse Bluetooth LE device"));
782 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
787 adapter->instance_.FireEvent(kScanEvent, value);
790 void BluetoothLEAdapter::OnAdvertiseResult(int result, bt_advertiser_h advertiser,
791 bt_adapter_le_advertising_state_e adv_state,
793 ScopeLogger("result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser,
794 adv_state, user_data);
796 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
799 LoggerE("user_data is NULL");
803 picojson::value value = picojson::value(picojson::object());
804 picojson::object* data_obj = &value.get<picojson::object>();
806 if (BT_ERROR_NONE != result) {
807 LogAndReportError(util::GetBluetoothError(result, "Error during advertising"), data_obj,
808 ("Error during advertising: %d (%s)", result, get_error_message(result)));
809 data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
811 const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
812 LoggerD("Advertise state is: %s", state);
813 data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
814 ReportSuccess(picojson::value(state), *data_obj);
815 if (adv_state == BT_ADAPTER_LE_ADVERTISING_STOPPED) {
816 LoggerD("Advertiser destroy");
817 int ret = bt_adapter_le_destroy_advertiser(advertiser);
818 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
819 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"),
820 data_obj, ("bt_adapter_le_destroy_advertiser() failed with: %d (%s)", ret,
821 get_error_message(ret)));
827 adapter->instance_.FireEvent(kAdvertiseEvent, value);
830 } // namespace bluetooth
831 } // namespace extension