aebc3923c16069ea3f4d9164f1c46f4aa63954c3
[platform/framework/web/tizen-extensions-crosswalk.git] / bluetooth / bluetooth_instance_capi.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "bluetooth/bluetooth_instance_capi.h"
6
7 #include <pthread.h>
8
9 #include "common/picojson.h"
10
11 namespace {
12
13 inline const char* BoolToString(bool b) {
14   return b ? "true" : "false";
15 }
16
17 static void* event_loop(void* arg) {
18   GMainLoop* event_loop;
19   event_loop = g_main_loop_new(NULL, FALSE);
20   g_main_loop_run(event_loop);
21   return NULL;
22 }
23
24 }  // anonymous namespace
25
26 BluetoothInstance::BluetoothInstance()
27     : is_js_context_initialized_(false),
28       adapter_enabled_(false),
29       js_reply_needed_(false),
30       stop_discovery_from_js_(false) {
31
32   // we need a thread for running the main loop
33   // and catching bluetooth glib signals
34   pthread_t event_thread;
35   pthread_attr_t thread_attr;
36   pthread_attr_init(&thread_attr);
37   pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
38   event_thread = pthread_create(&event_thread, &thread_attr,
39       event_loop, NULL);
40
41   CAPI(bt_initialize());
42   InitializeAdapter();
43 }
44
45 BluetoothInstance::~BluetoothInstance() {
46   UninitializeAdapter();
47   CAPI(bt_deinitialize());
48 }
49
50 void BluetoothInstance::HandleMessage(const char* message) {
51   picojson::value v;
52
53   std::string err;
54   picojson::parse(v, message, message + strlen(message), &err);
55   if (!err.empty()) {
56     LOG_ERR("Ignoring message");
57     return;
58   }
59
60   std::string cmd = v.get("cmd").to_str();
61   if (cmd == "DiscoverDevices")
62     HandleDiscoverDevices(v);
63   else if (cmd == "StopDiscovery")
64     HandleStopDiscovery(v);
65   else if (cmd == "SetAdapterProperty")
66     HandleSetAdapterProperty(v);
67   else if (cmd == "CreateBonding")
68     HandleCreateBonding(v);
69   else if (cmd == "DestroyBonding")
70     HandleDestroyBonding(v);
71   else if (cmd == "RFCOMMListen")
72     HandleRFCOMMListen(v);
73   else if (cmd == "CloseSocket")
74     HandleCloseSocket(v);
75   else if (cmd == "UnregisterServer")
76     HandleUnregisterServer(v);
77 }
78
79 void BluetoothInstance::HandleSyncMessage(const char* message) {
80   picojson::value v;
81
82   std::string err;
83   picojson::parse(v, message, message + strlen(message), &err);
84   if (!err.empty()) {
85     LOG_ERR("Ignoring Sync message.");
86     return;
87   }
88
89   std::string cmd = v.get("cmd").to_str();
90   if (cmd == "GetDefaultAdapter")
91     HandleGetDefaultAdapter(v);
92   else if (cmd == "SocketWriteData")
93     HandleSocketWriteData(v);
94 }
95
96 void BluetoothInstance::OnStateChanged(int result,
97     bt_adapter_state_e adapter_state, void* user_data) {
98   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
99   if (!obj) {
100     LOG_ERR("user_data is NULL");
101     return;
102   }
103
104   obj->adapter_enabled_ = (adapter_state == BT_ADAPTER_ENABLED) ? true : false;
105
106   if (obj->js_reply_needed_) {
107     // FIXME(clecou) directly call 'GetDefaultAdapter' once NTB is integrated.
108     // After testing, 100 ms is necessary to really get a powered adapter.
109     g_timeout_add(100, obj->GetDefaultAdapter, obj);
110     return;
111   }
112
113   picojson::value::object o;
114
115   o["cmd"] = picojson::value("");
116   o["reply_id"] = picojson::value(obj->callbacks_id_map_["Powered"]);
117   if (result)
118     o["error"] = picojson::value(static_cast<double>(1));
119   else
120     o["error"] = picojson::value(static_cast<double>(0));
121
122   obj->InternalPostMessage(picojson::value(o));
123   obj->callbacks_id_map_.erase("Powered");
124 }
125
126 void BluetoothInstance::OnNameChanged(char* name, void* user_data) {
127   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
128   if (!obj) {
129     LOG_ERR("user_data is NULL");
130     return;
131   }
132
133   picojson::value::object o;
134
135   o["error"] = picojson::value(static_cast<double>(0));
136   o["cmd"] = picojson::value("");
137   o["reply_id"] = picojson::value(obj->callbacks_id_map_["Name"]);
138   obj->InternalPostMessage(picojson::value(o));
139   obj->callbacks_id_map_.erase("Name");
140 }
141
142 void BluetoothInstance::OnVisibilityChanged(int result,
143     bt_adapter_visibility_mode_e visibility_mode, void* user_data) {
144   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
145   if (!obj) {
146     LOG_ERR("user_data is NULL");
147     return;
148   }
149
150   picojson::value::object o;
151
152   o["cmd"] = picojson::value("");
153   o["reply_id"] = picojson::value(obj->callbacks_id_map_["Discoverable"]);
154   if (result)
155     o["error"] = picojson::value(static_cast<double>(1));
156   else
157     o["error"] = picojson::value(static_cast<double>(0));
158
159   obj->InternalPostMessage(picojson::value(o));
160   obj->callbacks_id_map_.erase("Discoverable");
161 }
162
163 void BluetoothInstance::OnDiscoveryStateChanged(int result,
164     bt_adapter_device_discovery_state_e discovery_state,
165     bt_adapter_device_discovery_info_s* discovery_info, void* user_data) {
166   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
167   if (!obj) {
168     LOG_ERR("user_data is NULL");
169     return;
170   }
171
172   picojson::value::object o;
173
174   switch (discovery_state) {
175     case BT_ADAPTER_DEVICE_DISCOVERY_STARTED: {
176       o["cmd"] = picojson::value("");
177       o["reply_id"] = picojson::value(obj->callbacks_id_map_["StartDiscovery"]);
178       if (result) {
179         LOG_ERR(result);
180         o["error"] = picojson::value(static_cast<double>(1));
181       } else {
182         o["error"] = picojson::value(static_cast<double>(0));
183       }
184       obj->InternalPostMessage(picojson::value(o));
185       obj->callbacks_id_map_.erase("StartDiscovery");
186       break;
187     }
188     case BT_ADAPTER_DEVICE_DISCOVERY_FINISHED: {
189       if (obj->stop_discovery_from_js_) {
190         o["cmd"] = picojson::value("");
191         o["reply_id"] =
192             picojson::value(obj->callbacks_id_map_["StopDiscovery"]);
193         if (result) {
194           LOG_ERR(result);
195           o["error"] = picojson::value(static_cast<double>(1));
196         } else {
197           o["error"] = picojson::value(static_cast<double>(0));
198         }
199       } else {
200         // discovery stop was not initiated by JS. It was done by a timeout...
201         o["cmd"] = picojson::value("DiscoveryFinished");
202       }
203       obj->InternalPostMessage(picojson::value(o));
204       obj->callbacks_id_map_.erase("StopDiscovery");
205       obj->stop_discovery_from_js_ = false;
206       break;
207     }
208     case BT_ADAPTER_DEVICE_DISCOVERY_FOUND: {
209       o["Alias"] = picojson::value(discovery_info->remote_name);
210       o["Address"] = picojson::value(discovery_info->remote_address);
211
212       int major = discovery_info->bt_class.major_device_class;
213       int minor = discovery_info->bt_class.minor_device_class;
214       int service_class = discovery_info->bt_class.major_service_class_mask;
215       o["ClassMajor"] = picojson::value(static_cast<double>(major));
216       o["ClassMinor"] = picojson::value(static_cast<double>(minor));
217       o["ClassService"] = picojson::value(static_cast<double>(service_class));
218
219       picojson::array uuids;
220       for (int i = 0; i < discovery_info->service_count; i++)
221         uuids.push_back(picojson::value(discovery_info->service_uuid[i]));
222
223       o["UUIDs"] = picojson::value(uuids);
224
225       bool paired = false;
226       bool trusted = false;
227       bool connected = false;
228
229       if (discovery_info->is_bonded) {
230         bt_device_info_s* device_info = NULL;
231         CAPI(bt_adapter_get_bonded_device_info(discovery_info->remote_address,
232                                                &device_info));
233         if (!device_info)
234           LOG_ERR("device_info is NULL");
235
236         if (!device_info->is_bonded)
237           LOG_ERR("remote device should be bonded!");
238
239         paired = true;
240         trusted = device_info->is_authorized;
241         connected = device_info->is_connected;
242         CAPI(bt_adapter_free_device_info(device_info));
243       }
244
245       o["Paired"] = picojson::value(BoolToString(paired));
246       o["Trusted"] = picojson::value(BoolToString(trusted));
247       o["Connected"] = picojson::value(BoolToString(connected));
248
249       o["cmd"] = picojson::value("DeviceFound");
250       o["found_on_discovery"] = picojson::value(true);
251
252       obj->InternalPostMessage(picojson::value(o));
253       break;
254     }
255     default:
256       LOG_ERR("Unknown discovery state callback!");
257       break;
258   }
259 }
260
261 bool BluetoothInstance::OnKnownBondedDevice(bt_device_info_s* device_info,
262     void* user_data) {
263   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
264   if (!obj) {
265     LOG_ERR("user_data is NULL!");
266     return false;
267   }
268   if (!device_info) {
269     LOG_ERR("device_info is NULL!");
270     return false;
271   }
272
273   picojson::value::object o;
274   char* alias = device_info->remote_name;
275   o["Alias"] = picojson::value(alias);
276
277   char* address = device_info->remote_address;
278   o["Address"] = picojson::value(address);
279
280   int major = device_info->bt_class.major_device_class;
281   int minor = device_info->bt_class.minor_device_class;
282   int service_class = device_info->bt_class.major_service_class_mask;
283   o["ClassMajor"] = picojson::value(static_cast<double>(major));
284   o["ClassMinor"] = picojson::value(static_cast<double>(minor));
285   o["ClassService"] = picojson::value(static_cast<double>(service_class));
286
287   // parse UUIDs supported by remote device
288   picojson::array uuids;
289   for (int i = 0; i < device_info->service_count; i++)
290     uuids.push_back(picojson::value(device_info->service_uuid[i]));
291
292   o["UUIDs"] = picojson::value(uuids);
293   o["Paired"] = picojson::value(BoolToString(device_info->is_bonded));
294   o["Trusted"] = picojson::value(BoolToString(device_info->is_authorized));
295   o["Connected"] = picojson::value(BoolToString(device_info->is_connected));
296   o["reply_id"] = picojson::value("");
297   o["cmd"] = picojson::value("BondedDevice");
298   obj->InternalPostMessage(picojson::value(o));
299   return true;
300 }
301
302 void BluetoothInstance::OnBondCreated(int result, bt_device_info_s* device_info,
303     void* user_data) {
304   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
305   if (!obj) {
306     LOG_ERR("user_data is NULL!");
307     return;
308   }
309   if (!device_info) {
310     LOG_ERR("device_info is NULL!");
311     return;
312   }
313
314   picojson::value::object o;
315   o["cmd"] = picojson::value("");
316   o["reply_id"] = picojson::value(obj->callbacks_id_map_["CreateBonding"]);
317   o["capi"] = picojson::value(static_cast<double>(1));
318   if (result) {
319     LOG_ERR("onBondCreated() failed");
320     o["error"] = picojson::value(static_cast<double>(1));
321   } else {
322     o["error"] = picojson::value(static_cast<double>(0));
323   }
324   obj->InternalPostMessage(picojson::value(o));
325   obj->callbacks_id_map_.erase("CreateBonding");
326 }
327
328 void BluetoothInstance::OnBondDestroyed(int result, char* remote_address,
329     void* user_data) {
330   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
331   if (!obj) {
332     LOG_ERR("user_data is NULL!");
333     return;
334   }
335
336   if (!remote_address) {
337     LOG_ERR("remote_address is NULL!");
338     return;
339   }
340   picojson::value::object o;
341   o["cmd"] = picojson::value("");
342   o["reply_id"] = picojson::value(obj->callbacks_id_map_["DestroyBonding"]);
343   o["capi"] = picojson::value(static_cast<double>(1));
344   if (result) {
345     LOG_ERR("onBondDestroyed() failed");
346     o["error"] = picojson::value(static_cast<double>(1));
347   } else {
348     o["error"] = picojson::value(static_cast<double>(0));
349   }
350   obj->InternalPostMessage(picojson::value(o));
351   obj->callbacks_id_map_.erase("DestroyBonding");
352 }
353
354 void BluetoothInstance::OnSocketConnected(int result,
355     bt_socket_connection_state_e connection_state,
356     bt_socket_connection_s* connection,
357     void* user_data) {
358   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
359   if (!obj) {
360     LOG_ERR("user_data is NULL!");
361     return;
362   }
363   if (!connection) {
364     LOG_ERR("connection is NULL!");
365     return;
366   }
367
368   picojson::value::object o;
369
370   if (result) {
371     LOG_ERR("onSocketConnected() is failed");
372     o["error"] = picojson::value(static_cast<double>(1));
373   }
374
375   if (connection_state == BT_SOCKET_CONNECTED &&
376       connection->local_role == BT_SOCKET_SERVER) {
377     o["cmd"] = picojson::value("RFCOMMSocketAccept");
378     o["uuid"] = picojson::value(connection->service_uuid);
379     o["socket_fd"] =
380         picojson::value(static_cast<double>(connection->socket_fd));
381     o["peer"] = picojson::value(connection->remote_address);
382
383     CAPI(bt_socket_set_data_received_cb(OnSocketHasData, NULL));
384   } else if (connection_state == BT_SOCKET_CONNECTED &&
385              connection->local_role == BT_SOCKET_CLIENT) {
386     o["cmd"] = picojson::value("");
387     o["reply_id"] =
388         picojson::value(obj->callbacks_id_map_["ConnectToService"]);
389     obj->callbacks_id_map_.erase("ConnectToService");
390
391     o["uuid"] = picojson::value(connection->service_uuid);
392     o["socket_fd"] =
393         picojson::value(static_cast<double>(connection->socket_fd));
394
395     CAPI(bt_socket_set_data_received_cb(OnSocketHasData, NULL));
396   } else if (connection_state == BT_SOCKET_DISCONNECTED) {
397       o["cmd"] = picojson::value("");
398       o["reply_id"] =
399           picojson::value(obj->callbacks_id_map_["RFCOMMsocketDestroy"]);
400       obj->callbacks_id_map_.erase("RFCOMMsocketDestroy");
401       o["socket_fd"] =
402           picojson::value(static_cast<double>(connection->socket_fd));
403   } else {
404     LOG_ERR("Unknown role!");
405     return;
406   }
407   obj->InternalPostMessage(picojson::value(o));
408 }
409
410 void BluetoothInstance::OnSocketHasData(bt_socket_received_data_s* data,
411                                         void* user_data) {
412   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
413   if (!obj) {
414     LOG_ERR("user_data is NULL");
415     return;
416   }
417   if (!data) {
418     LOG_ERR("data is NULL");
419     return;
420   }
421   picojson::value::object o;
422   o["cmd"] = picojson::value("SocketHasData");
423   o["socket_fd"] = picojson::value(static_cast<double>(data->socket_fd));
424   o["data"] = picojson::value(static_cast<std::string>(data->data));
425   obj->InternalPostMessage(picojson::value(o));
426 }
427
428 gboolean BluetoothInstance::GetDefaultAdapter(gpointer user_data) {
429   BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
430   if (!obj) {
431     LOG_ERR("user_data is NULL");
432     return TRUE;
433   }
434
435   picojson::value::object o;
436
437   char* name = NULL;
438   CAPI(bt_adapter_get_name(&name));
439   if (!name)
440     return TRUE;
441   o["name"] = picojson::value(name);
442
443   char* address = NULL;
444   CAPI(bt_adapter_get_address(&address));
445   if (!address)
446     return TRUE;
447   o["address"] = picojson::value(address);
448
449   bool powered, visible = false;
450
451   if (obj->adapter_enabled_) {
452     powered = true;
453
454   bt_adapter_visibility_mode_e mode =
455       BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
456
457   CAPI(bt_adapter_get_visibility(&mode, NULL));
458   visible = (mode > 0) ? true : false;
459   }
460   o["powered"] = picojson::value(powered);
461   o["visible"] = picojson::value(visible);
462
463   // This is the JS API entry point, so we should clean our message queue
464   // on the next PostMessage call.
465   if (!obj->is_js_context_initialized_)
466     obj->is_js_context_initialized_ = true;
467
468   obj->InternalSetSyncReply(picojson::value(o));
469
470   // Retrieve already bonded devices linked to the adapter in order to
471   // fill known_devices array on javascript side.
472   CAPI(bt_adapter_foreach_bonded_device(OnKnownBondedDevice, obj));
473
474   obj->js_reply_needed_ = false;
475
476   return FALSE;
477 }
478
479 void BluetoothInstance::InitializeAdapter() {
480   // register C API bluetooth callbacks
481   CAPI(bt_adapter_set_state_changed_cb(OnStateChanged, this));
482   CAPI(bt_adapter_set_name_changed_cb(OnNameChanged, this));
483   CAPI(bt_adapter_set_visibility_mode_changed_cb(OnVisibilityChanged, this));
484   CAPI(bt_adapter_set_device_discovery_state_changed_cb(OnDiscoveryStateChanged,
485                                                         this));
486   CAPI(bt_device_set_bond_created_cb(OnBondCreated, this));
487   CAPI(bt_device_set_bond_destroyed_cb(OnBondDestroyed, this));
488
489   bt_adapter_state_e state = BT_ADAPTER_DISABLED;
490   CAPI(bt_adapter_get_state(&state));
491
492   // Most of the C API functions require as precondition to previously had
493   // called bt_adapter_enable(). So if adapter is turned OFF, we enable it.
494   if (state == BT_ADAPTER_DISABLED) {
495     CAPI(bt_adapter_enable());
496   } else {
497     adapter_enabled_ = true;
498   }
499 }
500
501 void BluetoothInstance::UninitializeAdapter() {
502   // unregister C API bluetooth callbacks
503   CAPI(bt_adapter_unset_state_changed_cb());
504   CAPI(bt_adapter_unset_name_changed_cb());
505   CAPI(bt_adapter_unset_visibility_mode_changed_cb());
506   CAPI(bt_adapter_unset_device_discovery_state_changed_cb());
507   CAPI(bt_device_unset_bond_created_cb());
508   CAPI(bt_device_unset_bond_destroyed_cb());
509   CAPI(bt_socket_unset_connection_state_changed_cb());
510   CAPI(bt_socket_unset_data_received_cb());
511 }
512
513 void BluetoothInstance::HandleGetDefaultAdapter(const picojson::value& msg) {
514   if (!adapter_enabled_) {
515     js_reply_needed_ = true;
516     return;
517   }
518
519   GetDefaultAdapter(this);
520 }
521
522 void BluetoothInstance::HandleSetAdapterProperty(const picojson::value& msg) {
523   picojson::value::object o;
524
525   std::string property = msg.get("property").to_str();
526   callbacks_id_map_[property] = msg.get("reply_id").to_str();
527
528   if (property == "Powered") {
529     bool power = msg.get("value").get<bool>();
530     if (power)
531       CAPI(bt_adapter_enable());
532     else
533       CAPI(bt_adapter_disable());
534   } else if (property == "Name") {
535     std::string name = msg.get("value").to_str();
536     CAPI(bt_adapter_set_name(name.c_str()));
537   } else if (property == "Discoverable") {
538     bool visible = msg.get("value").get<bool>();
539     int timeout = static_cast<int>(msg.get("timeout").get<double>());
540
541     bt_adapter_visibility_mode_e discoverable_mode =
542         BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
543     if (visible) {
544       if (timeout == 0)
545         discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
546       else
547         discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
548     }
549     CAPI(bt_adapter_set_visibility(discoverable_mode, timeout));
550   } else {
551     LOG_ERR("bad property received!");
552   }
553 }
554
555 void BluetoothInstance::HandleDiscoverDevices(const picojson::value& msg) {
556   callbacks_id_map_["StartDiscovery"] = msg.get("reply_id").to_str();
557   CAPI(bt_adapter_start_device_discovery());
558 }
559
560 void BluetoothInstance::HandleStopDiscovery(const picojson::value& msg) {
561   callbacks_id_map_["StopDiscovery"] = msg.get("reply_id").to_str();
562
563   bool is_discovering = false;
564   CAPI(bt_adapter_is_discovering(&is_discovering));
565   if (!is_discovering)
566     return;
567
568   stop_discovery_from_js_ = true;
569   CAPI(bt_adapter_stop_device_discovery());
570 }
571
572 void BluetoothInstance::HandleCreateBonding(const picojson::value& msg) {
573   callbacks_id_map_["CreateBonding"] = msg.get("reply_id").to_str();
574   std::string address = msg.get("address").to_str();
575   CAPI(bt_device_create_bond(address.c_str()));
576 }
577
578 void BluetoothInstance::HandleDestroyBonding(const picojson::value& msg) {
579   callbacks_id_map_["DestroyBonding"] = msg.get("reply_id").to_str();
580   std::string address = msg.get("address").to_str();
581   CAPI(bt_device_destroy_bond(address.c_str()));
582 }
583
584 void BluetoothInstance::HandleRFCOMMListen(const picojson::value& msg) {
585   picojson::value::object o;
586
587   int socket_fd = 0;
588   int error = 0;
589
590   CAPI_ERR(
591       bt_socket_create_rfcomm(msg.get("uuid").to_str().c_str(), &socket_fd),
592       error);
593   if (error) {
594     o["error"] = picojson::value(static_cast<double>(1));
595     InternalPostMessage(picojson::value(o));
596     return;
597   }
598
599   CAPI_ERR(bt_socket_listen_and_accept_rfcomm(socket_fd, 0), error);
600   if (error) {
601     o["error"] = picojson::value(static_cast<double>(1));
602     InternalPostMessage(picojson::value(o));
603     return;
604   }
605
606   CAPI_ERR(bt_socket_set_connection_state_changed_cb(OnSocketConnected, this),
607            error);
608   if (error) {
609     o["error"] = picojson::value(static_cast<double>(1));
610     InternalPostMessage(picojson::value(o));
611     return;
612   }
613
614   o["error"] = picojson::value(static_cast<double>(0));
615   // give the listened socket to JS and store it in service_handler
616   o["socket_fd"] = picojson::value(static_cast<double>(socket_fd));
617   InternalPostMessage(picojson::value(o));
618 }
619
620 void BluetoothInstance::HandleConnectToService(const picojson::value& msg) {
621   callbacks_id_map_["ConnectToService"] = msg.get("reply_id").to_str();
622   int error = 0;
623
624   CAPI_ERR(
625       bt_socket_connect_rfcomm(msg.get("address").to_str().c_str(),
626                                msg.get("uuid").to_str().c_str()),
627       error);
628   if (!error)
629     CAPI(bt_socket_set_connection_state_changed_cb(OnSocketConnected, this));
630 }
631
632 void BluetoothInstance::HandleSocketWriteData(const picojson::value& msg) {
633   picojson::value::object o;
634   std::string data = msg.get("data").to_str();
635   int socket = static_cast<int>(msg.get("socket_fd").get<double>());
636
637   CAPI(bt_socket_send_data(socket, data.c_str(),
638                            static_cast<int>(data.size())));
639   o["size"] = picojson::value(static_cast<double>(data.size()));
640
641   InternalSetSyncReply(picojson::value(o));
642 }
643
644 void BluetoothInstance::HandleCloseSocket(const picojson::value& msg) {
645   picojson::value::object o;
646   int error = 0;
647   int socket = static_cast<int>(msg.get("socket_fd").get<double>());
648
649   CAPI_ERR(bt_socket_disconnect_rfcomm(socket), error);
650   if (!error)
651     o["error"] = picojson::value(static_cast<double>(0));
652   else
653     o["error"] = picojson::value(static_cast<double>(1));
654
655
656   o["cmd"] = picojson::value("");
657   o["reply_id"] = msg.get("reply_id");
658   o["capi"] = picojson::value(static_cast<double>(1));
659   InternalPostMessage(picojson::value(o));
660 }
661
662 void BluetoothInstance::HandleUnregisterServer(const picojson::value& msg) {
663   callbacks_id_map_["RFCOMMsocketDestroy"] = msg.get("reply_id").to_str();
664   int socket = static_cast<int>(msg.get("server_fd").get<double>());
665
666   CAPI(bt_socket_destroy_rfcomm(socket));
667 }
668
669 void BluetoothInstance::FlushPendingMessages() {
670   // Flush previous pending messages.
671   if (queue_.empty())
672     return;
673
674   MessageQueue::iterator it;
675   for (it = queue_.begin(); it != queue_.end(); ++it)
676     PostMessage((*it).serialize().c_str());
677 }
678
679 void BluetoothInstance::InternalPostMessage(picojson::value v) {
680   // If the JavaScript 'context' hasn't been initialized yet (i.e. the C++
681   // backend was loaded and it is already executing but
682   // tizen.bluetooth.getDefaultAdapter() hasn't been called so far), we need to
683   // queue the PostMessage calls and defer them until the default adapter is set
684   // on the JS side. That will guarantee the correct callbacks will be called,
685   // and on the right order, only after tizen.bluetooth.getDefaultAdapter() is
686   // called.
687
688   if (!is_js_context_initialized_) {
689     queue_.push_back(v);
690     return;
691   }
692
693   FlushPendingMessages();
694   PostMessage(v.serialize().c_str());
695 }
696
697 void BluetoothInstance::InternalSetSyncReply(picojson::value v) {
698   SendSyncReply(v.serialize().c_str());
699
700   FlushPendingMessages();
701 }