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
22 #define COMPOUND_STATE(d) (((pa_tz_profile*)d)->playback_state | ((pa_tz_profile*)d)->capture_state)
24 int device_id_max_g = 1;
25 uint32_t event_id_max_g = 1;
27 static uint32_t _new_event_id() {
28 return event_id_max_g++;
31 static char* get_playback_list_str(pa_hashmap *playback_devices) {
37 if (!playback_devices || !pa_hashmap_size(playback_devices))
40 buf = pa_strbuf_new();
41 pa_strbuf_printf(buf, " Playback device list\n");
42 PA_HASHMAP_FOREACH_KEY(sink, playback_devices, state, role)
43 pa_strbuf_printf(buf, " %-13s -> %s\n", role, sink->name);
45 return pa_strbuf_tostring_free(buf);
48 static char* get_capture_list_str(pa_hashmap *capture_devices) {
49 pa_source *source = NULL;
54 if (!capture_devices || !pa_hashmap_size(capture_devices))
57 buf = pa_strbuf_new();
58 pa_strbuf_printf(buf, " Capture device list\n");
59 PA_HASHMAP_FOREACH_KEY(source, capture_devices, state, role)
60 pa_strbuf_printf(buf, " %-13s -> %s\n", role, source->name);
62 return pa_strbuf_tostring_free(buf);
65 /* Returned string must be freed */
66 static char* get_device_profile_info_str(pa_tz_profile *profile) {
68 char *playback_str, *capture_str;
72 buf = pa_strbuf_new();
73 pa_strbuf_printf(buf, " Profile : %s\n", pa_strna(profile->profile));
74 pa_strbuf_printf(buf, " Direction : %s\n", device_direction_to_string(profile->direction));
75 pa_strbuf_printf(buf, " Is activated : %s\n", pa_yes_no(COMPOUND_STATE(profile) == DM_DEVICE_STATE_ACTIVATED));
76 pa_strbuf_printf(buf, " Internal : %s\n", pa_yes_no(profile->use_internal_codec));
77 if (profile->profile && pa_streq(profile->profile, DEVICE_PROFILE_BT_SCO))
78 pa_strbuf_printf(buf, " SCO opened : %s\n", pa_yes_no(profile->sco_opened));
79 playback_str = get_playback_list_str(profile->playback_devices);
80 capture_str = get_capture_list_str(profile->capture_devices);
83 pa_strbuf_puts(buf, playback_str);
85 pa_strbuf_puts(buf, capture_str);
87 pa_xfree(playback_str);
88 pa_xfree(capture_str);
90 return pa_strbuf_tostring_free(buf);
93 static char* _device_get_info_str(pa_tz_device *device) {
96 pa_tz_profile *profile;
102 buf = pa_strbuf_new();
103 pa_strbuf_printf(buf, "[Device #%u]\n", device->id);
104 pa_strbuf_printf(buf, " ID : %u\n", device->id);
105 pa_strbuf_printf(buf, " Type : %s\n", device->type);
106 pa_strbuf_printf(buf, " Name : %s\n", device->name);
107 if (device_type_is_multi_profile(device->type))
108 pa_strbuf_printf(buf, " System ID : %s\n", device->system_id);
109 pa_strbuf_printf(buf, " Active Profile : %u\n", device->active_profile);
111 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
112 pa_strbuf_printf(buf, " (Profile #%d)\n", profile_idx);
113 profile_info = get_device_profile_info_str(profile);
115 pa_strbuf_puts(buf, profile_info);
116 pa_xfree(profile_info);
119 return pa_strbuf_tostring_free(buf);
123 void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level) {
129 if ((info = _device_get_info_str(device))) {
130 pa_logl(log_level, "%s", info);
135 static void notify_device_connection_changed(pa_tz_device *device, bool connected) {
136 pa_device_manager_hook_data_for_conn_changed hook_data;
139 event_id = _new_event_id();
141 hook_data.event_id = event_id;
142 hook_data.is_connected = connected;
143 hook_data.device = device;
145 pa_log_info("Fire hook for device connection changed, device(%u) %s",
146 device->id, connected ? "connected" : "disconnected");
147 pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), &hook_data);
150 static void notify_device_info_changed(pa_tz_device *device, dm_device_changed_info_t changed_type) {
151 pa_device_manager_hook_data_for_info_changed hook_data;
154 event_id = _new_event_id();
156 hook_data.event_id = event_id;
157 hook_data.changed_info = changed_type;
158 hook_data.device = device;
160 pa_log_info("Fire hook for device info changed, device(%u) %s changed",
161 device->id, changed_type == DM_DEVICE_CHANGED_INFO_STATE ? "state" : "direction");
162 pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED), &hook_data);
165 /* pa_tz_device_new_data */
166 void pa_tz_device_new_data_init(pa_tz_device_new_data *data, pa_idxset *list,
167 pa_communicator *comm, pa_dbus_connection *conn) {
174 data->dbus_conn = conn;
178 data->system_id = NULL;
179 data->direction = DM_DEVICE_DIRECTION_NONE;
181 data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
182 data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
187 void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type) {
190 data->type = pa_xstrdup(type);
193 void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name) {
196 data->name = pa_xstrdup(name);
199 void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction) {
202 data->direction = direction;
204 /* only for external? */
205 void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id) {
208 data->system_id = pa_xstrdup(system_id);
211 void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec) {
214 data->use_internal_codec = use_internal_codec;
217 void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink) {
220 pa_hashmap_put(data->playback_pcms, (void*)role, sink);
223 void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source) {
226 pa_hashmap_put(data->capture_pcms, (void*)role, source);
228 /* after set_type, only for multi profile type, and check direction, profile */
229 void pa_tz_device_new_data_add_profile(pa_tz_device_new_data *data, pa_tz_profile_new_data *profile_data, bool as_active) {
230 uint32_t profile_idx;
233 profile_idx = data->n_profile;
234 data->profile_data[profile_idx] = profile_data;
236 data->active_profile = profile_idx;
241 void pa_tz_device_new_data_done(pa_tz_device_new_data *data) {
244 pa_xfree(data->type);
245 pa_xfree(data->name);
248 static int _check_valid_device_new_data(pa_tz_device_new_data *data) {
249 bool is_multi_profile;
252 if (data->type == NULL) {
253 pa_log_error("new data type is null");
257 is_multi_profile = device_type_is_multi_profile(data->type);
259 if (is_multi_profile == false && data->direction == DM_DEVICE_DIRECTION_NONE) {
260 pa_log_error("new data direction is none");
264 if (is_multi_profile == true && data->n_profile == 0) {
265 pa_log_error("multi profile type, but there is no profile");
268 if (is_multi_profile == false && data->n_profile > 0) {
269 pa_log_error("not multi profile type, but there are profile");
276 static pa_tz_profile* profile_new(char *profile_str, dm_device_direction_t direction,
277 pa_hashmap *playbacks, pa_hashmap *captures, bool use_internal_codec, pa_tz_device *device) {
278 pa_tz_profile *profile;
280 pa_log_info("New profile(%s) direction(%s), for device(%u)",
281 pa_strempty(profile_str), device_direction_to_string(direction), device->id);
283 profile = pa_xmalloc(sizeof(pa_tz_profile));
285 profile->profile = pa_xstrdup(profile_str);
286 profile->playback_devices = playbacks;
287 profile->capture_devices = captures;
288 profile->direction = direction;
289 profile->playback_state = DM_DEVICE_STATE_DEACTIVATED;
290 profile->capture_state = DM_DEVICE_STATE_DEACTIVATED;
291 profile->device = device;
292 profile->creation_time = pa_rtclock_now();
293 profile->use_internal_codec = use_internal_codec;
294 profile->sco_opened = false;
299 static void profile_free(pa_tz_profile *profile) {
303 pa_log_info("Free profile(%s) for device(%u)",
304 pa_strempty(profile->profile), profile->device->id);
306 pa_xfree(profile->profile);
308 if (profile->playback_devices)
309 pa_hashmap_free(profile->playback_devices);
310 if (profile->capture_devices)
311 pa_hashmap_free(profile->capture_devices);
316 static int profile_add_sink(pa_tz_profile *profile, const char *role, pa_sink *sink) {
319 if (pa_hashmap_put(profile->playback_devices, (void*)role, sink) < 0) {
320 pa_log_error("Failed to add sink : put sink failed");
326 static int profile_add_source(pa_tz_profile *profile, const char *role, pa_source *source) {
329 if (pa_hashmap_put(profile->capture_devices, (void*)role, source) < 0) {
330 pa_log_error("Failed to add source : put source failed");
336 static pa_sink* profile_get_sink(pa_tz_profile *profile, const char *role) {
340 if ((sink = pa_hashmap_get(profile->playback_devices, role)) == NULL) {
341 pa_log_warn("Failed to get sink for %s", role);
348 static pa_source* profile_get_source(pa_tz_profile *profile, const char *role) {
352 if ((source = pa_hashmap_get(profile->capture_devices, role)) == NULL) {
353 pa_log_warn("Failed to get source for %s", role);
360 static void profile_set_state(pa_tz_profile *profile, dm_device_direction_t direction, dm_device_state_t state) {
361 dm_device_state_t prev_state, new_state;
364 prev_state = COMPOUND_STATE(profile);
365 pa_log_debug("previous playback_state : %d, capture_state : %d => state %d", profile->playback_state, profile->capture_state, prev_state);
366 if (direction & DM_DEVICE_DIRECTION_IN)
367 profile->capture_state = state;
368 if (direction & DM_DEVICE_DIRECTION_OUT)
369 profile->playback_state = state;
370 new_state = COMPOUND_STATE(profile);
371 pa_log_debug("new playback_state : %d, capture_state : %d => state %d", profile->playback_state, profile->capture_state, new_state);
373 if (prev_state != new_state) {
374 notify_device_info_changed(profile->device, DM_DEVICE_CHANGED_INFO_STATE);
375 pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
379 static dm_device_state_t profile_get_state(pa_tz_profile *profile, dm_device_direction_t direction) {
382 if (direction == DM_DEVICE_DIRECTION_BOTH)
383 return COMPOUND_STATE(profile);
384 else if (direction == DM_DEVICE_DIRECTION_OUT)
385 return profile->playback_state;
386 else if (direction == DM_DEVICE_DIRECTION_IN)
387 return profile->capture_state;
389 return DM_DEVICE_STATE_DEACTIVATED;
392 static int profile_remove_sink_with_role(pa_tz_profile *profile, const char *role) {
396 sink = pa_hashmap_remove(profile->playback_devices, role);
397 return sink ? 0 : -1;
400 static int profile_remove_source_with_role(pa_tz_profile *profile, const char *role) {
404 source = pa_hashmap_remove(profile->capture_devices, role);
405 return source ? 0 : -1;
408 static int profile_remove_sink(pa_tz_profile *profile, pa_sink *sink) {
415 PA_HASHMAP_FOREACH_KEY(_sink, profile->playback_devices, state, role) {
417 return profile_remove_sink_with_role(profile, role);
423 static int profile_remove_source(pa_tz_profile *profile, pa_source *source) {
430 PA_HASHMAP_FOREACH_KEY(_source, profile->capture_devices, state, role) {
431 if (source == _source)
432 return profile_remove_source_with_role(profile, role);
439 pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
440 pa_tz_device *device;
443 pa_tz_profile *profile;
444 uint32_t profile_idx;
448 if (_check_valid_device_new_data(data) < 0) {
449 pa_log_error("Invalid device_new_data");
453 device = pa_xmalloc(sizeof(pa_tz_device));
454 device->list = data->list;
455 device->comm = data->comm;
456 device->dbus_conn = data->dbus_conn;
458 device->id = device_id_max_g++;
459 device->type = pa_xstrdup(data->type);
461 device->name = pa_xstrdup(data->name);
463 device->name = pa_xstrdup(data->type);
464 device->system_id = pa_xstrdup(data->system_id);
465 device->active_profile = 0;
467 pa_log_info("New device type(%s) id(%u) name(%s) system_id(%s)",
468 device->type, device->id, device->name, pa_strempty(device->system_id));
470 device->profiles = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
472 /* If multi profile type, get from data->profile_data */
473 if (device_type_is_multi_profile(data->type)) {
474 pa_tz_profile_new_data *pdata;
475 for (int i = 0; i < data->n_profile; i++) {
476 pdata = data->profile_data[i];
477 profile = profile_new(pdata->profile, pdata->direction,
478 pdata->playback_pcms, pdata->capture_pcms, pdata->use_internal_codec, device);
479 pa_idxset_put(device->profiles, profile, NULL);
481 device->active_profile = data->active_profile;
483 profile = profile_new(NULL, data->direction,
484 data->playback_pcms, data->capture_pcms, data->use_internal_codec, device);
485 pa_idxset_put(device->profiles, profile, NULL);
488 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
489 if (device_type_is_use_external_card(device->type, profile->profile)) {
490 if ((sink = profile_get_sink(profile, DEVICE_ROLE_NORMAL)))
491 sink->device_item = device;
492 if ((source = profile_get_source(profile, DEVICE_ROLE_NORMAL)))
493 source->device_item = device;
497 pa_idxset_put(device->list, device, NULL);
498 notify_device_connection_changed(device, true);
500 pa_tz_device_dump_info(device, PA_LOG_INFO);
505 static uint32_t _get_profile_idx(pa_tz_device *device, const char *profile_str) {
506 pa_tz_profile *profile;
507 uint32_t profile_idx;
510 pa_assert(device->profiles);
512 if (profile_str == NULL || pa_streq(profile_str, "")) {
513 pa_idxset_first(device->profiles, &profile_idx);
517 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
518 if (device_profile_is_equal(profile->profile, profile_str))
522 return PA_INVALID_INDEX;
525 static pa_tz_profile* _get_profile(pa_tz_device *device, const char *profile_str) {
526 pa_tz_profile *profile;
527 uint32_t profile_idx;
530 pa_assert(device->profiles);
532 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
533 if (device_profile_is_equal(profile->profile, profile_str))
540 static pa_tz_profile* _get_profile_by_idx(pa_tz_device *device, uint32_t profile_idx) {
541 pa_tz_profile *profile;
545 profile = pa_idxset_get_by_index(device->profiles, profile_idx);
547 pa_log_error("No profile(%u) in device(%u)", profile_idx, device->id);
553 static pa_tz_profile* _get_active_profile(pa_tz_device *device) {
554 pa_tz_profile *profile;
558 profile = _get_profile_by_idx(device, device->active_profile);
560 pa_log_error("Failed to find active profile(%u)", device->active_profile);
565 /* if noti_always is true, always noti this change without checking index
566 * if profile is null, set first profile as active */
567 int _set_active_profile(pa_tz_device *device, const char *profile, bool noti_always) {
568 uint32_t profile_idx, prev_active_idx;
572 pa_log_info("Set active profile, device(%u) profile(%s)",
573 device->id, pa_strempty(profile));
575 prev_active_idx = device->active_profile;
576 profile_idx = _get_profile_idx(device, profile);
577 if (profile_idx == PA_INVALID_INDEX) {
578 pa_log_error("index for profile(%s) is invalid", pa_strempty(profile));
581 device->active_profile = profile_idx;
582 pa_log_info("new active profile index %u", profile_idx);
584 /* Compare index only when check_idx is true */
585 if (noti_always || prev_active_idx != device->active_profile)
586 notify_device_info_changed(device, DM_DEVICE_CHANGED_INFO_IO_DIRECTION);
591 /* only for multi profile type */
592 int pa_tz_device_add_profile(pa_tz_device *device, pa_tz_profile_new_data *pdata, bool as_active) {
593 pa_tz_profile *profile;
596 pa_assert(device->profiles);
598 pa_log_info("device add profile, device(%u) profile(%s) as_active(%s)",
599 device->id, pa_strempty(pdata->profile), pa_yes_no(as_active));
601 if (device_type_is_multi_profile(device->type) == false) {
602 pa_log_error("Failed to add profile : not multi profile type");
605 if (pa_idxset_size(device->profiles) >= PROFILE_NUM_MAX) {
606 pa_log_error("Failed to add profile : Too many profiles");
610 profile = profile_new(pdata->profile, pdata->direction,
611 pdata->playback_pcms, pdata->capture_pcms, pdata->use_internal_codec, device);
612 pa_idxset_put(device->profiles, profile, NULL);
615 _set_active_profile(device, pdata->profile, true);
616 pa_tz_device_dump_info(device, PA_LOG_INFO);
621 int pa_tz_device_remove_profile(pa_tz_device *device, const char *profile_str) {
622 pa_tz_profile *profile;
623 uint32_t profile_idx, remove_idx;
625 unsigned profile_num;
628 pa_assert(device->profiles);
630 pa_log_info("device remove profile, device(%u) profile(%s)",
631 device->id, pa_strempty(profile_str));
633 if (device_type_is_multi_profile(device->type) == false) {
634 pa_log_error("Failed to add profile : not multi profile type");
638 if ((profile_num = pa_tz_device_get_profile_num(device)) <= 1) {
639 pa_log_error("This device have too small profiles %u, Should be freed", profile_num);
643 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
644 if (pa_safe_streq(profile->profile, profile_str)) {
645 pa_log_info("found matching profile to remove");
647 remove_idx = profile_idx;
652 pa_idxset_remove_by_index(device->profiles, remove_idx);
653 /* change active profile if removed one was active */
654 if (device->active_profile == remove_idx)
655 _set_active_profile(device, NULL, true);
656 pa_tz_device_dump_info(device, PA_LOG_INFO);
659 pa_log_warn("no matching profile to remove");
664 /* only for single profile type */
665 int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
666 pa_tz_profile *profile;
669 pa_assert(device_role_is_valid(role));
672 pa_log_info("device add sink, device(%u) role(%s) sink(%s)",
673 device->id, role, sink->name);
675 if (pa_tz_device_get_profile_num(device) > 1) {
676 pa_log_error("Failed to add sink : Too many profiles");
680 profile = pa_idxset_first(device->profiles, NULL);
682 if (profile_add_sink(profile, role, sink) < 0) {
683 pa_log_error("Failed to add sink : Can't add to profile");
690 int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
691 pa_tz_profile *profile;
694 pa_assert(device_role_is_valid(role));
697 pa_log_info("device add source, device(%u) role(%s) source(%s)",
698 device->id, role, source->name);
700 if (pa_tz_device_get_profile_num(device) > 1) {
701 pa_log_warn("Failed to add source : Too many profiles");
705 profile = pa_idxset_first(device->profiles, NULL);
707 if (profile_add_source(profile, role, source) < 0) {
708 pa_log_error("Failed to add source : Can't add to profile");
715 int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink) {
716 pa_tz_profile *profile;
718 uint32_t profile_idx;
723 pa_log_info("device remove sink, device(%u) sink(%s)",
724 device->id, sink->name);
726 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
727 removed &= profile_remove_sink(profile, sink);
732 int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source) {
733 pa_tz_profile *profile;
734 uint32_t profile_idx;
740 pa_log_info("device remove source, device(%u) source(%s)",
741 device->id, source->name);
743 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
744 removed &= profile_remove_source(profile, source);
749 int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role) {
750 pa_tz_profile *profile;
751 uint32_t profile_idx;
755 pa_assert(device_role_is_valid(role));
757 pa_log_info("device remove sink with role, device(%u) role(%s)",
760 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
761 removed &= profile_remove_sink_with_role(profile, role);
766 int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role) {
767 pa_tz_profile *profile;
768 uint32_t profile_idx;
772 pa_assert(device_role_is_valid(role));
774 pa_log_info("device remove source with role, device(%u) role(%s)",
777 PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
778 removed &= profile_remove_source_with_role(profile, role);
783 /* only for multi profile */
784 int pa_tz_device_profile_add_sink(pa_tz_device *device, const char *profile_str, const char *role, pa_sink *sink) {
785 pa_tz_profile *profile;
789 pa_log_info("device profile add sink, device(%u) profile(%s) role(%s) sink(%s)",
790 device->id, pa_strempty(profile_str), role, sink->name);
792 if ((profile = _get_profile(device, profile_str)) == NULL) {
793 pa_log_error("Can't get profile %s", profile_str);
797 if (profile_add_sink(profile, role, sink) < 0) {
798 pa_log_error("Can't add to profile");
805 int pa_tz_device_profile_add_source(pa_tz_device *device, const char *profile_str, const char *role, pa_source *source) {
806 pa_tz_profile *profile;
810 pa_log_info("device profile add source, device(%u) profile(%s) role(%s) source(%s)",
811 device->id, pa_strempty(profile_str), role, source->name);
813 if ((profile = _get_profile(device, profile_str)) == NULL) {
814 pa_log_error("Can't get profile %s", profile_str);
818 if (profile_add_source(profile, role, source) < 0) {
819 pa_log_error("Can't add to profile");
826 int pa_tz_device_profile_remove_sink(pa_tz_device *device, const char *profile_str, pa_sink *sink) {
827 pa_tz_profile *profile;
831 pa_log_info("device profile remove sink, device(%u) profile(%s) sink(%s)",
832 device->id, pa_strempty(profile_str), sink->name);
834 if ((profile = _get_profile(device, profile_str)) == NULL) {
835 pa_log_error("Can't get profile %s", profile_str);
839 if (profile_remove_sink(profile, sink) < 0) {
840 pa_log_error("Can't remove from profile");
847 int pa_tz_device_profile_remove_source(pa_tz_device *device, const char *profile_str, pa_source *source) {
848 pa_tz_profile *profile;
852 pa_log_info("device profile remove source, device(%u) profile(%s) source(%s)",
853 device->id, pa_strempty(profile_str), source->name);
855 if ((profile = _get_profile(device, profile_str)) == NULL) {
856 pa_log_error("Can't get profile %s", profile_str);
860 if (profile_remove_source(profile, source) < 0) {
861 pa_log_error("Can't remove from profile");
868 int pa_tz_device_profile_remove_sink_with_role(pa_tz_device *device, const char *profile_str, const char *role) {
869 pa_tz_profile *profile;
872 pa_assert(device_role_is_valid(role));
874 pa_log_info("device profile remove sink with role, device(%u) profile(%s) role(%s)",
875 device->id, pa_strempty(profile_str), role);
877 if ((profile = _get_profile(device, profile_str)) == NULL) {
878 pa_log_error("Can't get profile %s", profile_str);
882 if (profile_remove_sink_with_role(profile, role) < 0) {
883 pa_log_error("Can't remove from profile");
890 int pa_tz_device_profile_remove_source_with_role(pa_tz_device *device, const char *profile_str, const char *role) {
891 pa_tz_profile *profile;
894 pa_assert(device_role_is_valid(role));
896 pa_log_info("device profile remove source with role, device(%u) profile(%s) role(%s)",
897 device->id, pa_strempty(profile_str), role);
899 if ((profile = _get_profile(device, profile_str)) == NULL) {
900 pa_log_error("Can't get profile %s", profile_str);
904 if (profile_remove_source_with_role(profile, role) < 0) {
905 pa_log_error("Can't remove from profile");
912 pa_sink* pa_tz_device_profile_get_sink(pa_tz_device *device, const char *profile_str, const char *role) {
914 pa_tz_profile *profile;
918 pa_log_info("device profile get sink, device(%u) profile(%s) role(%s)",
919 device->id, pa_strempty(profile_str), role);
921 if ((profile = _get_profile(device, profile_str)) == NULL) {
922 pa_log_error("Can't get profile %s", profile_str);
926 if ((sink = profile_get_sink(profile, role)) == NULL) {
927 pa_log_error("Can't get sink from profile");
934 pa_source* pa_tz_device_profile_get_source(pa_tz_device *device, const char *profile_str, const char *role) {
936 pa_tz_profile *profile;
940 pa_log_info("device profile get source, device(%u) profile(%s) role(%s)",
941 device->id, pa_strempty(profile_str), role);
943 if ((profile = _get_profile(device, profile_str)) == NULL) {
944 pa_log_error("Can't get profile %s", profile_str);
948 if ((source = profile_get_source(profile, role)) == NULL) {
949 pa_log_error("Can't get source from profile");
956 void pa_tz_device_free(pa_tz_device *device) {
959 pa_log_info("Free device type(%s) id(%u) name(%s) system_id(%s)",
960 device->type, device->id, device->name, device->system_id);
962 pa_tz_device_dump_info(device, PA_LOG_INFO);
964 pa_idxset_remove_by_data(device->list, device, NULL);
965 notify_device_connection_changed(device, false);
967 pa_xfree(device->type);
968 pa_xfree(device->name);
969 pa_xfree(device->system_id);
971 pa_idxset_free(device->profiles, (pa_free_cb_t)profile_free);
976 /* pa_tz_profile_new_data */
977 void pa_tz_profile_new_data_init(pa_tz_profile_new_data *profile_data) {
978 pa_assert(profile_data);
980 profile_data->profile = NULL;
981 profile_data->direction = DM_DEVICE_DIRECTION_NONE;
983 profile_data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
984 profile_data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
987 void pa_tz_profile_new_data_set_direction(pa_tz_profile_new_data *profile_data, dm_device_direction_t direction) {
988 pa_assert(profile_data);
990 profile_data->direction = direction;
993 void pa_tz_profile_new_data_set_profile(pa_tz_profile_new_data *profile_data, const char *profile) {
994 pa_assert(profile_data);
996 profile_data->profile = pa_xstrdup(profile);
999 void pa_tz_profile_new_data_set_use_internal_codec(pa_tz_profile_new_data *profile_data, bool use_internal_codec) {
1000 pa_assert(profile_data);
1001 profile_data->use_internal_codec = use_internal_codec;
1004 void pa_tz_profile_new_data_add_sink(pa_tz_profile_new_data *profile_data, const char *role, pa_sink *sink) {
1005 pa_assert(profile_data);
1007 pa_hashmap_put(profile_data->playback_pcms, (void*)role, sink);
1010 void pa_tz_profile_new_data_add_source(pa_tz_profile_new_data *profile_data, const char *role, pa_source *source) {
1011 pa_assert(profile_data);
1013 pa_hashmap_put(profile_data->capture_pcms, (void*)role, source);
1016 void pa_tz_profile_new_data_done(pa_tz_profile_new_data *profile_data) {
1017 pa_assert(profile_data);
1019 pa_xfree(profile_data->profile);
1023 pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role) {
1024 pa_tz_profile *profile;
1028 pa_assert(profile = _get_active_profile(device));
1030 pa_log_info("device get sink, device(%u) role(%s), active-profile(%s)",
1031 device->id, role, pa_strempty(profile->profile));
1033 if ((sink = profile_get_sink(profile, role)) == NULL) {
1034 pa_log_error("Failed to get sink from profile");
1041 pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
1042 pa_tz_profile *profile;
1046 pa_assert(profile = _get_active_profile(device));
1048 pa_log_info("device get source, device(%u) role(%s), active-profile(%s)",
1049 device->id, role, pa_strempty(profile->profile));
1051 if ((source = profile_get_source(profile, role)) == NULL) {
1052 pa_log_error("Failed to get source from profile");
1059 void pa_tz_device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state) {
1060 pa_tz_profile *profile;
1063 pa_assert(profile = _get_active_profile(device));
1065 pa_log_info("device set state, device(%u) type(%s) active-profile(%s) direction(%s) -> %d",
1066 device->id, device->type, pa_strempty(profile->profile), device_direction_to_string(direction), state);
1067 profile_set_state(profile, direction, state);
1070 dm_device_state_t pa_tz_device_get_state(pa_tz_device *device, dm_device_direction_t direction) {
1071 pa_tz_profile *profile;
1074 pa_assert(profile = _get_active_profile(device));
1076 return profile_get_state(profile, direction);
1079 uint32_t pa_tz_device_get_id(pa_tz_device *device) {
1085 char* pa_tz_device_get_type(pa_tz_device *device) {
1088 return device->type;
1091 char* pa_tz_device_get_name(pa_tz_device *device) {
1094 return device->name;
1097 char* pa_tz_device_get_system_id(pa_tz_device *device) {
1100 return device->system_id;
1103 char* pa_tz_device_get_profile(pa_tz_device *device) {
1104 pa_tz_profile *profile;
1107 pa_assert(profile = _get_active_profile(device));
1109 return profile->profile;
1112 dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device) {
1113 pa_tz_profile *profile;
1116 pa_assert(profile = _get_active_profile(device));
1118 return profile->direction;
1121 pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device) {
1122 pa_tz_profile *profile;
1125 pa_assert(profile = _get_active_profile(device));
1127 return profile->creation_time;
1130 bool pa_tz_device_is_use_internal_codec(pa_tz_device *device) {
1131 pa_tz_profile *profile;
1134 pa_assert(profile = _get_active_profile(device));
1136 return profile->use_internal_codec;
1139 unsigned pa_tz_device_get_profile_num(pa_tz_device *device) {
1141 pa_assert(device->profiles);
1143 return pa_idxset_size(device->profiles);
1146 bool pa_tz_device_have_profile(pa_tz_device *device, const char *profile) {
1149 if (_get_profile(device, profile) == NULL)
1155 static int method_call_bt_sco(pa_dbus_connection *conn, bool onoff) {
1156 DBusMessage *msg, *reply;
1162 method = onoff ? "Play" : "Stop";
1163 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
1164 pa_log_error("dbus method call failed");
1168 dbus_error_init(&err);
1169 if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
1170 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
1171 dbus_error_free(&err);
1175 dbus_message_unref(reply);
1179 static int method_call_bt_sco_get_property(pa_dbus_connection *conn, bool *is_wide_band, bool *nrec) {
1180 DBusMessage *msg, *reply;
1181 DBusMessageIter reply_iter, reply_iter_entry;
1184 const char *property;
1188 if (!is_wide_band && !nrec) {
1192 if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, "GetProperties"))) {
1193 pa_log_error("dbus method call failed");
1197 dbus_error_init(&err);
1198 if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
1199 pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
1200 dbus_error_free(&err);
1204 dbus_message_iter_init(reply, &reply_iter);
1206 if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
1207 pa_log_error("Cannot get reply argument");
1211 dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
1213 while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
1214 DBusMessageIter dict_entry, dict_entry_val;
1215 dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
1216 dbus_message_iter_get_basic(&dict_entry, &property);
1217 pa_log_debug("String received = %s", property);
1219 if (pa_streq("codec", property) && is_wide_band) {
1220 dbus_message_iter_next(&dict_entry);
1221 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
1222 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_UINT32)
1224 dbus_message_iter_get_basic(&dict_entry_val, &codec);
1225 pa_log_debug("Codec = [%d]", codec);
1226 *is_wide_band = (codec == BT_MSBC_CODEC_ID) ? true : false;
1227 } else if (pa_streq("nrec", property) && nrec) {
1228 dbus_message_iter_next(&dict_entry);
1229 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
1230 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_BOOLEAN)
1232 dbus_message_iter_get_basic(&dict_entry_val, nrec);
1233 pa_log_debug("nrec= [%d]", *nrec);
1236 dbus_message_iter_next(&reply_iter_entry);
1240 dbus_message_unref(reply);
1244 /* only for bt device, which have sco profile */
1245 int pa_tz_device_sco_open(pa_tz_device *device) {
1246 pa_tz_profile *profile;
1249 pa_assert(device->dbus_conn);
1251 pa_log_info("BT SCO Open for device(%u)", device->id);
1252 if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
1253 pa_log_error("Not BT device");
1256 if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
1257 pa_log_error("No BT SCO profile");
1261 if (profile->sco_opened) {
1262 pa_log_warn("SCO already opened");
1266 if (method_call_bt_sco(device->dbus_conn, true) < 0) {
1267 pa_log_error("Failed to bt sco on");
1271 profile->sco_opened = true;
1272 _set_active_profile(device, DEVICE_PROFILE_BT_SCO, false);
1273 pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
1274 pa_log_info("BT SCO Open - SUCCESS");
1279 /* only for bt device, which have sco profile */
1280 int pa_tz_device_sco_close(pa_tz_device *device) {
1281 pa_tz_profile *profile;
1284 pa_log_info("BT SCO Close for device(%u)", device->id);
1286 if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
1287 pa_log_error("Not BT device");
1290 if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
1291 pa_log_error("No BT SCO profile");
1295 if (profile->sco_opened == false) {
1296 pa_log_warn("SCO not opened");
1300 if (method_call_bt_sco(device->dbus_conn, false) < 0) {
1301 pa_log_error("Failed to bt sco on");
1305 profile->sco_opened = false;
1306 if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_A2DP))
1307 _set_active_profile(device, DEVICE_PROFILE_BT_A2DP, false);
1308 pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
1309 pa_log_info("BT SCO Close - Success");
1314 /* only for bt device, which have sco profile */
1315 int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec) {
1318 pa_log_info("BT SCO get property for device(%u)", device->id);
1319 if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
1320 pa_log_error("Not BT device");
1323 if ((_get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
1324 pa_log_error("No BT SCO profile");
1328 if (method_call_bt_sco_get_property(device->dbus_conn, is_wide_band, nrec) < 0) {
1329 pa_log_error("Failed to get BT SCO Property");
1333 pa_log_info("BT SCO Get Property - Success, is wide band : %s, nrec : %s", pa_yes_no(is_wide_band), pa_yes_no(nrec));
1338 /* only for bt device */
1339 int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t *status) {
1340 pa_tz_profile *profile;
1343 pa_log_info("BT SCO get status for device(%u)", device->id);
1344 if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
1345 pa_log_error("Not BT device");
1348 if (status == NULL) {
1349 pa_log_error("invalid parameter");
1353 if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO))) {
1354 if (profile->sco_opened == false)
1355 *status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
1357 *status = DM_DEVICE_BT_SCO_STATUS_OPENED;
1359 *status = DM_DEVICE_BT_SCO_STATUS_DISCONNECTED;
1362 pa_log_debug("BT SCO Get Status, %d", *status);