2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "bt-internal-types.h"
19 #include "bt-service-common.h"
20 #include "bt-service-avrcp-controller.h"
21 #include "bt-service-audio.h"
22 #include "bt-service-event.h"
24 static bt_player_settinngs_t repeat_status[] = {
25 { REPEAT_INVALID, "" },
26 { REPEAT_MODE_OFF, "off" },
27 { REPEAT_SINGLE_TRACK, "singletrack" },
28 { REPEAT_ALL_TRACK, "alltracks" },
29 { REPEAT_GROUP, "group" },
30 { REPEAT_INVALID, "" }
33 static bt_player_settinngs_t equalizer_status[] = {
34 { EQUALIZER_INVALID, "" },
35 { EQUALIZER_OFF, "off" },
36 { EQUALIZER_ON, "on" },
37 { EQUALIZER_INVALID, "" },
40 static bt_player_settinngs_t scan_status[] = {
42 { SCAN_MODE_OFF, "off" },
43 { SCAN_ALL_TRACK, "alltracks" },
44 { SCAN_GROUP, "group" },
48 static bt_player_settinngs_t shuffle_settings[] = {
49 { SHUFFLE_INVALID, "" },
50 { SHUFFLE_MODE_OFF, "off" },
51 { SHUFFLE_ALL_TRACK, "alltracks" },
52 { SHUFFLE_GROUP, "group" },
53 { SHUFFLE_INVALID, "" }
56 static char *avrcp_control_path = NULL;
58 void _bt_set_control_device_path(const char *path)
63 g_free(avrcp_control_path);
64 BT_DBG("control_path = %s", path);
65 avrcp_control_path = g_strdup(path);
68 void _bt_remove_control_device_path(const char *path)
72 if (avrcp_control_path &&
73 !g_strcmp0(avrcp_control_path, path)) {
74 BT_DBG("control_path = %s", path);
75 g_free(avrcp_control_path);
76 avrcp_control_path = NULL;
80 static char *__bt_get_control_device_path(void)
84 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
88 retv_if(avrcp_control_path != NULL, avrcp_control_path);
90 retv_if(!_bt_is_headset_type_connected(BT_AVRCP,
91 connected_address), NULL);
93 BT_DBG("device address = %s", connected_address);
95 adapter_path = _bt_get_device_object_path(connected_address);
96 retv_if(adapter_path == NULL, NULL);
98 control_path = g_strdup_printf(BT_MEDIA_CONTROL_PATH, adapter_path);
101 avrcp_control_path = control_path;
102 BT_DBG("control_path = %s", control_path);
106 static int __bt_media_send_control_msg(const char *name)
108 GVariant *reply = NULL;
110 GDBusConnection *conn = NULL;
111 GDBusProxy *proxy = NULL;
112 char *control_path = NULL;
114 retv_if(name == NULL, BLUETOOTH_ERROR_INTERNAL);
116 conn = _bt_get_system_conn();
117 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
119 control_path = __bt_get_control_device_path();
120 retv_if(control_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
121 BT_DBG("control_path %s", control_path);
123 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
124 BT_BLUEZ_NAME, control_path,
125 BT_PLAYER_CONTROL_INTERFACE, NULL, &err);
127 BT_ERR("Unable to allocate new proxy \n");
129 BT_ERR("%s", err->message);
132 return BLUETOOTH_ERROR_INTERNAL;
135 reply = g_dbus_proxy_call_sync(proxy, name, NULL,
136 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
138 g_object_unref(proxy);
141 BT_ERR("Error returned in method call");
143 BT_ERR("%s", err->message);
146 return BLUETOOTH_ERROR_INTERNAL;
149 g_variant_unref(reply);
152 return BLUETOOTH_ERROR_NONE;
155 int _bt_avrcp_control_cmd(int type)
157 int ret = BLUETOOTH_ERROR_INTERNAL;
162 ret = __bt_media_send_control_msg("Play");
165 ret = __bt_media_send_control_msg("Pause");
168 ret = __bt_media_send_control_msg("Stop");
171 ret = __bt_media_send_control_msg("Next");
174 ret = __bt_media_send_control_msg("Previous");
177 ret = __bt_media_send_control_msg("FastForward");
180 ret = __bt_media_send_control_msg("Rewind");
183 BT_DBG("Invalid Type\n");
184 return BLUETOOTH_ERROR_INTERNAL;
190 GDBusProxy *__bt_get_control_properties_proxy(void)
192 GDBusProxy *proxy = NULL;
193 GError *error = NULL;
194 char *control_path = NULL;
195 GDBusConnection *conn = NULL;
197 control_path = __bt_get_control_device_path();
198 retv_if(control_path == NULL, NULL);
199 BT_DBG("control_path = %s", control_path);
201 conn = _bt_get_system_conn();
202 retv_if(conn == NULL, NULL);
204 proxy = g_dbus_proxy_new_sync(conn,
205 G_DBUS_PROXY_FLAGS_NONE, NULL,
206 BT_BLUEZ_NAME, control_path,
207 BT_PROPERTIES_INTERFACE, NULL, &error);
209 BT_ERR("Unable to allocate new proxy");
211 BT_ERR("%s", error->message);
212 g_clear_error(&error);
220 static int __bt_media_attr_to_event(const char *str)
222 if (!strcasecmp(str, "Equalizer"))
223 return BLUETOOTH_EVENT_AVRCP_CONTROL_EQUALIZER_STATUS;
224 else if (!strcasecmp(str, "Repeat"))
225 return BLUETOOTH_EVENT_AVRCP_CONTROL_REPEAT_STATUS;
226 else if (!strcasecmp(str, "Shuffle"))
227 return BLUETOOTH_EVENT_AVRCP_CONTROL_SHUFFLE_STATUS;
228 else if (!strcasecmp(str, "Scan"))
229 return BLUETOOTH_EVENT_AVRCP_CONTROL_SCAN_STATUS;
230 else if (!strcasecmp(str, "Position"))
231 return BLUETOOTH_EVENT_AVRCP_SONG_POSITION_STATUS;
232 else if (!strcasecmp(str, "Track"))
233 return BLUETOOTH_EVENT_AVRCP_TRACK_CHANGED;
234 else if (!strcasecmp(str, "Status"))
235 return BLUETOOTH_EVENT_AVRCP_PLAY_STATUS_CHANGED;
240 static int __bt_media_attr_to_type(const char *str)
242 if (!strcasecmp(str, "Equalizer"))
244 else if (!strcasecmp(str, "Repeat"))
246 else if (!strcasecmp(str, "Shuffle"))
248 else if (!strcasecmp(str, "Scan"))
250 else if (!strcasecmp(str, "Position"))
252 else if (!strcasecmp(str, "Track"))
254 else if (!strcasecmp(str, "Status"))
260 static const char *__bt_media_type_to_str(int type)
281 static int __bt_media_attrval_to_val(int type, const char *value)
287 if (!strcmp(value, "off"))
289 else if (!strcmp(value, "on"))
292 ret = EQUALIZER_INVALID;
296 if (!strcmp(value, "off"))
297 ret = REPEAT_MODE_OFF;
298 else if (!strcmp(value, "singletrack"))
299 ret = REPEAT_SINGLE_TRACK;
300 else if (!strcmp(value, "alltracks"))
301 ret = REPEAT_ALL_TRACK;
302 else if (!strcmp(value, "group"))
305 ret = REPEAT_INVALID;
309 if (!strcmp(value, "off"))
310 ret = SHUFFLE_MODE_OFF;
311 else if (!strcmp(value, "alltracks"))
312 ret = SHUFFLE_ALL_TRACK;
313 else if (!strcmp(value, "group"))
316 ret = SHUFFLE_INVALID;
320 if (!strcmp(value, "off"))
322 else if (!strcmp(value, "alltracks"))
323 ret = SCAN_ALL_TRACK;
324 else if (!strcmp(value, "group"))
331 if (!strcmp(value, "stopped"))
332 ret = STATUS_STOPPED;
333 else if (!strcmp(value, "playing"))
334 ret = STATUS_PLAYING;
335 else if (!strcmp(value, "paused"))
337 else if (!strcmp(value, "forward-seek"))
338 ret = STATUS_FORWARD_SEEK;
339 else if (!strcmp(value, "reverse-seek"))
340 ret = STATUS_REVERSE_SEEK;
341 else if (!strcmp(value, "error"))
344 ret = STATUS_INVALID;
349 int _bt_avrcp_control_get_property(int type, unsigned int *value)
351 GDBusProxy *proxy = NULL;
353 int ret = BLUETOOTH_ERROR_NONE;
355 GVariant *reply = NULL;
357 BT_CHECK_PARAMETER(value, return);
359 proxy = __bt_get_control_properties_proxy();
360 retv_if(proxy == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
362 reply = g_dbus_proxy_call_sync(proxy,
363 "Get", g_variant_new("ss", BT_PLAYER_CONTROL_INTERFACE, __bt_media_type_to_str(type)),
364 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
366 g_object_unref(proxy);
369 BT_ERR("Can't get managed objects");
371 BT_ERR("%s", err->message);
374 return BLUETOOTH_ERROR_INTERNAL;
382 name =(char *)g_variant_get_string(reply, NULL);
383 *value = __bt_media_attrval_to_val(type, name);
384 BT_DBG("Type[%s] and Value[%s]", __bt_media_type_to_str(type), name);
387 *value = g_variant_get_uint32(reply);
390 BT_DBG("Invalid Type\n");
391 ret = BLUETOOTH_ERROR_INTERNAL;
394 g_variant_unref(reply);
398 int _bt_avrcp_control_set_property(int type, unsigned int value)
400 GValue *attr_value = NULL;
401 GDBusProxy *proxy = NULL;
402 GError *error = NULL;
403 GVariant *reply, *param;
405 g_value_init(attr_value, G_TYPE_STRING);
409 param = g_variant_new("s", equalizer_status[value].property);
410 BT_DBG("equalizer_status %s", equalizer_status[value].property);
413 param = g_variant_new("s", repeat_status[value].property);
414 BT_DBG("repeat_status %s", repeat_status[value].property);
417 param = g_variant_new("s", shuffle_settings[value].property);
418 BT_DBG("shuffle_settings %s", shuffle_settings[value].property);
421 param = g_variant_new("s", scan_status[value].property);
422 BT_DBG("scan_status %s", scan_status[value].property);
425 BT_ERR("Invalid property type: %d", type);
426 g_value_unset(attr_value);
427 return BLUETOOTH_ERROR_INTERNAL;
430 proxy = __bt_get_control_properties_proxy();
431 retv_if(proxy == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
433 reply = g_dbus_proxy_call_sync(proxy,
434 "Set", g_variant_new("ssv", BT_PLAYER_CONTROL_INTERFACE, __bt_media_type_to_str(type), param),
435 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
437 g_object_unref(proxy);
438 g_variant_unref(param);
441 BT_ERR("Can't get managed objects");
443 BT_ERR("SetProperty Fail: %s", error->message);
444 g_clear_error(&error);
445 return BLUETOOTH_ERROR_INTERNAL;
449 g_variant_unref(reply);
450 g_value_unset(attr_value);
452 return BLUETOOTH_ERROR_NONE;
455 static int __bt_avrcp_control_parse_properties(
456 media_metadata_attributes_t *metadata,
459 GVariant *value = NULL;
461 char *value_string = NULL;
462 unsigned int value_uint;
463 const char *key = NULL;
465 g_variant_iter_init(&iter, item);
466 while (g_variant_iter_loop(&iter, "{sv}", &key, &value)){
467 if (strcasecmp(key, "Title") == 0){
468 value_string = (char *)g_variant_get_string(value, NULL);
469 BT_DBG("Value : %s ", value_string);
470 metadata->title = value_string;
471 } else if (strcasecmp(key, "Artist") == 0) {
472 value_string =(char *)g_variant_get_string(value, NULL);
473 BT_DBG("Value : %s ", value_string);
474 metadata->artist = value_string;
475 } else if (strcasecmp(key, "Album") == 0) {
476 value_string =(char *)g_variant_get_string(value, NULL);
477 BT_DBG("Value : %s ", value_string);
478 metadata->album = value_string;
479 } else if (strcasecmp(key, "Genre") == 0) {
480 value_string =(char *)g_variant_get_string(value, NULL);
481 BT_DBG("Value : %s ", value_string);
482 metadata->genre = value_string;
483 } else if (strcasecmp(key, "Duration") == 0) {
484 value_uint = g_variant_get_uint32(value);
485 metadata->duration = value_uint;
486 } else if (strcasecmp(key, "NumberOfTracks") == 0) {
487 value_uint = g_variant_get_uint32(value);
488 metadata->total_tracks = value_uint;
489 } else if (strcasecmp(key, "TrackNumber") == 0) {
490 value_uint = g_variant_get_uint32(value);
491 metadata->number = value_uint;
493 BT_DBG("%s not supported, ignoring", key);
496 if (!metadata->title)
497 metadata->title = g_strdup("");
498 if (!metadata->artist)
499 metadata->artist = g_strdup("");
500 if (!metadata->album)
501 metadata->album = g_strdup("");
502 if (!metadata->genre)
503 metadata->genre = g_strdup("");
505 return BLUETOOTH_ERROR_NONE;
509 int _bt_avrcp_control_get_track_info(media_metadata_attributes_t *metadata)
511 GDBusProxy *proxy = NULL;
512 GVariant *reply = NULL;
513 GVariant *item = NULL;
515 GDBusConnection *conn = NULL;
516 char *control_path = NULL;
517 char *interface_name = NULL;
518 char *property_name = NULL;
519 GVariant *parameters = NULL;
520 int ret = BLUETOOTH_ERROR_NONE;
522 retv_if(metadata == NULL, BLUETOOTH_ERROR_INTERNAL);
524 conn = _bt_get_system_conn();
525 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
527 control_path = __bt_get_control_device_path();
528 retv_if(control_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
529 BT_DBG("control_path %s", control_path);
531 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
532 BT_BLUEZ_NAME, control_path,
533 BT_PROPERTIES_INTERFACE, NULL, &err);
535 BT_ERR("Unable to allocate new proxy \n");
537 BT_ERR("%s", err->message);
540 return BLUETOOTH_ERROR_INTERNAL;
543 interface_name = g_strdup(BT_PLAYER_CONTROL_INTERFACE);
544 property_name = g_strdup("Track");
546 parameters = g_variant_new("(ss)", interface_name, property_name);
548 g_free(interface_name);
549 g_free(property_name);
551 reply = g_dbus_proxy_call_sync(proxy, "Get", parameters,
552 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
554 g_object_unref(proxy);
557 BT_ERR("Error returned in method call");
559 BT_ERR("%s", err->message);
562 return BLUETOOTH_ERROR_INTERNAL;
565 g_variant_get(reply, "(v)", &item);
567 ret = __bt_avrcp_control_parse_properties(metadata, item);
569 g_variant_unref(reply);
574 void _bt_handle_avrcp_control_event(GVariant *reply, const char *path)
576 GVariant *param = NULL;
577 const char *property = NULL;
580 BT_ERR("Error returned in method call\n");
585 GVariant *value = NULL;
586 g_variant_iter_init(&iter, reply);
587 while (g_variant_iter_loop(&iter, "{sv}", &property,
589 if ((strcasecmp(property, "Equalizer") == 0) ||
590 (strcasecmp(property, "Repeat") == 0) ||
591 (strcasecmp(property, "Shuffle") == 0) ||
592 (strcasecmp(property, "Scan") == 0) ||
593 (strcasecmp(property, "Status") == 0)){
595 unsigned int type, val;
597 valstr = g_variant_get_string(value, NULL);
598 BT_DBG("Value : %s ", valstr);
599 type = __bt_media_attr_to_type(property);
600 val = __bt_media_attrval_to_val(type, valstr);
602 /* Send event to application */
603 param = g_variant_new("(u)", val);
604 _bt_send_event(BT_AVRCP_CONTROL_EVENT,
605 __bt_media_attr_to_event(property), param);
606 } else if (strcasecmp(property, "Position") == 0) {
609 val = g_variant_get_uint32(value);
610 BT_DBG("Value : %d ", val);
612 /* Send event to application */
613 param = g_variant_new("(u)", val);
614 _bt_send_event(BT_AVRCP_CONTROL_EVENT,
615 __bt_media_attr_to_event(property), param);
616 } else if (strcasecmp(property, "Track") == 0) {
617 int ret = BLUETOOTH_ERROR_NONE;
618 media_metadata_attributes_t metadata;
620 memset(&metadata, 0x00, sizeof(media_metadata_attributes_t));
622 ret = __bt_avrcp_control_parse_properties(
624 if (BLUETOOTH_ERROR_NONE != ret){
625 /* Free key and value because of break unless free not required */
626 free((char *)property);
627 g_variant_unref(value);
631 /* Send event to application */
632 param = g_variant_new("(ssssuuu)",
637 metadata.total_tracks,
640 _bt_send_event(BT_AVRCP_CONTROL_EVENT,
641 BLUETOOTH_EVENT_AVRCP_TRACK_CHANGED, param);
643 g_free((char *)metadata.title);
644 g_free((char *)metadata.artist);
645 g_free((char *)metadata.album);
646 g_free((char *)metadata.genre);
648 BT_DBG("Property not handled");