b40503a58e48d95cb287009882a1216fd6165bf6
[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 static int device_id_max_g = 1;
29 static 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         pa_strbuf_printf(buf, "  Specified Stream role : %s\n", device->specified_stream_role);
147     }
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));
151 #endif
152     playback_str = get_playback_list_str(device->playback_devices);
153     capture_str = get_capture_list_str(device->capture_devices);
154
155     if (playback_str)
156         pa_strbuf_puts(buf, playback_str);
157     if (capture_str)
158         pa_strbuf_puts(buf, capture_str);
159
160     pa_xfree(playback_str);
161     pa_xfree(capture_str);
162
163     return pa_strbuf_to_string_free(buf);
164 }
165
166
167 void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level) {
168     char *info;
169
170     if (!device)
171         return;
172
173     if ((info = _device_get_info_str(device))) {
174         pa_logl(log_level, "%s", info);
175         pa_xfree(info);
176     }
177 }
178
179 static void notify_device_connection_changed(pa_tz_device *device, bool connected) {
180     pa_tz_device_hook_data_for_conn_changed hook_data;
181
182     hook_data.event_id = _new_event_id();
183     hook_data.is_connected = connected;
184     hook_data.device = device;
185
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);
189 }
190
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;
193
194     hook_data.event_id = _new_event_id();
195     hook_data.activated = (state == DM_DEVICE_STATE_ACTIVATED) ? true : false;
196     hook_data.device = device;
197
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);
201 }
202
203 static void notify_device_running_changed(pa_tz_device *device, bool running) {
204     pa_tz_device_hook_data_for_running_changed hook_data;
205
206     hook_data.event_id = _new_event_id();
207     hook_data.is_running = running;
208     hook_data.device = device;
209
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);
213 }
214
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) {
218     pa_assert(data);
219     pa_assert(list);
220     pa_assert(comm);
221
222     data->list = list;
223     data->comm = comm;
224     data->dbus_conn = conn;
225
226     data->type = NULL;
227     data->name = NULL;
228     data->system_id = NULL;
229     data->vendor_id = -1;
230     data->product_id = -1;
231     data->direction = DM_DEVICE_DIRECTION_NONE;
232
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);
235 }
236
237 void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type) {
238     pa_assert(data);
239
240     data->type = pa_xstrdup(type);
241 }
242
243 void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name) {
244     pa_assert(data);
245
246     data->name = pa_xstrdup(name);
247 }
248
249 void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction) {
250     pa_assert(data);
251
252     data->direction = direction;
253 }
254 /* only for external? */
255 void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id) {
256     pa_assert(data);
257
258     data->system_id = pa_xstrdup(system_id);
259 }
260
261 void pa_tz_device_new_data_set_vendor_id(pa_tz_device_new_data *data, int vendor_id) {
262     pa_assert(data);
263
264     data->vendor_id = vendor_id;
265 }
266
267 void pa_tz_device_new_data_set_product_id(pa_tz_device_new_data *data, int product_id) {
268     pa_assert(data);
269
270     data->product_id = product_id;
271 }
272
273 void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec) {
274     pa_assert(data);
275
276     data->use_internal_codec = use_internal_codec;
277 }
278
279 void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink) {
280     pa_assert(data);
281
282     pa_hashmap_put(data->playback_pcms, (void*)role, sink);
283 }
284
285 void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source) {
286     pa_assert(data);
287
288     pa_hashmap_put(data->capture_pcms, (void*)role, source);
289 }
290
291 void pa_tz_device_new_data_done(pa_tz_device_new_data *data) {
292     pa_assert(data);
293
294     pa_xfree(data->type);
295     pa_xfree(data->name);
296 }
297
298 static int _check_valid_device_new_data(pa_tz_device_new_data *data) {
299     pa_assert(data);
300
301     if (data->type == NULL) {
302         pa_log_error("new data type is null");
303         return -1;
304     }
305
306     if (data->direction == DM_DEVICE_DIRECTION_NONE) {
307         pa_log_error("new data direction is none");
308         return -1;
309     }
310
311     return 0;
312 }
313
314 static int device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
315     pa_assert(device);
316     pa_assert(device->playback_devices);
317
318     if (pa_hashmap_put(device->playback_devices, (void*)role, sink) < 0) {
319         pa_log_error("Failed to add sink : put sink failed");
320         return -1;
321     }
322     return 0;
323 }
324
325 static int device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
326     pa_assert(device);
327     pa_assert(device->capture_devices);
328
329     if (pa_hashmap_put(device->capture_devices, (void*)role, source) < 0) {
330         pa_log_error("Failed to add source : put source failed");
331         return -1;
332     }
333     return 0;
334 }
335
336 static pa_sink* device_get_sink(pa_tz_device *device, const char *role) {
337     pa_sink *sink;
338     pa_assert(device);
339     pa_assert(device->playback_devices);
340
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. */
343     if (!role) {
344         if ((sink = pa_hashmap_first(device->playback_devices)) == NULL) {
345             pa_log_warn("Failed to get sink for default");
346             return NULL;
347         }
348         return sink;
349     }
350
351     if ((sink = pa_hashmap_get(device->playback_devices, role)) == NULL) {
352         pa_log_warn("Failed to get sink for %s", role);
353         return NULL;
354     }
355
356     return sink;
357 }
358
359 static pa_source* device_get_source(pa_tz_device *device, const char *role) {
360     pa_source *source;
361     pa_assert(device);
362     pa_assert(device->capture_devices);
363
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. */
366     if (!role) {
367         if ((source = pa_hashmap_first(device->capture_devices)) == NULL) {
368             pa_log_warn("Failed to get source for default");
369             return NULL;
370         }
371         return source;
372     }
373
374     if ((source = pa_hashmap_get(device->capture_devices, role)) == NULL) {
375         pa_log_warn("Failed to get source for %s", role);
376         return NULL;
377     }
378
379     return source;
380 }
381
382 static void device_set_state(pa_tz_device *device, dm_device_state_t new_state) {
383     pa_assert(device);
384
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);
390     } else {
391         pa_log_debug("same state, not change it");
392     }
393 }
394
395 static dm_device_state_t device_get_state(pa_tz_device *device) {
396     pa_assert(device);
397     return device->state;
398 }
399
400 static void device_set_running_and_notify(pa_tz_device *device, bool running) {
401     pa_assert(device);
402
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);
408     } else {
409         pa_log_debug("same running state, not change it");
410     }
411 }
412
413 static int device_remove_sink_with_role(pa_tz_device *device, const char *role) {
414     pa_sink *sink;
415     pa_assert(device);
416
417     sink = pa_hashmap_remove(device->playback_devices, role);
418     return sink ? 0 : -1;
419 }
420
421 static int device_remove_source_with_role(pa_tz_device *device, const char *role) {
422     pa_source *source;
423     pa_assert(device);
424
425     source = pa_hashmap_remove(device->capture_devices, role);
426     return source ? 0 : -1;
427 }
428
429 static int device_remove_sink(pa_tz_device *device, pa_sink *sink) {
430     pa_sink *_sink;
431     void *state;
432     char *role;
433
434     pa_assert(device);
435
436     PA_HASHMAP_FOREACH_KV(role, _sink, device->playback_devices, state) {
437         if (sink == _sink)
438             return device_remove_sink_with_role(device, role);
439     }
440
441     return -1;
442 }
443
444 static int device_remove_source(pa_tz_device *device, pa_source *source) {
445     pa_source *_source;
446     void *state;
447     char *role;
448
449     pa_assert(device);
450
451     PA_HASHMAP_FOREACH_KV(role, _source, device->capture_devices, state) {
452         if (source == _source)
453             return device_remove_source_with_role(device, role);
454     }
455
456     return -1;
457 }
458
459 /* pa_tz_device */
460 pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
461     pa_tz_device *device;
462     pa_sink *sink;
463     pa_source *source;
464
465     char spec_str[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0, };
466
467     pa_assert(data);
468
469     if (_check_valid_device_new_data(data) < 0) {
470         pa_log_error("Invalid device_new_data");
471         return NULL;
472     }
473
474     device = pa_xmalloc0(sizeof(pa_tz_device));
475
476     device->list = data->list;
477     device->comm = data->comm;
478     device->dbus_conn = data->dbus_conn;
479
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;
486
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;
495 #endif
496     device->is_running = false;
497     device->specified_stream_role = pa_xstrdup("none");
498
499     if ((sink = device_get_sink(device, NULL))) {
500         sink->device_item = device;
501         device->sample_spec = &sink->sample_spec;
502     }
503     if ((source = device_get_source(device, NULL))) {
504         source->device_item = device;
505         device->sample_spec = &source->sample_spec;
506     }
507     pa_sample_spec_snprint(spec_str, sizeof(spec_str), device->sample_spec);
508
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);
512
513     pa_idxset_put(device->list, device, NULL);
514
515     notify_device_connection_changed(device, true);
516
517     pa_tz_device_dump_info(device, PA_LOG_INFO);
518
519     return device;
520 }
521
522 int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
523     pa_assert(device);
524     pa_assert(device_role_is_valid(role));
525     pa_assert(sink);
526
527     pa_log_info("device add sink, device(%u) role(%s) sink(%s)",
528             device->id, role, sink->name);
529
530     if (device_add_sink(device, role, sink) < 0) {
531         pa_log_error("Failed to add sink : Can't add to device");
532         return -1;
533     }
534
535     return 0;
536 }
537
538 int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
539     pa_assert(device);
540     pa_assert(device_role_is_valid(role));
541     pa_assert(source);
542
543     pa_log_info("device add source, device(%u) role(%s) source(%s)",
544             device->id, role, source->name);
545
546     if (device_add_source(device, role, source) < 0) {
547         pa_log_error("Failed to add source : Can't add to device");
548         return -1;
549     }
550
551     return 0;
552 }
553
554 int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink) {
555     pa_assert(device);
556     pa_assert(sink);
557
558     pa_log_info("device remove sink, device(%u) sink(%s)",
559             device->id, sink->name);
560
561     return device_remove_sink(device, sink);
562 }
563
564 int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source) {
565     pa_assert(device);
566     pa_assert(source);
567
568     pa_log_info("device remove source, device(%u) source(%s)",
569             device->id, source->name);
570
571     return device_remove_source(device, source);
572 }
573
574 int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role) {
575     pa_assert(device);
576     pa_assert(device_role_is_valid(role));
577
578     pa_log_info("device remove sink with role, device(%u) role(%s)",
579             device->id, role);
580
581     return device_remove_sink_with_role(device, role);
582 }
583
584 int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role) {
585     pa_assert(device);
586     pa_assert(device_role_is_valid(role));
587
588     pa_log_info("device remove source with role, device(%u) role(%s)",
589             device->id, role);
590
591     return device_remove_source_with_role(device, role);
592 }
593
594 void pa_tz_device_free(pa_tz_device *device) {
595     pa_sink *sink;
596     pa_source *source;
597     void *state;
598
599     pa_assert(device);
600
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);
603
604     pa_tz_device_dump_info(device, PA_LOG_INFO);
605
606     pa_idxset_remove_by_data(device->list, device, NULL);
607
608     if (device->playback_devices)
609         PA_HASHMAP_FOREACH(sink, device->playback_devices, state)
610             sink->device_item = NULL;
611
612     if (device->capture_devices)
613         PA_HASHMAP_FOREACH(source, device->capture_devices, state)
614             source->device_item = NULL;
615
616     notify_device_connection_changed(device, false);
617
618     pa_xfree(device->type);
619     pa_xfree(device->name);
620     pa_xfree(device->system_id);
621     pa_xfree(device->specified_stream_role);
622
623     pa_xfree(device);
624 }
625
626 /* exported api */
627 pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role) {
628     pa_sink *sink;
629
630     pa_assert(device);
631
632     pa_log_info("device get sink, device(%u) role(%s)", device->id, role);
633
634     if ((sink = device_get_sink(device, role)) == NULL) {
635         pa_log_error("Failed to get sink from device");
636         return NULL;
637     }
638
639     pa_log_info("sink name(%s)", sink->name);
640
641     return sink;
642 }
643
644 pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
645     pa_source *source;
646
647     pa_assert(device);
648
649     pa_log_info("device get source, device(%u) role(%s)",
650             device->id, role);
651
652     if ((source = device_get_source(device, role)) == NULL) {
653         pa_log_error("Failed to get source from device");
654         return NULL;
655     }
656
657     pa_log_info("source name(%s)", source->name);
658
659     return source;
660 }
661
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) {
665     pa_assert(device);
666
667     pa_log_info("device set state, device(%u) type(%s) -> %d",
668             device->id, device->type, state);
669     device_set_state(device, state);
670 }
671
672 dm_device_state_t pa_tz_device_get_state(pa_tz_device *device) {
673     pa_assert(device);
674
675     return device_get_state(device);
676 }
677
678 void pa_tz_device_set_running_and_notify(pa_tz_device *device, bool running) {
679     pa_assert(device);
680
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);
684 }
685
686 bool pa_tz_device_is_running(pa_tz_device *device) {
687     pa_assert(device);
688
689     return device->is_running;
690 }
691
692 uint32_t pa_tz_device_get_id(pa_tz_device *device) {
693     pa_assert(device);
694
695     return device->id;
696 }
697
698 char* pa_tz_device_get_type(pa_tz_device *device) {
699     pa_assert(device);
700
701     return device->type;
702 }
703
704 char* pa_tz_device_get_role(pa_tz_device *device, const char *preferred_role) {
705     char *role;
706     pa_sink *sink;
707     pa_source *source;
708     void *state;
709
710     pa_assert(device);
711
712     if (device->playback_devices) {
713         PA_HASHMAP_FOREACH_KV(role, sink, device->playback_devices, state) {
714             if (!preferred_role)
715                 return role;
716
717             if (pa_safe_streq(role, preferred_role))
718                 return role;
719         }
720     }
721
722     if (device->capture_devices) {
723         PA_HASHMAP_FOREACH_KV(role, source, device->capture_devices, state) {
724             if (!preferred_role)
725                 return role;
726
727             if (pa_safe_streq(role, preferred_role))
728                 return role;
729         }
730     }
731
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);
734
735     return NULL;
736 }
737
738 char* pa_tz_device_get_name(pa_tz_device *device) {
739     pa_assert(device);
740
741     return device->name;
742 }
743
744 char* pa_tz_device_get_system_id(pa_tz_device *device) {
745     pa_assert(device);
746
747     return device->system_id;
748 }
749
750 int pa_tz_device_get_vendor_id(pa_tz_device *device) {
751     pa_assert(device);
752
753     return device->vendor_id;
754 }
755
756 int pa_tz_device_get_product_id(pa_tz_device *device) {
757     pa_assert(device);
758
759     return device->product_id;
760 }
761
762 char* pa_tz_device_get_specified_stream_role(pa_tz_device *device) {
763     pa_assert(device);
764
765     if (pa_safe_streq("none", device->specified_stream_role))
766         return NULL;
767
768     return device->specified_stream_role;
769 }
770
771 dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device) {
772     pa_assert(device);
773
774     return device->direction;
775 }
776
777 pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device) {
778     pa_assert(device);
779
780     return device->creation_time;
781 }
782
783 bool pa_tz_device_is_use_internal_codec(pa_tz_device *device) {
784     pa_assert(device);
785
786     return device->use_internal_codec;
787 }
788
789 const pa_sample_spec* pa_tz_device_get_sample_spec(pa_tz_device *device) {
790     pa_assert(device);
791
792     return device->sample_spec;
793 }
794
795 bool pa_tz_device_is_all_suspended(pa_tz_device *device) {
796     pa_sink *sink;
797     pa_source *source;
798     void *state;
799
800     PA_HASHMAP_FOREACH(sink, device->playback_devices, state) {
801         if (sink->state != PA_SINK_SUSPENDED)
802             return false;
803     }
804
805     PA_HASHMAP_FOREACH(source, device->capture_devices, state) {
806         if (source->state != PA_SOURCE_SUSPENDED)
807             return false;
808     }
809
810     return true;
811 }
812
813 pa_intset* pa_tz_device_get_stream_list(pa_tz_device *device) {
814     pa_sink *sink;
815     pa_source *source;
816     pa_sink_input *input;
817     pa_source_output *output;
818     void *state;
819     const char *p_id_str;
820     int32_t p_id;
821     uint32_t idx;
822     pa_intset *stream_id_set;
823
824     pa_assert(device);
825
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);
832             } else {
833                 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
834             }
835         }
836     }
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);
842             } else {
843                 pa_log_warn("Invalid Parent ID : '%s'", pa_strnull(p_id_str));
844             }
845         }
846     }
847
848     return stream_id_set;
849 }
850
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;
854     DBusError err;
855     const char *method = "SetVoiceDial";
856     dbus_bool_t _enable = (dbus_bool_t)enable;
857
858     pa_assert(conn);
859
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");
862         return -1;
863     }
864
865     pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &_enable, DBUS_TYPE_INVALID));
866
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);
870     if (!reply) {
871         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
872         dbus_error_free(&err);
873         return -1;
874     }
875
876     dbus_message_unref(reply);
877     return 0;
878 }
879
880 static int method_call_bt_sco(pa_dbus_connection *conn, bool onoff) {
881     DBusMessage *msg, *reply;
882     DBusError err;
883     const char *method;
884
885     pa_assert(conn);
886
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");
890         return -1;
891     }
892
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);
896     if (!reply) {
897         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
898         dbus_error_free(&err);
899         return -1;
900     }
901
902     dbus_message_unref(reply);
903     return 0;
904 }
905
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;
909     DBusError err;
910     unsigned int codec;
911     unsigned int nrec;
912     const char *property;
913
914     pa_assert(conn);
915
916     if (!is_wide_band && !is_nrec) {
917         return -1;
918     }
919
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");
922         return -1;
923     }
924
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);
928     if (!reply) {
929         pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
930         dbus_error_free(&err);
931         return -1;
932     }
933
934     dbus_message_iter_init(reply,  &reply_iter);
935
936     if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
937         pa_log_error("Cannot get reply argument");
938         return -1;
939     }
940
941     dbus_message_iter_recurse(&reply_iter,  &reply_iter_entry);
942
943     while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
944         DBusMessageIter dict_entry, dict_entry_val;
945
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);
949
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)
954                 continue;
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)
962                 continue;
963             dbus_message_iter_get_basic(&dict_entry_val, &nrec);
964             pa_log_debug("nrec = [%d]", nrec);
965             *is_nrec = nrec;
966         }
967
968         dbus_message_iter_next(&reply_iter_entry);
969     }
970
971     dbus_message_unref(reply);
972
973     return 0;
974 }
975
976 /* only for bt sco device */
977 int pa_tz_device_sco_enable_pcm(pa_tz_device *device, bool enable) {
978     pa_assert(device);
979     pa_assert(device->dbus_conn);
980
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");
984         return -1;
985     }
986
987     if (enable && device->sco_opened) {
988         pa_log_info("BT SCO is already opened, skip enable pcm");
989         return 0;
990     }
991
992     if (method_call_bt_sco_enable_pcm(device->dbus_conn, enable) < 0) {
993         pa_log_error("Failed to bt sco enable pcm");
994         return -1;
995     }
996
997     pa_log_info("BT SCO PCM enable[%d]- SUCCESS", enable);
998
999     return 0;
1000 }
1001
1002 /* only for bt sco device */
1003 int pa_tz_device_sco_open(pa_tz_device *device) {
1004     pa_assert(device);
1005     pa_assert(device->dbus_conn);
1006
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");
1010         return -1;
1011     }
1012
1013     if (device->sco_opened) {
1014         pa_log_warn("SCO already opened");
1015         return -1;
1016     }
1017
1018     if (method_call_bt_sco(device->dbus_conn, true) < 0) {
1019         pa_log_error("Failed to bt sco on");
1020         return -1;
1021     }
1022
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");
1027
1028     return 0;
1029 }
1030
1031 /* only for bt sco device */
1032 int pa_tz_device_sco_close(pa_tz_device *device) {
1033     pa_assert(device);
1034
1035     pa_log_info("BT SCO Close for device(%u)", device->id);
1036
1037     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO) == false) {
1038         pa_log_error("Not BT SCO device");
1039         return -1;
1040     }
1041
1042     if (device->sco_opened == false) {
1043         pa_log_warn("SCO not opened");
1044         return -1;
1045     }
1046
1047     if (method_call_bt_sco(device->dbus_conn, false) < 0) {
1048         pa_log_error("Failed to bt sco on");
1049         return -1;
1050     }
1051
1052     device->sco_opened = false;
1053     pa_tz_device_dump_info(device, PA_LOG_DEBUG);
1054     pa_log_info("BT SCO Close - Success");
1055
1056     return 0;
1057 }
1058
1059 /* only for bt sco device */
1060 int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec) {
1061     pa_assert(device);
1062
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");
1066         return -1;
1067     }
1068
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");
1071         return -1;
1072     }
1073
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));
1075
1076     return 0;
1077 }
1078
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) {
1081     pa_assert(device);
1082
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");
1086         return -1;
1087     }
1088     if (status == NULL) {
1089         pa_log_error("invalid parameter");
1090         return -1;
1091     }
1092
1093     if (device->sco_opened == false)
1094         *status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
1095     else
1096         *status = DM_DEVICE_BT_SCO_STATUS_OPENED;
1097
1098     pa_log_info("BT SCO (%u) Get Status, %d", device->id, *status);
1099     return 0;
1100 }
1101 #endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */
1102