6 #include <pulse/proplist.h>
7 #include <pulse/util.h>
8 #include <pulse/rtclock.h>
9 #include <pulsecore/log.h>
10 #include <pulsecore/core-util.h>
11 #include <pulsecore/strbuf.h>
13 #include "tizen-device.h"
15 #define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
16 #define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
17 #define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
19 #define BT_CVSD_CODEC_ID 1 // narrow-band
20 #define BT_MSBC_CODEC_ID 2 // wide-band
23 int values[MAX_INTSET_NUM];
28 static int device_id_max_g = 1;
29 static uint32_t event_id_max_g = 1;
31 static uint32_t _new_event_id() {
32 return event_id_max_g++;
35 int pa_intset_put(pa_intset *s, int val) {
40 if (s->write_index >= MAX_INTSET_NUM)
43 for(i = 0; i < s->write_index; i++) {
44 if (s->values[i] == val)
48 s->values[s->write_index++] = val;
53 pa_intset* pa_intset_new() {
56 s = pa_xmalloc0(sizeof(pa_intset));
63 void pa_intset_free(pa_intset *s) {
68 int pa_intset_first(pa_intset *s, int *val) {
72 if (s->write_index == 0)
76 *val = s->values[s->read_index++];
81 int pa_intset_next(pa_intset *s, int *val) {
85 if (s->read_index >= s->write_index)
88 *val = s->values[s->read_index++];
93 static char* get_playback_list_str(pa_hashmap *playback_devices) {
99 if (!playback_devices || !pa_hashmap_size(playback_devices))
102 buf = pa_strbuf_new();
103 pa_strbuf_printf(buf, " Playback device list\n");
104 PA_HASHMAP_FOREACH_KV(role, sink, playback_devices, state)
105 pa_strbuf_printf(buf, " %-13s -> %s\n", role, sink->name);
107 return pa_strbuf_to_string_free(buf);
110 static char* get_capture_list_str(pa_hashmap *capture_devices) {
111 pa_source *source = NULL;
116 if (!capture_devices || !pa_hashmap_size(capture_devices))
119 buf = pa_strbuf_new();
120 pa_strbuf_printf(buf, " Capture device list\n");
121 PA_HASHMAP_FOREACH_KV(role, source, capture_devices, state)
122 pa_strbuf_printf(buf, " %-13s -> %s\n", role, source->name);
124 return pa_strbuf_to_string_free(buf);
127 static char* _device_get_info_str(pa_tz_device *device) {
129 char *playback_str, *capture_str;
134 buf = pa_strbuf_new();
135 pa_strbuf_printf(buf, "[Device #%u]\n", device->id);
136 pa_strbuf_printf(buf, " ID : %u\n", device->id);
137 pa_strbuf_printf(buf, " Type : %s\n", device->type);
138 pa_strbuf_printf(buf, " Name : %s\n", device->name);
139 pa_strbuf_printf(buf, " System ID : %s\n", device->system_id);
140 pa_strbuf_printf(buf, " Direction : %s\n", device_direction_to_string(device->direction));
141 pa_strbuf_printf(buf, " Is activated : %s\n", pa_yes_no(device->state == DM_DEVICE_STATE_ACTIVATED));
142 pa_strbuf_printf(buf, " Internal : %s\n", pa_yes_no(device->use_internal_codec));
143 if (device_type_is_equal(device->type, DEVICE_TYPE_USB_AUDIO)) {
144 pa_strbuf_printf(buf, " Vendor ID : %04x\n", device->vendor_id);
145 pa_strbuf_printf(buf, " Product ID : %04x\n", device->product_id);
146 pa_strbuf_printf(buf, " Specified Stream role : %s\n", device->specified_stream_role);
148 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
149 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO))
150 pa_strbuf_printf(buf, " SCO opened : %s\n", pa_yes_no(device->sco_opened));
152 playback_str = get_playback_list_str(device->playback_devices);
153 capture_str = get_capture_list_str(device->capture_devices);
156 pa_strbuf_puts(buf, playback_str);
158 pa_strbuf_puts(buf, capture_str);
160 pa_xfree(playback_str);
161 pa_xfree(capture_str);
163 return pa_strbuf_to_string_free(buf);
167 void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level) {
173 if ((info = _device_get_info_str(device))) {
174 pa_logl(log_level, "%s", info);
179 static void notify_device_connection_changed(pa_tz_device *device, bool connected) {
180 pa_tz_device_hook_data_for_conn_changed hook_data;
182 hook_data.event_id = _new_event_id();
183 hook_data.is_connected = connected;
184 hook_data.device = device;
186 pa_log_info("Fire hook for device connection changed, device(%s/%u) %s",
187 device->type, device->id, connected ? "connected" : "disconnected");
188 pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), &hook_data);
191 static void notify_device_state_changed(pa_tz_device *device, dm_device_state_t state) {
192 pa_tz_device_hook_data_for_state_changed hook_data;
194 hook_data.event_id = _new_event_id();
195 hook_data.activated = (state == DM_DEVICE_STATE_ACTIVATED) ? true : false;
196 hook_data.device = device;
198 pa_log_info("Fire hook for device state changed, device(%s/%u) %s",
199 device->type, device->id, hook_data.activated ? "Activated" : "De-activated");
200 pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED), &hook_data);
203 static void notify_device_running_changed(pa_tz_device *device, bool running) {
204 pa_tz_device_hook_data_for_running_changed hook_data;
206 hook_data.event_id = _new_event_id();
207 hook_data.is_running = running;
208 hook_data.device = device;
210 pa_log_info("Fire hook for device running changed, device(%s/%u) %s",
211 device->type, device->id, hook_data.is_running ? "Running" : "Not running");
212 pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED), &hook_data);
215 /* pa_tz_device_new_data */
216 void pa_tz_device_new_data_init(pa_tz_device_new_data *data, pa_idxset *list,
217 pa_communicator *comm, pa_dbus_connection *conn) {
224 data->dbus_conn = conn;
228 data->system_id = NULL;
229 data->vendor_id = -1;
230 data->product_id = -1;
231 data->direction = DM_DEVICE_DIRECTION_NONE;
233 data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
234 data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
237 void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type) {
240 data->type = pa_xstrdup(type);
243 void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name) {
246 data->name = pa_xstrdup(name);
249 void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction) {
252 data->direction = direction;
254 /* only for external? */
255 void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id) {
258 data->system_id = pa_xstrdup(system_id);
261 void pa_tz_device_new_data_set_vendor_id(pa_tz_device_new_data *data, int vendor_id) {
264 data->vendor_id = vendor_id;
267 void pa_tz_device_new_data_set_product_id(pa_tz_device_new_data *data, int product_id) {
270 data->product_id = product_id;
273 void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec) {
276 data->use_internal_codec = use_internal_codec;
279 void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink) {
282 pa_hashmap_put(data->playback_pcms, (void*)role, sink);
285 void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source) {
288 pa_hashmap_put(data->capture_pcms, (void*)role, source);
291 void pa_tz_device_new_data_done(pa_tz_device_new_data *data) {
294 pa_xfree(data->type);
295 pa_xfree(data->name);
298 static int _check_valid_device_new_data(pa_tz_device_new_data *data) {
301 if (data->type == NULL) {
302 pa_log_error("new data type is null");
306 if (data->direction == DM_DEVICE_DIRECTION_NONE) {
307 pa_log_error("new data direction is none");
314 static int device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
316 pa_assert(device->playback_devices);
318 if (pa_hashmap_put(device->playback_devices, (void*)role, sink) < 0) {
319 pa_log_error("Failed to add sink : put sink failed");
325 static int device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
327 pa_assert(device->capture_devices);
329 if (pa_hashmap_put(device->capture_devices, (void*)role, source) < 0) {
330 pa_log_error("Failed to add source : put source failed");
336 static pa_sink* device_get_sink(pa_tz_device *device, const char *role) {
339 pa_assert(device->playback_devices);
341 /* If the role is null, it returns the first one. We consider it as default sink
342 * until the default value is newly defined in device-map.json later on. */
344 if ((sink = pa_hashmap_first(device->playback_devices)) == NULL) {
345 pa_log_warn("Failed to get sink for default");
351 if ((sink = pa_hashmap_get(device->playback_devices, role)) == NULL) {
352 pa_log_warn("Failed to get sink for %s", role);
359 static pa_source* device_get_source(pa_tz_device *device, const char *role) {
362 pa_assert(device->capture_devices);
364 /* If the role is null, it returns the first one. We consider it as default source
365 * until the default value is newly defined in device-map.json later on. */
367 if ((source = pa_hashmap_first(device->capture_devices)) == NULL) {
368 pa_log_warn("Failed to get source for default");
374 if ((source = pa_hashmap_get(device->capture_devices, role)) == NULL) {
375 pa_log_warn("Failed to get source for %s", role);
382 static void device_set_state(pa_tz_device *device, dm_device_state_t new_state) {
385 if (device->state != new_state) {
386 pa_log_debug("change state %d -> %d", device->state, new_state);
387 device->state = new_state;
388 notify_device_state_changed(device, new_state);
389 pa_tz_device_dump_info(device, PA_LOG_DEBUG);
391 pa_log_debug("same state, not change it");
395 static dm_device_state_t device_get_state(pa_tz_device *device) {
397 return device->state;
400 static void device_set_running_and_notify(pa_tz_device *device, bool running) {
403 if (device->is_running != running) {
404 pa_log_debug("change running state %d -> %d", device->is_running, running);
405 device->is_running = running;
406 notify_device_running_changed(device, running);
407 pa_tz_device_dump_info(device, PA_LOG_DEBUG);
409 pa_log_debug("same running state, not change it");
413 static int device_remove_sink_with_role(pa_tz_device *device, const char *role) {
417 sink = pa_hashmap_remove(device->playback_devices, role);
418 return sink ? 0 : -1;
421 static int device_remove_source_with_role(pa_tz_device *device, const char *role) {
425 source = pa_hashmap_remove(device->capture_devices, role);
426 return source ? 0 : -1;
429 static int device_remove_sink(pa_tz_device *device, pa_sink *sink) {
436 PA_HASHMAP_FOREACH_KV(role, _sink, device->playback_devices, state) {
438 return device_remove_sink_with_role(device, role);
444 static int device_remove_source(pa_tz_device *device, pa_source *source) {
451 PA_HASHMAP_FOREACH_KV(role, _source, device->capture_devices, state) {
452 if (source == _source)
453 return device_remove_source_with_role(device, role);
460 pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
461 pa_tz_device *device;
465 char spec_str[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0, };
469 if (_check_valid_device_new_data(data) < 0) {
470 pa_log_error("Invalid device_new_data");
474 device = pa_xmalloc0(sizeof(pa_tz_device));
476 device->list = data->list;
477 device->comm = data->comm;
478 device->dbus_conn = data->dbus_conn;
480 device->id = device_id_max_g++;
481 device->type = pa_xstrdup(data->type);
482 device->name = pa_xstrdup(data->name ? data->name : data->type);
483 device->system_id = pa_xstrdup(data->system_id);
484 device->vendor_id = data->vendor_id;
485 device->product_id = data->product_id;
487 device->playback_devices = data->playback_pcms;
488 device->capture_devices = data->capture_pcms;
489 device->direction = data->direction;
490 device->state = DM_DEVICE_STATE_DEACTIVATED;
491 device->creation_time = pa_rtclock_now();
492 device->use_internal_codec = data->use_internal_codec;
493 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
494 device->sco_opened = false;
496 device->is_running = false;
497 device->specified_stream_role = pa_xstrdup("none");
499 if ((sink = device_get_sink(device, NULL))) {
500 sink->device_item = device;
501 device->sample_spec = &sink->sample_spec;
503 if ((source = device_get_source(device, NULL))) {
504 source->device_item = device;
505 device->sample_spec = &source->sample_spec;
507 pa_sample_spec_snprint(spec_str, sizeof(spec_str), device->sample_spec);
509 pa_log_info("New device: type(%s) spec(%s) id(%u) name(%s) system_id(%s) vendor_id(%04x) product_id(%04x)",
510 device->type, spec_str, device->id, device->name,
511 pa_strempty(device->system_id), device->vendor_id, device->product_id);
513 pa_idxset_put(device->list, device, NULL);
515 notify_device_connection_changed(device, true);
517 pa_tz_device_dump_info(device, PA_LOG_INFO);
522 int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
524 pa_assert(device_role_is_valid(role));
527 pa_log_info("device add sink, device(%u) role(%s) sink(%s)",
528 device->id, role, sink->name);
530 if (device_add_sink(device, role, sink) < 0) {
531 pa_log_error("Failed to add sink : Can't add to device");
538 int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
540 pa_assert(device_role_is_valid(role));
543 pa_log_info("device add source, device(%u) role(%s) source(%s)",
544 device->id, role, source->name);
546 if (device_add_source(device, role, source) < 0) {
547 pa_log_error("Failed to add source : Can't add to device");
554 int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink) {
558 pa_log_info("device remove sink, device(%u) sink(%s)",
559 device->id, sink->name);
561 return device_remove_sink(device, sink);
564 int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source) {
568 pa_log_info("device remove source, device(%u) source(%s)",
569 device->id, source->name);
571 return device_remove_source(device, source);
574 int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role) {
576 pa_assert(device_role_is_valid(role));
578 pa_log_info("device remove sink with role, device(%u) role(%s)",
581 return device_remove_sink_with_role(device, role);
584 int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role) {
586 pa_assert(device_role_is_valid(role));
588 pa_log_info("device remove source with role, device(%u) role(%s)",
591 return device_remove_source_with_role(device, role);
594 void pa_tz_device_free(pa_tz_device *device) {
601 pa_log_info("Free device type(%s) id(%u) name(%s) system_id(%s)",
602 device->type, device->id, device->name, device->system_id);
604 pa_tz_device_dump_info(device, PA_LOG_INFO);
606 pa_idxset_remove_by_data(device->list, device, NULL);
608 if (device->playback_devices)
609 PA_HASHMAP_FOREACH(sink, device->playback_devices, state)
610 sink->device_item = NULL;
612 if (device->capture_devices)
613 PA_HASHMAP_FOREACH(source, device->capture_devices, state)
614 source->device_item = NULL;
616 notify_device_connection_changed(device, false);
618 pa_xfree(device->type);
619 pa_xfree(device->name);
620 pa_xfree(device->system_id);
621 pa_xfree(device->specified_stream_role);
627 pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role) {
632 pa_log_info("device get sink, device(%u) role(%s)", device->id, role);
634 if ((sink = device_get_sink(device, role)) == NULL) {
635 pa_log_error("Failed to get sink from device");
639 pa_log_info("sink name(%s)", sink->name);
644 pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
649 pa_log_info("device get source, device(%u) role(%s)",
652 if ((source = device_get_source(device, role)) == NULL) {
653 pa_log_error("Failed to get source from device");
657 pa_log_info("source name(%s)", source->name);
662 /* TODO : Change param dm_device_state_t to bool or pa_tz_device_state_t,
663 * Because this state represent pa_tz_device's own state */
664 void pa_tz_device_set_state(pa_tz_device *device, dm_device_state_t state) {
667 pa_log_info("device set state, device(%u) type(%s) -> %d",
668 device->id, device->type, state);
669 device_set_state(device, state);
672 dm_device_state_t pa_tz_device_get_state(pa_tz_device *device) {
675 return device_get_state(device);
678 void pa_tz_device_set_running_and_notify(pa_tz_device *device, bool running) {
681 pa_log_info("device set running, device(%u) type(%s) -> %d (0:not running, 1:running)",
682 device->id, device->type, running);
683 device_set_running_and_notify(device, running);
686 bool pa_tz_device_is_running(pa_tz_device *device) {
689 return device->is_running;
692 uint32_t pa_tz_device_get_id(pa_tz_device *device) {
698 char* pa_tz_device_get_type(pa_tz_device *device) {
704 char* pa_tz_device_get_role(pa_tz_device *device, const char *preferred_role) {
712 if (device->playback_devices) {
713 PA_HASHMAP_FOREACH_KV(role, sink, device->playback_devices, state) {
717 if (pa_safe_streq(role, preferred_role))
722 if (device->capture_devices) {
723 PA_HASHMAP_FOREACH_KV(role, source, device->capture_devices, state) {
727 if (pa_safe_streq(role, preferred_role))
732 pa_log_error("Failed to get a role from the device[type:%s, id:%u, name:%s] with preferred_role[%s]",
733 device->type, device->id, device->name, preferred_role);
738 char* pa_tz_device_get_name(pa_tz_device *device) {
744 char* pa_tz_device_get_system_id(pa_tz_device *device) {
747 return device->system_id;
750 int pa_tz_device_get_vendor_id(pa_tz_device *device) {
753 return device->vendor_id;
756 int pa_tz_device_get_product_id(pa_tz_device *device) {
759 return device->product_id;
762 char* pa_tz_device_get_specified_stream_role(pa_tz_device *device) {
765 if (pa_safe_streq("none", device->specified_stream_role))
768 return device->specified_stream_role;
771 dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device) {
774 return device->direction;
777 pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device) {
780 return device->creation_time;
783 bool pa_tz_device_is_use_internal_codec(pa_tz_device *device) {
786 return device->use_internal_codec;
789 const pa_sample_spec* pa_tz_device_get_sample_spec(pa_tz_device *device) {
792 return device->sample_spec;
795 bool pa_tz_device_is_all_suspended(pa_tz_device *device) {
800 PA_HASHMAP_FOREACH(sink, device->playback_devices, state) {
801 if (sink->state != PA_SINK_SUSPENDED)
805 PA_HASHMAP_FOREACH(source, device->capture_devices, state) {
806 if (source->state != PA_SOURCE_SUSPENDED)
813 pa_intset* pa_tz_device_get_stream_list(pa_tz_device *device) {
816 pa_sink_input *input;
817 pa_source_output *output;
819 const char *p_id_str;
822 pa_intset *stream_id_set;
826 stream_id_set = pa_intset_new();
827 PA_HASHMAP_FOREACH(sink, device->playback_devices, state) {
828 PA_IDXSET_FOREACH(input, sink->inputs, idx) {
829 p_id_str = pa_proplist_gets(input->proplist, PA_PROP_MEDIA_PARENT_ID);
830 if (p_id_str && !pa_atoi(p_id_str, &p_id)) {
831 pa_intset_put(stream_id_set, p_id);
833 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
837 PA_HASHMAP_FOREACH(source, device->capture_devices, state) {
838 PA_IDXSET_FOREACH(output, source->outputs, idx) {
839 p_id_str = pa_proplist_gets(output->proplist, PA_PROP_MEDIA_PARENT_ID);
840 if (p_id_str && !pa_atoi(p_id_str, &p_id)) {
841 pa_intset_put(stream_id_set, p_id);
843 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
848 return stream_id_set;
851 #ifndef __TIZEN_TV_EXTERNAL_BT_SCO__
852 static int method_call_bt_sco_enable_pcm(pa_dbus_connection *conn, bool enable) {
853 DBusMessage *msg, *reply;
855 const char *method = "SetVoiceDial";
856 dbus_bool_t _enable = (dbus_bool_t)enable;
860 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
861 pa_log_error("dbus method call failed");
865 pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &_enable, DBUS_TYPE_INVALID));
867 dbus_error_init(&err);
868 reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
869 dbus_message_unref(msg);
871 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
872 dbus_error_free(&err);
876 dbus_message_unref(reply);
880 static int method_call_bt_sco(pa_dbus_connection *conn, bool onoff) {
881 DBusMessage *msg, *reply;
887 method = onoff ? "Play" : "Stop";
888 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
889 pa_log_error("dbus method call failed");
893 dbus_error_init(&err);
894 reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
895 dbus_message_unref(msg);
897 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
898 dbus_error_free(&err);
902 dbus_message_unref(reply);
906 static int method_call_bt_sco_get_property(pa_dbus_connection *conn, bool *is_wide_band, bool *is_nrec) {
907 DBusMessage *msg, *reply;
908 DBusMessageIter reply_iter, reply_iter_entry;
912 const char *property;
916 if (!is_wide_band && !is_nrec) {
920 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, "GetProperties"))) {
921 pa_log_error("dbus method call failed");
925 dbus_error_init(&err);
926 reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
927 dbus_message_unref(msg);
929 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
930 dbus_error_free(&err);
934 dbus_message_iter_init(reply, &reply_iter);
936 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
937 pa_log_error("Cannot get reply argument");
941 dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
943 while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
944 DBusMessageIter dict_entry, dict_entry_val;
946 dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
947 dbus_message_iter_get_basic(&dict_entry, &property);
948 pa_log_debug("String received = %s", property);
950 if (pa_safe_streq("codec", property) && is_wide_band) {
951 dbus_message_iter_next(&dict_entry);
952 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
953 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_UINT32)
955 dbus_message_iter_get_basic(&dict_entry_val, &codec);
956 pa_log_debug("Codec = [%d]", codec);
957 *is_wide_band = (codec == BT_MSBC_CODEC_ID) ? true : false;
958 } else if (pa_safe_streq("nrec", property) && is_nrec) {
959 dbus_message_iter_next(&dict_entry);
960 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
961 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_BOOLEAN)
963 dbus_message_iter_get_basic(&dict_entry_val, &nrec);
964 pa_log_debug("nrec = [%d]", nrec);
968 dbus_message_iter_next(&reply_iter_entry);
971 dbus_message_unref(reply);
976 /* only for bt sco device */
977 int pa_tz_device_sco_enable_pcm(pa_tz_device *device, bool enable) {
979 pa_assert(device->dbus_conn);
981 pa_log_info("BT SCO PCM[device id:%u, enable: %d]", device->id, enable);
982 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
983 pa_log_error("Not BT SCO device");
987 if (enable && device->sco_opened) {
988 pa_log_info("BT SCO is already opened, skip enable pcm");
992 if (method_call_bt_sco_enable_pcm(device->dbus_conn, enable) < 0) {
993 pa_log_error("Failed to bt sco enable pcm");
997 pa_log_info("BT SCO PCM enable[%d]- SUCCESS", enable);
1002 /* only for bt sco device */
1003 int pa_tz_device_sco_open(pa_tz_device *device) {
1005 pa_assert(device->dbus_conn);
1007 pa_log_info("BT SCO Open for device(%u)", device->id);
1008 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
1009 pa_log_error("Not BT SCO device");
1013 if (device->sco_opened) {
1014 pa_log_warn("SCO already opened");
1018 if (method_call_bt_sco(device->dbus_conn, true) < 0) {
1019 pa_log_error("Failed to bt sco on");
1023 device->sco_opened = true;
1024 device->creation_time = pa_rtclock_now();
1025 pa_tz_device_dump_info(device, PA_LOG_DEBUG);
1026 pa_log_info("BT SCO Open - SUCCESS");
1031 /* only for bt sco device */
1032 int pa_tz_device_sco_close(pa_tz_device *device) {
1035 pa_log_info("BT SCO Close for device(%u)", device->id);
1037 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
1038 pa_log_error("Not BT SCO device");
1042 if (device->sco_opened == false) {
1043 pa_log_warn("SCO not opened");
1047 if (method_call_bt_sco(device->dbus_conn, false) < 0) {
1048 pa_log_error("Failed to bt sco on");
1052 device->sco_opened = false;
1053 pa_tz_device_dump_info(device, PA_LOG_DEBUG);
1054 pa_log_info("BT SCO Close - Success");
1059 /* only for bt sco device */
1060 int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec) {
1063 pa_log_info("BT SCO get property for device(%u)", device->id);
1064 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
1065 pa_log_error("Not BT device");
1069 if (method_call_bt_sco_get_property(device->dbus_conn, is_wide_band, nrec) < 0) {
1070 pa_log_error("Failed to get BT SCO Property");
1074 pa_log_info("BT SCO Get Property - Success, is wide band : %s, nrec : %s", pa_yes_no(*is_wide_band), pa_yes_no(*nrec));
1079 /* only for bt sco device */
1080 int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t *status) {
1083 pa_log_debug("BT SCO get status for device(%u)", device->id);
1084 if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
1085 pa_log_error("Not BT device");
1088 if (status == NULL) {
1089 pa_log_error("invalid parameter");
1093 if (device->sco_opened == false)
1094 *status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
1096 *status = DM_DEVICE_BT_SCO_STATUS_OPENED;
1098 pa_log_info("BT SCO (%u) Get Status, %d", device->id, *status);
1101 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */