2204430083820a863446ca0a8f2845ba849349d6
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / tizen-device.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <ctype.h>
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>
12
13 #include "tizen-device.h"
14
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"
18
19 #define BT_CVSD_CODEC_ID 1 // narrow-band
20 #define BT_MSBC_CODEC_ID 2 // wide-band
21
22 struct pa_intset {
23     int values[MAX_INTSET_NUM];
24     uint32_t write_index;
25     uint32_t read_index;
26 };
27
28 int device_id_max_g = 1;
29 uint32_t event_id_max_g = 1;
30
31 static uint32_t _new_event_id() {
32     return event_id_max_g++;
33 }
34
35 int pa_intset_put(pa_intset *s, int val) {
36     int i;
37
38     pa_assert(s);
39
40     if (s->write_index >= MAX_INTSET_NUM)
41         return -1;
42
43     for(i = 0; i < s->write_index; i++) {
44         if (s->values[i] == val)
45             return -1;
46     }
47
48     s->values[s->write_index++] = val;
49
50     return 0;
51 }
52
53 pa_intset* pa_intset_new() {
54     pa_intset *s;
55
56     s = pa_xmalloc0(sizeof(pa_intset));
57     s->write_index = 0;
58     s->read_index = 0;
59
60     return s;
61 }
62
63 void pa_intset_free(pa_intset *s) {
64     pa_assert(s);
65     pa_xfree(s);
66 }
67
68 int pa_intset_first(pa_intset *s, int *val) {
69     pa_assert(s);
70     pa_assert(val);
71
72     if (s->write_index == 0)
73         return -1;
74
75     s->read_index = 0;
76     *val = s->values[s->read_index++];
77
78     return 0;
79 }
80
81 int pa_intset_next(pa_intset *s, int *val) {
82     pa_assert(s);
83     pa_assert(val);
84
85     if (s->read_index >= s->write_index)
86         return -1;
87
88     *val = s->values[s->read_index++];
89
90     return 0;
91 }
92
93 static char* get_playback_list_str(pa_hashmap *playback_devices) {
94     pa_sink *sink = NULL;
95     void *state;
96     const char *role;
97     pa_strbuf *buf;
98
99     if (!playback_devices || !pa_hashmap_size(playback_devices))
100         return NULL;
101
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);
106
107     return pa_strbuf_to_string_free(buf);
108 }
109
110 static char* get_capture_list_str(pa_hashmap *capture_devices) {
111     pa_source *source = NULL;
112     void *state;
113     const char *role;
114     pa_strbuf *buf;
115
116     if (!capture_devices || !pa_hashmap_size(capture_devices))
117         return NULL;
118
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);
123
124     return pa_strbuf_to_string_free(buf);
125 }
126
127 static char* _device_get_info_str(pa_tz_device *device) {
128     pa_strbuf *buf;
129     char *playback_str, *capture_str;
130
131     if (!device)
132         return NULL;
133
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     }
147     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO))
148         pa_strbuf_printf(buf, "    SCO opened   : %s\n", pa_yes_no(device->sco_opened));
149     playback_str = get_playback_list_str(device->playback_devices);
150     capture_str = get_capture_list_str(device->capture_devices);
151
152     if (playback_str)
153         pa_strbuf_puts(buf, playback_str);
154     if (capture_str)
155         pa_strbuf_puts(buf, capture_str);
156
157     pa_xfree(playback_str);
158     pa_xfree(capture_str);
159
160     return pa_strbuf_to_string_free(buf);
161 }
162
163
164 void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level) {
165     char *info;
166
167     if (!device)
168         return;
169
170     if ((info = _device_get_info_str(device))) {
171         pa_logl(log_level, "%s", info);
172         pa_xfree(info);
173     }
174 }
175
176 static void notify_device_connection_changed(pa_tz_device *device, bool connected) {
177     pa_tz_device_hook_data_for_conn_changed hook_data;
178
179     hook_data.event_id = _new_event_id();
180     hook_data.is_connected = connected;
181     hook_data.device = device;
182
183     pa_log_info("Fire hook for device connection changed, device(%s/%u) %s",
184             device->type, device->id, connected ? "connected" : "disconnected");
185     pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), &hook_data);
186 }
187
188 static void notify_device_state_changed(pa_tz_device *device, dm_device_state_t state) {
189     pa_tz_device_hook_data_for_state_changed hook_data;
190
191     hook_data.event_id = _new_event_id();
192     hook_data.activated = (state == DM_DEVICE_STATE_ACTIVATED) ? true : false;
193     hook_data.device = device;
194
195     pa_log_info("Fire hook for device state changed, device(%s/%u) %s",
196             device->type, device->id, hook_data.activated ? "Activated" : "De-activated");
197     pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED), &hook_data);
198 }
199
200 static void notify_device_running_changed(pa_tz_device *device, bool running) {
201     pa_tz_device_hook_data_for_running_changed hook_data;
202
203     hook_data.event_id = _new_event_id();
204     hook_data.is_running = running;
205     hook_data.device = device;
206
207     pa_log_info("Fire hook for device running changed, device(%s/%u) %s",
208             device->type, device->id, hook_data.is_running ? "Running" : "Not running");
209     pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED), &hook_data);
210 }
211
212 /* pa_tz_device_new_data */
213 void pa_tz_device_new_data_init(pa_tz_device_new_data *data, pa_idxset *list,
214         pa_communicator *comm, pa_dbus_connection *conn) {
215     pa_assert(data);
216     pa_assert(list);
217     pa_assert(comm);
218
219     data->list = list;
220     data->comm = comm;
221     data->dbus_conn = conn;
222
223     data->type = NULL;
224     data->name = NULL;
225     data->system_id = NULL;
226     data->vendor_id = -1;
227     data->product_id = -1;
228     data->direction = DM_DEVICE_DIRECTION_NONE;
229
230     data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
231     data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
232 }
233
234 void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type) {
235     pa_assert(data);
236
237     data->type = pa_xstrdup(type);
238 }
239
240 void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name) {
241     pa_assert(data);
242
243     data->name = pa_xstrdup(name);
244 }
245
246 void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction) {
247     pa_assert(data);
248
249     data->direction = direction;
250 }
251 /* only for external? */
252 void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id) {
253     pa_assert(data);
254
255     data->system_id = pa_xstrdup(system_id);
256 }
257
258 void pa_tz_device_new_data_set_vendor_id(pa_tz_device_new_data *data, int vendor_id) {
259     pa_assert(data);
260
261     data->vendor_id = vendor_id;
262 }
263
264 void pa_tz_device_new_data_set_product_id(pa_tz_device_new_data *data, int product_id) {
265     pa_assert(data);
266
267     data->product_id = product_id;
268 }
269
270 void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec) {
271     pa_assert(data);
272
273     data->use_internal_codec = use_internal_codec;
274 }
275
276 void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink) {
277     pa_assert(data);
278
279     pa_hashmap_put(data->playback_pcms, (void*)role, sink);
280 }
281
282 void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source) {
283     pa_assert(data);
284
285     pa_hashmap_put(data->capture_pcms, (void*)role, source);
286 }
287
288 void pa_tz_device_new_data_done(pa_tz_device_new_data *data) {
289     pa_assert(data);
290
291     pa_xfree(data->type);
292     pa_xfree(data->name);
293 }
294
295 static int _check_valid_device_new_data(pa_tz_device_new_data *data) {
296     pa_assert(data);
297
298     if (data->type == NULL) {
299         pa_log_error("new data type is null");
300         return -1;
301     }
302
303     if (data->direction == DM_DEVICE_DIRECTION_NONE) {
304         pa_log_error("new data direction is none");
305         return -1;
306     }
307
308     return 0;
309 }
310
311 static int device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
312     pa_assert(device);
313     pa_assert(device->playback_devices);
314
315     if (pa_hashmap_put(device->playback_devices, (void*)role, sink) < 0) {
316         pa_log_error("Failed to add sink : put sink failed");
317         return -1;
318     }
319     return 0;
320 }
321
322 static int device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
323     pa_assert(device);
324     pa_assert(device->capture_devices);
325
326     if (pa_hashmap_put(device->capture_devices, (void*)role, source) < 0) {
327         pa_log_error("Failed to add source : put source failed");
328         return -1;
329     }
330     return 0;
331 }
332
333 static pa_sink* device_get_sink(pa_tz_device *device, const char *role) {
334     pa_sink *sink;
335     pa_assert(device);
336     pa_assert(device->playback_devices);
337
338     if ((sink = pa_hashmap_get(device->playback_devices, role)) == NULL) {
339         pa_log_warn("Failed to get sink for %s", role);
340         return NULL;
341     }
342
343     return sink;
344 }
345
346 static pa_source* device_get_source(pa_tz_device *device, const char *role) {
347     pa_source *source;
348     pa_assert(device);
349     pa_assert(device->capture_devices);
350
351     if ((source = pa_hashmap_get(device->capture_devices, role)) == NULL) {
352         pa_log_warn("Failed to get source for %s", role);
353         return NULL;
354     }
355
356     return source;
357 }
358
359 static void device_set_state(pa_tz_device *device, dm_device_state_t new_state) {
360     pa_assert(device);
361
362     if (device->state != new_state) {
363         pa_log_debug("change state %d -> %d", device->state, new_state);
364         device->state = new_state;
365         notify_device_state_changed(device, new_state);
366         pa_tz_device_dump_info(device, PA_LOG_DEBUG);
367     } else {
368         pa_log_debug("same state, not change it");
369     }
370 }
371
372 static dm_device_state_t device_get_state(pa_tz_device *device) {
373     pa_assert(device);
374     return device->state;
375 }
376
377 static void device_set_running_and_notify(pa_tz_device *device, bool running) {
378     pa_assert(device);
379
380     if (device->is_running != running) {
381         pa_log_debug("change running state %d -> %d", device->is_running, running);
382         device->is_running = running;
383         notify_device_running_changed(device, running);
384         pa_tz_device_dump_info(device, PA_LOG_DEBUG);
385     } else {
386         pa_log_debug("same running state, not change it");
387     }
388 }
389
390 static int device_remove_sink_with_role(pa_tz_device *device, const char *role) {
391     pa_sink *sink;
392     pa_assert(device);
393
394     sink = pa_hashmap_remove(device->playback_devices, role);
395     return sink ? 0 : -1;
396 }
397
398 static int device_remove_source_with_role(pa_tz_device *device, const char *role) {
399     pa_source *source;
400     pa_assert(device);
401
402     source = pa_hashmap_remove(device->capture_devices, role);
403     return source ? 0 : -1;
404 }
405
406 static int device_remove_sink(pa_tz_device *device, pa_sink *sink) {
407     pa_sink *_sink;
408     void *state;
409     char *role;
410
411     pa_assert(device);
412
413     PA_HASHMAP_FOREACH_KV(role, _sink, device->playback_devices, state) {
414         if (sink == _sink)
415             return device_remove_sink_with_role(device, role);
416     }
417
418     return -1;
419 }
420
421 static int device_remove_source(pa_tz_device *device, pa_source *source) {
422     pa_source *_source;
423     void *state;
424     char *role;
425
426     pa_assert(device);
427
428     PA_HASHMAP_FOREACH_KV(role, _source, device->capture_devices, state) {
429         if (source == _source)
430             return device_remove_source_with_role(device, role);
431     }
432
433     return -1;
434 }
435
436 /* pa_tz_device */
437 pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
438     pa_tz_device *device;
439     pa_sink *sink;
440     pa_source *source;
441
442     pa_assert(data);
443
444     if (_check_valid_device_new_data(data) < 0) {
445         pa_log_error("Invalid device_new_data");
446         return NULL;
447     }
448
449     device = pa_xmalloc(sizeof(pa_tz_device));
450     device->list = data->list;
451     device->comm = data->comm;
452     device->dbus_conn = data->dbus_conn;
453
454     device->id = device_id_max_g++;
455     device->type = pa_xstrdup(data->type);
456     if (data->name)
457         device->name = pa_xstrdup(data->name);
458     else
459         device->name = pa_xstrdup(data->type);
460     device->system_id = pa_xstrdup(data->system_id);
461     device->vendor_id = data->vendor_id;
462     device->product_id = data->product_id;
463
464     pa_log_info("New device type(%s) id(%u) name(%s) system_id(%s) vendor_id(%04x) product_id(%04x)",
465             device->type, device->id, device->name, pa_strempty(device->system_id),
466             device->vendor_id, device->product_id);
467
468     device->playback_devices = data->playback_pcms;
469     device->capture_devices = data->capture_pcms;
470     device->direction = data->direction;
471     device->state = DM_DEVICE_STATE_DEACTIVATED;
472     device->creation_time = pa_rtclock_now();
473     device->use_internal_codec = data->use_internal_codec;
474     device->sco_opened = false;
475     device->is_running = false;
476
477     if (device_type_is_use_external_card(device->type)) {
478         if ((sink = device_get_sink(device, DEVICE_ROLE_NORMAL)))
479             sink->device_item = device;
480         if ((source = device_get_source(device, DEVICE_ROLE_NORMAL)))
481             source->device_item = device;
482     }
483
484     pa_idxset_put(device->list, device, NULL);
485     notify_device_connection_changed(device, true);
486
487     pa_tz_device_dump_info(device, PA_LOG_INFO);
488
489     return device;
490 }
491
492 int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
493     pa_assert(device);
494     pa_assert(device_role_is_valid(role));
495     pa_assert(sink);
496
497     pa_log_info("device add sink, device(%u) role(%s) sink(%s)",
498             device->id, role, sink->name);
499
500     if (device_add_sink(device, role, sink) < 0) {
501         pa_log_error("Failed to add sink : Can't add to device");
502         return -1;
503     }
504
505     return 0;
506 }
507
508 int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
509     pa_assert(device);
510     pa_assert(device_role_is_valid(role));
511     pa_assert(source);
512
513     pa_log_info("device add source, device(%u) role(%s) source(%s)",
514             device->id, role, source->name);
515
516     if (device_add_source(device, role, source) < 0) {
517         pa_log_error("Failed to add source : Can't add to device");
518         return -1;
519     }
520
521     return 0;
522 }
523
524 int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink) {
525     pa_assert(device);
526     pa_assert(sink);
527
528     pa_log_info("device remove sink, device(%u) sink(%s)",
529             device->id, sink->name);
530
531     return device_remove_sink(device, sink);
532 }
533
534 int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source) {
535     pa_assert(device);
536     pa_assert(source);
537
538     pa_log_info("device remove source, device(%u) source(%s)",
539             device->id, source->name);
540
541     return device_remove_source(device, source);
542 }
543
544 int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role) {
545     pa_assert(device);
546     pa_assert(device_role_is_valid(role));
547
548     pa_log_info("device remove sink with role, device(%u) role(%s)",
549             device->id, role);
550
551     return device_remove_sink_with_role(device, role);
552 }
553
554 int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role) {
555     pa_assert(device);
556     pa_assert(device_role_is_valid(role));
557
558     pa_log_info("device remove source with role, device(%u) role(%s)",
559             device->id, role);
560
561     return device_remove_source_with_role(device, role);
562 }
563
564 void pa_tz_device_free(pa_tz_device *device) {
565     pa_sink *sink;
566     pa_source *source;
567     void *state;
568
569     pa_assert(device);
570
571     pa_log_info("Free device type(%s) id(%u) name(%s) system_id(%s)",
572             device->type, device->id, device->name, device->system_id);
573
574     pa_tz_device_dump_info(device, PA_LOG_INFO);
575
576     pa_idxset_remove_by_data(device->list, device, NULL);
577
578     if (device->playback_devices)
579         PA_HASHMAP_FOREACH(sink, device->playback_devices, state)
580             sink->device_item = NULL;
581
582     if (device->capture_devices)
583         PA_HASHMAP_FOREACH(source, device->capture_devices, state)
584             source->device_item = NULL;
585
586     notify_device_connection_changed(device, false);
587
588     pa_xfree(device->type);
589     pa_xfree(device->name);
590     pa_xfree(device->system_id);
591
592     pa_xfree(device);
593 }
594
595 /* exported api */
596 pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role) {
597     pa_sink *sink;
598
599     pa_assert(device);
600
601     pa_log_info("device get sink, device(%u) role(%s)", device->id, role);
602
603     if ((sink = device_get_sink(device, role)) == NULL) {
604         pa_log_error("Failed to get sink from device");
605         return NULL;
606     }
607
608     return sink;
609 }
610
611 pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
612     pa_source *source;
613
614     pa_assert(device);
615
616     pa_log_info("device get source, device(%u) role(%s)",
617             device->id, role);
618
619     if ((source = device_get_source(device, role)) == NULL) {
620         pa_log_error("Failed to get source from device");
621         return NULL;
622     }
623
624     return source;
625 }
626
627 /* TODO : Change param dm_device_state_t to bool or pa_tz_device_state_t,
628  * Because this state represent pa_tz_device's own state */
629 void pa_tz_device_set_state(pa_tz_device *device, dm_device_state_t state) {
630     pa_assert(device);
631
632     pa_log_info("device set state, device(%u) type(%s) -> %d",
633             device->id, device->type, state);
634     device_set_state(device, state);
635 }
636
637 dm_device_state_t pa_tz_device_get_state(pa_tz_device *device) {
638     pa_assert(device);
639
640     return device_get_state(device);
641 }
642
643 void pa_tz_device_set_running_and_notify(pa_tz_device *device, bool running) {
644     pa_assert(device);
645
646     pa_log_info("device set running, device(%u) type(%s) -> %d (0:not running, 1:running)",
647                 device->id, device->type, running);
648     device_set_running_and_notify(device, running);
649 }
650
651 bool pa_tz_device_is_running(pa_tz_device *device) {
652     pa_assert(device);
653
654     return device->is_running;
655 }
656
657 uint32_t pa_tz_device_get_id(pa_tz_device *device) {
658     pa_assert(device);
659
660     return device->id;
661 }
662
663 char* pa_tz_device_get_type(pa_tz_device *device) {
664     pa_assert(device);
665
666     return device->type;
667 }
668
669 char* pa_tz_device_get_name(pa_tz_device *device) {
670     pa_assert(device);
671
672     return device->name;
673 }
674
675 char* pa_tz_device_get_system_id(pa_tz_device *device) {
676     pa_assert(device);
677
678     return device->system_id;
679 }
680
681 int pa_tz_device_get_vendor_id(pa_tz_device *device) {
682     pa_assert(device);
683
684     return device->vendor_id;
685 }
686
687 int pa_tz_device_get_product_id(pa_tz_device *device) {
688     pa_assert(device);
689
690     return device->product_id;
691 }
692
693 dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device) {
694     pa_assert(device);
695
696     return device->direction;
697 }
698
699 pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device) {
700     pa_assert(device);
701
702     return device->creation_time;
703 }
704
705 bool pa_tz_device_is_use_internal_codec(pa_tz_device *device) {
706     pa_assert(device);
707
708     return device->use_internal_codec;
709 }
710
711 bool pa_tz_device_is_all_suspended(pa_tz_device *device) {
712     pa_sink *sink;
713     pa_source *source;
714     void *state;
715
716     PA_HASHMAP_FOREACH(sink, device->playback_devices, state) {
717         if (pa_sink_get_state(sink) != PA_SINK_SUSPENDED)
718             return false;
719     }
720
721     PA_HASHMAP_FOREACH(source, device->capture_devices, state) {
722         if (pa_source_get_state(source) != PA_SOURCE_SUSPENDED)
723             return false;
724     }
725
726     return true;
727 }
728
729 pa_intset* pa_tz_device_get_stream_list(pa_tz_device *device) {
730     pa_sink *sink;
731     pa_source *source;
732     pa_sink_input *input;
733     pa_source_output *output;
734     void *state;
735     const char *p_id_str;
736     int32_t p_id;
737     uint32_t idx;
738     pa_intset *stream_id_set;
739
740     pa_assert(device);
741
742     stream_id_set = pa_intset_new();
743     PA_HASHMAP_FOREACH(sink, device->playback_devices, state) {
744         PA_IDXSET_FOREACH(input, sink->inputs, idx) {
745             p_id_str = pa_proplist_gets(input->proplist, PA_PROP_MEDIA_PARENT_ID);
746             if (p_id_str && !pa_atoi(p_id_str, &p_id)) {
747                 pa_intset_put(stream_id_set, p_id);
748             } else {
749                 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
750             }
751         }
752     }
753     PA_HASHMAP_FOREACH(source, device->capture_devices, state) {
754         PA_IDXSET_FOREACH(output, source->outputs, idx) {
755             p_id_str = pa_proplist_gets(output->proplist, PA_PROP_MEDIA_PARENT_ID);
756             if (p_id_str && !pa_atoi(p_id_str, &p_id)) {
757                 pa_intset_put(stream_id_set, p_id);
758             } else {
759                 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
760             }
761         }
762     }
763
764     return stream_id_set;
765 }
766
767 static int method_call_bt_sco_enable_pcm(pa_dbus_connection *conn, bool enable) {
768     DBusMessage *msg, *reply;
769     DBusError err;
770     const char *method = "SetVoiceDial";
771
772     pa_assert(conn);
773
774     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
775         pa_log_error("dbus method call failed");
776         return -1;
777     }
778
779     dbus_error_init(&err);
780     dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_INVALID);
781     if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
782         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
783         dbus_error_free(&err);
784         return -1;
785     }
786
787     dbus_message_unref(reply);
788     return 0;
789 }
790
791 static int method_call_bt_sco(pa_dbus_connection *conn, bool onoff) {
792     DBusMessage *msg, *reply;
793     DBusError err;
794     const char *method;
795
796     pa_assert(conn);
797
798     method = onoff ? "Play" : "Stop";
799     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
800         pa_log_error("dbus method call failed");
801         return -1;
802     }
803
804     dbus_error_init(&err);
805     if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
806         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
807         dbus_error_free(&err);
808         return -1;
809     }
810
811     dbus_message_unref(reply);
812     return 0;
813 }
814
815 static int method_call_bt_sco_get_property(pa_dbus_connection *conn, bool *is_wide_band, bool *is_nrec) {
816     DBusMessage *msg, *reply;
817     DBusMessageIter reply_iter, reply_iter_entry;
818     DBusError err;
819     unsigned int codec;
820     unsigned int nrec;
821     const char *property;
822
823     pa_assert(conn);
824
825     if (!is_wide_band && !is_nrec) {
826         return -1;
827     }
828
829     if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, "GetProperties"))) {
830         pa_log_error("dbus method call failed");
831         return -1;
832     }
833
834     dbus_error_init(&err);
835     if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
836         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
837         dbus_error_free(&err);
838         return -1;
839     }
840
841     dbus_message_iter_init(reply,  &reply_iter);
842
843     if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
844         pa_log_error("Cannot get reply argument");
845         return -1;
846     }
847
848     dbus_message_iter_recurse(&reply_iter,  &reply_iter_entry);
849
850     while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
851         DBusMessageIter dict_entry, dict_entry_val;
852         dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
853         dbus_message_iter_get_basic(&dict_entry, &property);
854         pa_log_debug("String received = %s", property);
855         if (property) {
856             if (pa_streq("codec", property) && is_wide_band) {
857                 dbus_message_iter_next(&dict_entry);
858                 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
859                 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_UINT32)
860                     continue;
861                 dbus_message_iter_get_basic(&dict_entry_val, &codec);
862                 pa_log_debug("Codec = [%d]", codec);
863                 *is_wide_band = (codec == BT_MSBC_CODEC_ID) ? true : false;
864             } else if (pa_streq("nrec", property) && is_nrec) {
865                 dbus_message_iter_next(&dict_entry);
866                 dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
867                 if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_BOOLEAN)
868                     continue;
869                 dbus_message_iter_get_basic(&dict_entry_val, &nrec);
870                 pa_log_debug("nrec= [%d]", nrec);
871                 *is_nrec = nrec;
872             }
873         }
874         dbus_message_iter_next(&reply_iter_entry);
875     }
876
877
878     dbus_message_unref(reply);
879     return 0;
880 }
881
882 /* only for bt sco device */
883 int pa_tz_device_sco_enable_pcm(pa_tz_device *device, bool enable) {
884     pa_assert(device);
885     pa_assert(device->dbus_conn);
886
887     pa_log_info("BT SCO PCM[device id:%u, enable: %d]", device->id, enable);
888     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
889         pa_log_error("Not BT SCO device");
890         return -1;
891     }
892
893     if (enable && device->sco_opened) {
894         pa_log_info("BT SCO is already opened, skip enable pcm");
895         return 0;
896     }
897
898     if (method_call_bt_sco_enable_pcm(device->dbus_conn, enable) < 0) {
899         pa_log_error("Failed to bt sco enable pcm");
900         return -1;
901     }
902
903     pa_log_info("BT SCO PCM enable[%d]- SUCCESS", enable);
904
905     return 0;
906 }
907
908 /* only for bt sco device */
909 int pa_tz_device_sco_open(pa_tz_device *device) {
910     pa_assert(device);
911     pa_assert(device->dbus_conn);
912
913     pa_log_info("BT SCO Open for device(%u)", device->id);
914     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
915         pa_log_error("Not BT SCO device");
916         return -1;
917     }
918
919     if (device->sco_opened) {
920         pa_log_warn("SCO already opened");
921         return -1;
922     }
923
924     if (method_call_bt_sco(device->dbus_conn, true) < 0) {
925         pa_log_error("Failed to bt sco on");
926         return -1;
927     }
928
929     device->sco_opened = true;
930     device->creation_time = pa_rtclock_now();
931     pa_tz_device_dump_info(device, PA_LOG_DEBUG);
932     pa_log_info("BT SCO Open - SUCCESS");
933
934     return 0;
935 }
936
937 /* only for bt sco device */
938 int pa_tz_device_sco_close(pa_tz_device *device) {
939     pa_assert(device);
940
941     pa_log_info("BT SCO Close for device(%u)", device->id);
942
943     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
944         pa_log_error("Not BT SCO device");
945         return -1;
946     }
947
948     if (device->sco_opened == false) {
949         pa_log_warn("SCO not opened");
950         return -1;
951     }
952
953     if (method_call_bt_sco(device->dbus_conn, false) < 0) {
954         pa_log_error("Failed to bt sco on");
955         return -1;
956     }
957
958     device->sco_opened = false;
959     pa_tz_device_dump_info(device, PA_LOG_DEBUG);
960     pa_log_info("BT SCO Close - Success");
961
962     return 0;
963 }
964
965 /* only for bt sco device */
966 int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec) {
967     pa_assert(device);
968
969     pa_log_info("BT SCO get property for device(%u)", device->id);
970     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
971         pa_log_error("Not BT device");
972         return -1;
973     }
974
975     if (method_call_bt_sco_get_property(device->dbus_conn, is_wide_band, nrec) < 0) {
976         pa_log_error("Failed to get BT SCO Property");
977         return -1;
978     }
979
980     pa_log_info("BT SCO Get Property - Success, is wide band : %s, nrec : %s", pa_yes_no(*is_wide_band), pa_yes_no(*nrec));
981
982     return 0;
983 }
984
985 /* only for bt sco device */
986 int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t *status) {
987     pa_assert(device);
988
989     pa_log_debug("BT SCO get status for device(%u)", device->id);
990     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
991         pa_log_error("Not BT device");
992         return -1;
993     }
994     if (status == NULL) {
995         pa_log_error("invalid parameter");
996         return -1;
997     }
998
999     if (device->sco_opened == false)
1000         *status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
1001     else
1002         *status = DM_DEVICE_BT_SCO_STATUS_OPENED;
1003
1004     pa_log_info("BT SCO (%u) Get Status, %d", device->id, *status);
1005     return 0;
1006 }
1007