Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" | 5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "device/bluetooth/bluetooth_adapter_win.h" | 8 #include "device/bluetooth/bluetooth_adapter_win.h" |
| 9 #include "device/bluetooth/bluetooth_gatt_notify_session_win.h" | |
| 9 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_win.h" | 10 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_win.h" |
| 10 #include "device/bluetooth/bluetooth_remote_gatt_service_win.h" | 11 #include "device/bluetooth/bluetooth_remote_gatt_service_win.h" |
| 11 #include "device/bluetooth/bluetooth_task_manager_win.h" | 12 #include "device/bluetooth/bluetooth_task_manager_win.h" |
| 12 | 13 |
| 14 namespace { | |
| 15 | |
| 16 // Function to be registered to OS to monitor Bluetooth LE GATT event. | |
| 17 void OnGetGattEventWin(BTH_LE_GATT_EVENT_TYPE type, | |
| 18 PVOID event_parameter, | |
| 19 PVOID context) { | |
| 20 device::BluetoothRemoteGattCharacteristicWin* characteristic = | |
| 21 (device::BluetoothRemoteGattCharacteristicWin*)context; | |
|
ortuno
2016/03/07 18:48:45
Space between parentheses and context.
gogerald1
2016/03/07 22:52:49
Is this google code style? It looks making more se
ortuno
2016/03/08 00:05:36
Interesting. Well if git cl format says no space t
gogerald1
2016/03/08 19:22:23
Acknowledged.
| |
| 22 characteristic->OnGetRemoteGattEvent(type, event_parameter); | |
| 23 } | |
| 24 | |
| 25 } // namespace | |
| 26 | |
| 13 namespace device { | 27 namespace device { |
| 14 | 28 |
| 15 BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin( | 29 BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin( |
| 16 BluetoothRemoteGattServiceWin* parent_service, | 30 BluetoothRemoteGattServiceWin* parent_service, |
| 17 BTH_LE_GATT_CHARACTERISTIC* characteristic_info, | 31 BTH_LE_GATT_CHARACTERISTIC* characteristic_info, |
| 18 scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) | 32 scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) |
| 19 : parent_service_(parent_service), | 33 : parent_service_(parent_service), |
| 20 characteristic_info_(characteristic_info), | 34 characteristic_info_(characteristic_info), |
| 21 ui_task_runner_(ui_task_runner), | 35 ui_task_runner_(ui_task_runner), |
| 22 characteristic_added_notified_(false), | 36 characteristic_added_notified_(false), |
| 23 characteristic_value_read_or_write_in_progress_(false), | 37 characteristic_value_read_or_write_in_progress_(false), |
| 38 number_of_active_notify_sessions_(0), | |
| 39 gatt_event_registeration_in_progress_(false), | |
| 40 gatt_event_handle_(NULL), | |
| 24 weak_ptr_factory_(this) { | 41 weak_ptr_factory_(this) { |
| 25 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 42 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 26 DCHECK(parent_service_); | 43 DCHECK(parent_service_); |
| 27 DCHECK(characteristic_info_); | 44 DCHECK(characteristic_info_); |
| 28 | 45 |
| 29 task_manager_ = | 46 task_manager_ = |
| 30 parent_service_->GetWinAdapter()->GetWinBluetoothTaskManager(); | 47 parent_service_->GetWinAdapter()->GetWinBluetoothTaskManager(); |
| 31 DCHECK(task_manager_); | 48 DCHECK(task_manager_); |
| 32 characteristic_uuid_ = | 49 characteristic_uuid_ = |
| 33 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid( | 50 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid( |
| 34 characteristic_info_->CharacteristicUuid); | 51 characteristic_info_->CharacteristicUuid); |
| 35 characteristic_identifier_ = | 52 characteristic_identifier_ = |
| 36 parent_service_->GetIdentifier() + "_" + | 53 parent_service_->GetIdentifier() + "_" + |
| 37 std::to_string(characteristic_info_->AttributeHandle); | 54 std::to_string(characteristic_info_->AttributeHandle); |
| 38 Update(); | 55 Update(); |
| 39 } | 56 } |
| 40 | 57 |
| 41 BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() { | 58 BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() { |
| 42 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 59 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 43 | 60 |
| 61 if (gatt_event_handle_ != NULL) { | |
| 62 task_manager_->UnregisterGattCharacteristicValueChangedEvent( | |
| 63 gatt_event_handle_); | |
| 64 gatt_event_handle_ = NULL; | |
| 65 } | |
| 44 parent_service_->GetWinAdapter()->NotifyGattCharacteristicRemoved(this); | 66 parent_service_->GetWinAdapter()->NotifyGattCharacteristicRemoved(this); |
| 45 } | 67 } |
| 46 | 68 |
| 47 std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const { | 69 std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const { |
| 48 return characteristic_identifier_; | 70 return characteristic_identifier_; |
| 49 } | 71 } |
| 50 | 72 |
| 51 BluetoothUUID BluetoothRemoteGattCharacteristicWin::GetUUID() const { | 73 BluetoothUUID BluetoothRemoteGattCharacteristicWin::GetUUID() const { |
| 52 return characteristic_uuid_; | 74 return characteristic_uuid_; |
| 53 } | 75 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 | 120 |
| 99 if (characteristic_info_->IsReadable) | 121 if (characteristic_info_->IsReadable) |
| 100 permissions = permissions | PERMISSION_READ; | 122 permissions = permissions | PERMISSION_READ; |
| 101 if (characteristic_info_->IsWritable) | 123 if (characteristic_info_->IsWritable) |
| 102 permissions = permissions | PERMISSION_WRITE; | 124 permissions = permissions | PERMISSION_WRITE; |
| 103 | 125 |
| 104 return permissions; | 126 return permissions; |
| 105 } | 127 } |
| 106 | 128 |
| 107 bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const { | 129 bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const { |
| 108 NOTIMPLEMENTED(); | 130 return gatt_event_handle_ != NULL; |
| 109 return false; | |
| 110 } | 131 } |
| 111 | 132 |
| 112 std::vector<BluetoothGattDescriptor*> | 133 std::vector<BluetoothGattDescriptor*> |
| 113 BluetoothRemoteGattCharacteristicWin::GetDescriptors() const { | 134 BluetoothRemoteGattCharacteristicWin::GetDescriptors() const { |
| 114 std::vector<BluetoothGattDescriptor*> descriptors; | 135 std::vector<BluetoothGattDescriptor*> descriptors; |
| 115 for (const auto& descriptor : included_descriptors_) | 136 for (const auto& descriptor : included_descriptors_) |
| 116 descriptors.push_back(descriptor.second.get()); | 137 descriptors.push_back(descriptor.second.get()); |
| 117 return descriptors; | 138 return descriptors; |
| 118 } | 139 } |
| 119 | 140 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 133 | 154 |
| 134 bool BluetoothRemoteGattCharacteristicWin::UpdateValue( | 155 bool BluetoothRemoteGattCharacteristicWin::UpdateValue( |
| 135 const std::vector<uint8_t>& value) { | 156 const std::vector<uint8_t>& value) { |
| 136 NOTIMPLEMENTED(); | 157 NOTIMPLEMENTED(); |
| 137 return false; | 158 return false; |
| 138 } | 159 } |
| 139 | 160 |
| 140 void BluetoothRemoteGattCharacteristicWin::StartNotifySession( | 161 void BluetoothRemoteGattCharacteristicWin::StartNotifySession( |
| 141 const NotifySessionCallback& callback, | 162 const NotifySessionCallback& callback, |
| 142 const ErrorCallback& error_callback) { | 163 const ErrorCallback& error_callback) { |
| 143 NOTIMPLEMENTED(); | 164 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 144 error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); | 165 |
| 166 if (IsNotifying()) { | |
| 167 scoped_ptr<BluetoothGattNotifySessionWin> notify_session( | |
| 168 new BluetoothGattNotifySessionWin(weak_ptr_factory_.GetWeakPtr())); | |
| 169 callback.Run(std::move(notify_session)); | |
|
ortuno
2016/03/07 18:48:45
StartNotifySession should be async. Post a task he
gogerald1
2016/03/07 22:52:49
Done.
| |
| 170 number_of_active_notify_sessions_++; | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 if (gatt_event_registeration_in_progress_) { | |
| 175 start_notify_session_callbacks_.push_back( | |
| 176 std::make_pair(callback, error_callback)); | |
| 177 return; | |
| 178 } | |
| 179 | |
| 180 start_notify_session_callbacks_.push_back( | |
| 181 std::make_pair(callback, error_callback)); | |
| 182 task_manager_->PostRegisterGattCharacteristicValueChangedEvent( | |
| 183 parent_service_->GetServicePath(), characteristic_info_.get(), | |
| 184 base::Bind( | |
| 185 &BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback, | |
| 186 weak_ptr_factory_.GetWeakPtr()), | |
| 187 &OnGetGattEventWin, (PVOID) this); | |
|
ortuno
2016/03/07 18:48:45
Wouldn't you get a null pointer dereference if win
gogerald1
2016/03/07 22:52:49
Event will be unregistered in ~BluetoothRemoteGatt
ortuno
2016/03/08 00:05:36
Could the following happen?
PostTask(~BluetoothRe
gogerald1
2016/03/08 19:22:23
This could not happen since UnregisterGattCharacte
| |
| 188 gatt_event_registeration_in_progress_ = true; | |
|
ortuno
2016/03/07 18:48:45
Are you sure the registering for the event is enou
gogerald1
2016/03/07 22:52:49
No needed,
ortuno
2016/03/08 00:05:36
This sort of statements are not useful when trying
scheib
2016/03/08 18:30:07
If a question ever comes up from a reviewer it is
gogerald1
2016/03/08 19:22:23
My judgement is based on this API document (https:
ortuno
2016/03/09 16:53:59
Nothing in the link you sent mentions anything abo
gogerald1
2016/03/09 23:59:12
I definitely have told you that I have experimente
| |
| 145 } | 189 } |
| 146 | 190 |
| 147 void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( | 191 void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( |
| 148 const ValueCallback& callback, | 192 const ValueCallback& callback, |
| 149 const ErrorCallback& error_callback) { | 193 const ErrorCallback& error_callback) { |
| 150 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 194 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 151 | 195 |
| 152 if (!characteristic_info_.get()->IsReadable) { | 196 if (!characteristic_info_.get()->IsReadable) { |
| 153 error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); | 197 error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); |
| 154 return; | 198 return; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 characteristic_value_read_or_write_in_progress_ = true; | 232 characteristic_value_read_or_write_in_progress_ = true; |
| 189 write_characteristic_value_callbacks_ = | 233 write_characteristic_value_callbacks_ = |
| 190 std::make_pair(callback, error_callback); | 234 std::make_pair(callback, error_callback); |
| 191 task_manager_->PostWriteGattCharacteristicValue( | 235 task_manager_->PostWriteGattCharacteristicValue( |
| 192 parent_service_->GetServicePath(), characteristic_info_.get(), new_value, | 236 parent_service_->GetServicePath(), characteristic_info_.get(), new_value, |
| 193 base::Bind(&BluetoothRemoteGattCharacteristicWin:: | 237 base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
| 194 OnWriteRemoteCharacteristicValueCallback, | 238 OnWriteRemoteCharacteristicValueCallback, |
| 195 weak_ptr_factory_.GetWeakPtr())); | 239 weak_ptr_factory_.GetWeakPtr())); |
| 196 } | 240 } |
| 197 | 241 |
| 242 void BluetoothRemoteGattCharacteristicWin::OnGetRemoteGattEvent( | |
|
ortuno
2016/03/07 18:48:45
Does this get called after reading or writing to a
gogerald1
2016/03/07 22:52:49
No the case on Windows. I don't see why it should
ortuno
2016/03/08 00:05:36
Can you confirm that you registered for an event a
scheib
2016/03/08 18:30:07
If the interface isn't documented precisely enough
gogerald1
2016/03/08 19:22:23
I have confirmed it by experiment. I think it's cl
ortuno
2016/03/09 16:53:59
Just to be sure, you registered for the event and
gogerald1
2016/03/09 23:59:12
yes
| |
| 243 BTH_LE_GATT_EVENT_TYPE type, | |
| 244 PVOID event_parameter) { | |
| 245 if (type == CharacteristicValueChangedEvent) { | |
| 246 BLUETOOTH_GATT_VALUE_CHANGED_EVENT* event = | |
| 247 (BLUETOOTH_GATT_VALUE_CHANGED_EVENT*)event_parameter; | |
|
ortuno
2016/03/07 18:48:45
Space between parentheses and evet_parameter
gogerald1
2016/03/07 22:52:49
Acknowledged.
| |
| 248 PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value_win = | |
| 249 event->CharacteristicValue; | |
| 250 scoped_ptr<uint8_t> new_value(new uint8_t[new_value_win->DataSize]); | |
|
ortuno
2016/03/07 18:48:45
Why do you use a pointer to a uint8? I think scope
gogerald1
2016/03/07 22:52:49
Done.
| |
| 251 for (ULONG i = 0; i < new_value_win->DataSize; i++) | |
| 252 new_value.get()[i] = new_value_win->Data[i]; | |
| 253 | |
| 254 ui_task_runner_->PostTask(FROM_HERE, | |
| 255 base::Bind(&BluetoothRemoteGattCharacteristicWin:: | |
| 256 OnGattCharacteristicValueChanged, | |
| 257 weak_ptr_factory_.GetWeakPtr(), | |
| 258 base::Passed(std::move(new_value)), | |
| 259 new_value_win->DataSize)); | |
|
ortuno
2016/03/07 18:48:45
I think you should return here and add a NOTREACHE
gogerald1
2016/03/07 22:52:49
Done.
| |
| 260 } | |
| 261 } | |
| 262 | |
| 198 void BluetoothRemoteGattCharacteristicWin::Update() { | 263 void BluetoothRemoteGattCharacteristicWin::Update() { |
| 199 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 264 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 200 | 265 |
| 201 task_manager_->PostGetGattIncludedDescriptors( | 266 task_manager_->PostGetGattIncludedDescriptors( |
| 202 parent_service_->GetServicePath(), characteristic_info_.get(), | 267 parent_service_->GetServicePath(), characteristic_info_.get(), |
| 203 base::Bind(&BluetoothRemoteGattCharacteristicWin:: | 268 base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
| 204 OnGetIncludedDescriptorsCallback, | 269 OnGetIncludedDescriptorsCallback, |
| 205 weak_ptr_factory_.GetWeakPtr())); | 270 weak_ptr_factory_.GetWeakPtr())); |
| 206 } | 271 } |
| 207 | 272 |
| 208 uint16_t BluetoothRemoteGattCharacteristicWin::GetAttributeHandle() const { | 273 uint16_t BluetoothRemoteGattCharacteristicWin::GetAttributeHandle() const { |
| 209 return characteristic_info_->AttributeHandle; | 274 return characteristic_info_->AttributeHandle; |
| 210 } | 275 } |
| 211 | 276 |
| 277 void BluetoothRemoteGattCharacteristicWin::StopNotifySession() { | |
| 278 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 279 | |
| 280 if (!IsNotifying()) | |
| 281 return; | |
| 282 | |
| 283 if (number_of_active_notify_sessions_ > 1) { | |
| 284 number_of_active_notify_sessions_--; | |
| 285 return; | |
| 286 } | |
| 287 | |
| 288 task_manager_->UnregisterGattCharacteristicValueChangedEvent( | |
| 289 gatt_event_handle_); | |
| 290 gatt_event_handle_ = NULL; | |
| 291 number_of_active_notify_sessions_ = 0; | |
| 292 start_notify_session_callbacks_.clear(); | |
|
ortuno
2016/03/07 18:48:45
When would you have pending callbacks?
gogerald1
2016/03/07 22:52:49
Done.
| |
| 293 } | |
| 294 | |
| 212 void BluetoothRemoteGattCharacteristicWin::OnGetIncludedDescriptorsCallback( | 295 void BluetoothRemoteGattCharacteristicWin::OnGetIncludedDescriptorsCallback( |
| 213 scoped_ptr<BTH_LE_GATT_DESCRIPTOR> descriptors, | 296 scoped_ptr<BTH_LE_GATT_DESCRIPTOR> descriptors, |
| 214 uint16_t num, | 297 uint16_t num, |
| 215 HRESULT hr) { | 298 HRESULT hr) { |
| 216 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 299 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 217 | 300 |
| 218 UpdateIncludedDescriptors(descriptors.get(), num); | 301 UpdateIncludedDescriptors(descriptors.get(), num); |
| 219 if (!characteristic_added_notified_) { | 302 if (!characteristic_added_notified_) { |
| 220 characteristic_added_notified_ = true; | 303 characteristic_added_notified_ = true; |
| 221 parent_service_->GetWinAdapter()->NotifyGattCharacteristicAdded(this); | 304 parent_service_->GetWinAdapter()->NotifyGattCharacteristicAdded(this); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 BluetoothRemoteGattCharacteristicWin::HRESULTToGattErrorCode(HRESULT hr) { | 409 BluetoothRemoteGattCharacteristicWin::HRESULTToGattErrorCode(HRESULT hr) { |
| 327 switch (hr) { | 410 switch (hr) { |
| 328 case E_BLUETOOTH_ATT_READ_NOT_PERMITTED: | 411 case E_BLUETOOTH_ATT_READ_NOT_PERMITTED: |
| 329 case E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED: | 412 case E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED: |
| 330 return BluetoothGattService::GATT_ERROR_NOT_PERMITTED; | 413 return BluetoothGattService::GATT_ERROR_NOT_PERMITTED; |
| 331 case E_BLUETOOTH_ATT_UNKNOWN_ERROR: | 414 case E_BLUETOOTH_ATT_UNKNOWN_ERROR: |
| 332 return BluetoothGattService::GATT_ERROR_UNKNOWN; | 415 return BluetoothGattService::GATT_ERROR_UNKNOWN; |
| 333 case ERROR_INVALID_USER_BUFFER: | 416 case ERROR_INVALID_USER_BUFFER: |
| 334 case E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: | 417 case E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: |
| 335 return BluetoothGattService::GATT_ERROR_INVALID_LENGTH; | 418 return BluetoothGattService::GATT_ERROR_INVALID_LENGTH; |
| 419 case E_BLUETOOTH_ATT_REQUEST_NOT_SUPPORTED: | |
| 420 return BluetoothGattService::GATT_ERROR_NOT_SUPPORTED; | |
| 336 default: | 421 default: |
| 337 return BluetoothGattService::GATT_ERROR_FAILED; | 422 return BluetoothGattService::GATT_ERROR_FAILED; |
| 338 } | 423 } |
| 339 } | 424 } |
| 340 | 425 |
| 426 void BluetoothRemoteGattCharacteristicWin::OnGattCharacteristicValueChanged( | |
| 427 scoped_ptr<uint8_t> new_value, | |
| 428 ULONG size) { | |
| 429 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 430 | |
| 431 characteristic_value_.clear(); | |
| 432 for (ULONG i = 0; i < size; i++) | |
| 433 characteristic_value_.push_back(new_value.get()[i]); | |
|
ortuno
2016/03/07 18:48:45
As mentioned before I think you should pass in a v
gogerald1
2016/03/07 22:52:49
Done.
| |
| 434 parent_service_->GetWinAdapter()->NotifyGattCharacteristicValueChanged( | |
| 435 this, characteristic_value_); | |
| 436 } | |
| 437 | |
| 438 void BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback( | |
| 439 BLUETOOTH_GATT_EVENT_HANDLE event_handle, | |
| 440 HRESULT hr) { | |
| 441 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 442 | |
| 443 gatt_event_registeration_in_progress_ = false; | |
| 444 std::vector<std::pair<NotifySessionCallback, ErrorCallback>> callbacks; | |
| 445 callbacks.swap(start_notify_session_callbacks_); | |
| 446 if (SUCCEEDED(hr)) { | |
| 447 for (auto callback : callbacks) { | |
|
ortuno
2016/03/07 18:48:45
You should use a reference of the callback not a c
gogerald1
2016/03/07 22:52:49
Done.
| |
| 448 scoped_ptr<BluetoothGattNotifySessionWin> notify_session( | |
|
ortuno
2016/03/07 18:48:45
You don't need to create a scoped pointer first yo
gogerald1
2016/03/07 22:52:49
Done.
| |
| 449 new BluetoothGattNotifySessionWin(weak_ptr_factory_.GetWeakPtr())); | |
| 450 callback.first.Run(std::move(notify_session)); | |
|
ortuno
2016/03/07 18:48:45
I think you should just post a task here. Otherwis
gogerald1
2016/03/07 22:52:49
Done.
| |
| 451 number_of_active_notify_sessions_++; | |
| 452 } | |
| 453 gatt_event_handle_ = event_handle; | |
| 454 } else { | |
| 455 for (auto callback : callbacks) | |
|
ortuno
2016/03/07 18:48:45
Same here use a reference not a copy.
gogerald1
2016/03/07 22:52:49
Done.
| |
| 456 callback.second.Run(HRESULTToGattErrorCode(hr)); | |
| 457 } | |
| 458 } | |
| 459 | |
| 341 } // namespace device. | 460 } // namespace device. |
| OLD | NEW |