4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Girishashok Joshi <girish.joshi@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
28 #include <syspopup_caller.h>
29 #include <dbus/dbus.h>
31 #include "bluetooth-api.h"
32 #include "bt-internal-types.h"
33 #include "bt-service-common.h"
34 #include "bt-service-avrcp.h"
35 #include "bt-service-event.h"
36 #include "bt-service-util.h"
37 #include "bt-service-audio.h"
39 static bt_player_settinngs_t loopstatus_settings[] = {
40 { REPEAT_INVALID, "" },
41 { REPEAT_MODE_OFF, "None" },
42 { REPEAT_SINGLE_TRACK, "Track" },
43 { REPEAT_ALL_TRACK, "Playlist" },
44 { REPEAT_INVALID, "" }
47 static bt_player_settinngs_t shuffle_settings[] = {
48 { SHUFFLE_INVALID, "" },
49 { SHUFFLE_MODE_OFF, "off" },
50 { SHUFFLE_ALL_TRACK, "alltracks" },
51 { SHUFFLE_GROUP, "group" },
52 { SHUFFLE_INVALID, "" }
55 static bt_player_settinngs_t player_status[] = {
56 { STATUS_STOPPED, "stopped" },
57 { STATUS_PLAYING, "playing" },
58 { STATUS_PAUSED, "paused" },
59 { STATUS_FORWARD_SEEK, "forward-seek" },
60 { STATUS_REVERSE_SEEK, "reverse-seek" },
61 { STATUS_ERROR, "error" },
62 { STATUS_INVALID, "" }
65 GDBusConnection *bt_gdbus_conn = NULL;
66 static guint avrcp_reg_id = 0;
67 static GDBusProxy *service_gproxy = NULL;
69 /* Introspection data exposed from bt-service */
70 static const gchar bt_avrcp_bluez_introspection_xml[] =
72 " <interface name='org.freedesktop.DBus.Properties'>"
73 " <method name='Set'>"
74 " <arg type='s' name='interface' direction='in'/>"
75 " <arg type='s' name='property' direction='in'/>"
76 " <arg type='v' name='value' direction='in'/>"
81 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
82 const char *path, const char *interface, const char *name,
83 const GVariant *variant)
85 GVariantBuilder *builder = NULL;
88 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
89 g_variant_builder_add(builder, "{sv}", name, variant);
91 g_dbus_connection_emit_signal(connection, NULL, path,
92 DBUS_INTERFACE_PROPERTIES,
94 g_variant_new("(sa{sv})",
98 g_variant_builder_unref(builder);
100 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
101 error->code, error->message);
102 g_clear_error(&error);
109 static GQuark __bt_avrcp_error_quark(void)
111 static GQuark quark = 0;
114 quark = g_quark_from_static_string("bt-avrcp");
119 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
121 BT_ERR("error[%d]\n", error);
124 case BT_AVRCP_ERROR_INVALID_PARAM:
125 return g_error_new(BT_AVRCP_ERROR, error,
126 BT_ERROR_INVALID_PARAM);
127 case BT_AVRCP_ERROR_INVALID_INTERFACE:
128 return g_error_new(BT_AVRCP_ERROR, error,
129 BT_ERROR_INVALID_INTERFACE);
130 case BT_AVRCP_ERROR_INTERNAL:
132 return g_error_new(BT_AVRCP_ERROR, error,
137 static void __bt_avrcp_agent_method(GDBusConnection *connection,
139 const gchar *object_path,
140 const gchar *interface_name,
141 const gchar *method_name,
142 GVariant *parameters,
143 GDBusMethodInvocation *invocation,
147 BT_INFO("method %s", method_name);
148 BT_INFO("object_path %s", object_path);
149 int ret = BT_AVRCP_ERROR_NONE;
151 gboolean shuffle_status;
153 gchar *interface = NULL;
154 gchar *property = NULL;
155 gchar *loop_status = NULL;
158 if (g_strcmp0(method_name, "Set") == 0) {
159 g_variant_get(parameters, "(&s&sv)", &interface, &property,
162 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
163 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
168 BT_DBG("Property: %s\n", property);
169 if (g_strcmp0(property, "Shuffle") == 0) {
171 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
173 ret = BT_AVRCP_ERROR_INVALID_PARAM;
177 shuffle_status = g_variant_get_boolean(value);
178 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
179 if (shuffle_status == TRUE)
180 status = SHUFFLE_ALL_TRACK;
182 status = SHUFFLE_MODE_OFF;
184 _bt_send_event(BT_AVRCP_EVENT,
185 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
186 g_variant_new("(u)", status));
187 } else if (g_strcmp0(property, "LoopStatus") == 0) {
189 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
191 ret = BT_AVRCP_ERROR_INVALID_PARAM;
195 loop_status = (gchar *)g_variant_get_string(value, NULL);
196 BT_DBG("Value: %s\n", loop_status);
198 if (g_strcmp0(loop_status, "Track") == 0)
199 status = REPEAT_SINGLE_TRACK;
200 else if (g_strcmp0(loop_status, "Playlist") == 0)
201 status = REPEAT_ALL_TRACK;
202 else if (g_strcmp0(loop_status, "None") == 0)
203 status = REPEAT_MODE_OFF;
205 status = REPEAT_INVALID;
207 _bt_send_event(BT_AVRCP_EVENT,
208 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
209 g_variant_new("(u)", status));
216 g_variant_unref(value);
217 err = __bt_avrcp_set_error(ret);
218 g_dbus_method_invocation_return_gerror(invocation, err);
223 static const GDBusInterfaceVTable method_table = {
224 __bt_avrcp_agent_method,
229 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
230 (const gchar *introspection_data)
233 GDBusNodeInfo *node_info = NULL;
235 if (introspection_data == NULL)
238 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
241 BT_ERR("Unable to create node: %s", err->message);
248 static GDBusProxy *__bt_avrcp_gdbus_init_service_proxy(void)
255 if (bt_gdbus_conn == NULL)
256 bt_gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
258 if (!bt_gdbus_conn) {
260 BT_ERR("Unable to connect to gdbus: %s", err->message);
266 adapter_path = _bt_get_adapter_path();
267 retv_if(adapter_path == NULL, NULL);
269 proxy = g_dbus_proxy_new_sync(bt_gdbus_conn,
270 G_DBUS_PROXY_FLAGS_NONE, NULL,
271 BT_BLUEZ_NAME, adapter_path,
272 BT_MEDIA_INTERFACE, NULL, &err);
273 g_free(adapter_path);
276 BT_ERR("Unable to create proxy");
278 BT_ERR("Error: %s", err->message);
288 static GDBusProxy *__bt_avrcp_gdbus_get_service_proxy(void)
290 return (service_gproxy) ? service_gproxy :
291 __bt_avrcp_gdbus_init_service_proxy();
294 int _bt_register_media_player(void)
298 gboolean shuffle_status;
300 GDBusConnection *conn;
301 GDBusNodeInfo *node_info;
303 GVariantBuilder *builder;
305 GError *error = NULL;
307 media_player_settings_t player_settings = {0,};
309 player_settings.repeat = REPEAT_MODE_OFF;
310 player_settings.status = STATUS_STOPPED;
311 player_settings.position = 0;
312 shuffle_status = FALSE;
314 conn = _bt_get_system_gconn();
315 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
316 bt_gdbus_conn = conn;
318 node_info = __bt_avrcp_create_method_node_info(
319 bt_avrcp_bluez_introspection_xml);
320 if (node_info == NULL)
321 return BLUETOOTH_ERROR_INTERNAL;
323 avrcp_reg_id = g_dbus_connection_register_object(bt_gdbus_conn,
324 BT_MEDIA_OBJECT_PATH,
325 node_info->interfaces[0],
328 g_dbus_node_info_unref(node_info);
330 if (avrcp_reg_id == 0) {
331 BT_ERR("Failed to register: %s", error->message);
332 g_clear_error(&error);
333 return BLUETOOTH_ERROR_INTERNAL;
336 adapter_path = _bt_get_adapter_path();
337 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
339 proxy = g_dbus_proxy_new_sync(conn,
340 G_DBUS_PROXY_FLAGS_NONE, NULL,
341 BT_BLUEZ_NAME, adapter_path,
342 BT_MEDIA_INTERFACE, NULL, &error);
343 g_free(adapter_path);
346 BT_ERR("Unable to create proxy");
348 BT_ERR("Error: %s", error->message);
349 g_clear_error(&error);
351 return BLUETOOTH_ERROR_INTERNAL;
354 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
356 g_variant_builder_add(builder, "{sv}", "LoopStatus",
358 loopstatus_settings[player_settings.repeat].property));
359 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
361 g_variant_builder_add(builder, "{sv}", "Shuffle",
362 g_variant_new("b", shuffle_status));
364 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
366 player_status[player_settings.status].property));
367 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
369 g_variant_builder_add(builder, "{sv}", "Position",
370 g_variant_new("u", player_settings.position));
372 path = g_strdup(BT_MEDIA_OBJECT_PATH);
373 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
374 g_variant_new("(oa{sv})", path, builder),
375 G_DBUS_CALL_FLAGS_NONE, -1,
378 g_object_unref(proxy);
380 g_variant_builder_unref(builder);
383 BT_ERR("Call RegisterPlayer Failed");
385 BT_ERR("errCode[%x], message[%s]",
386 error->code, error->message);
387 g_clear_error(&error);
389 return BLUETOOTH_ERROR_INTERNAL;
392 g_variant_unref(ret);
393 return BLUETOOTH_ERROR_NONE;
396 static void __bt_avrcp_unregister_object_path(void)
398 if (avrcp_reg_id > 0) {
399 g_dbus_connection_unregister_object(bt_gdbus_conn,
405 int _bt_unregister_media_player(void)
410 GError *error = NULL;
411 GDBusConnection *conn;
414 conn = bt_gdbus_conn;
415 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
417 proxy = __bt_avrcp_gdbus_get_service_proxy();
419 return BLUETOOTH_ERROR_INTERNAL;
421 path = g_strdup(BT_MEDIA_OBJECT_PATH);
422 BT_DBG("path is [%s]", path);
424 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
425 g_variant_new("(o)", path),
426 G_DBUS_CALL_FLAGS_NONE, -1,
431 BT_ERR("UnregisterPlayer failed");
433 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
434 error->code, error->message);
435 g_clear_error(&error);
437 return BLUETOOTH_ERROR_INTERNAL;
440 __bt_avrcp_unregister_object_path();
442 g_variant_unref(ret);
443 g_object_unref(bt_gdbus_conn);
444 bt_gdbus_conn = NULL;
447 return BLUETOOTH_ERROR_NONE;
450 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
453 char *interface = BT_MEDIA_PLAYER_INTERFACE;
454 GDBusConnection *conn;
455 GError *error = NULL;
456 GVariantBuilder *builder = NULL;
457 GVariantBuilder *inner_builder = NULL;
458 GVariant *children[1];
461 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
463 conn = bt_gdbus_conn;
464 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
466 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
467 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
469 g_variant_builder_add(inner_builder, "{sv}",
470 "xesam:title", g_variant_new_string(meta_data->title));
472 children[0] = g_variant_new_string(meta_data->artist);
473 g_variant_builder_add(inner_builder, "{sv}",
474 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
477 g_variant_builder_add(inner_builder, "{sv}",
478 "xesam:album", g_variant_new_string(meta_data->album));
480 children[0] = g_variant_new_string(meta_data->genre);
481 g_variant_builder_add(inner_builder, "{sv}",
482 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
485 g_variant_builder_add(inner_builder, "{sv}",
486 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
488 g_variant_builder_add(inner_builder, "{sv}",
489 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
491 g_variant_builder_add(inner_builder, "{sv}",
492 "mpris:lenght", g_variant_new_int64(meta_data->duration));
494 g_variant_builder_add(builder, "{sv}",
495 "Metadata", g_variant_new("a{sv}", inner_builder));
497 ret = g_dbus_connection_emit_signal(conn, NULL, BT_MEDIA_OBJECT_PATH,
498 DBUS_INTERFACE_PROPERTIES,
500 g_variant_new("(sa{sv})",
504 g_variant_builder_unref(inner_builder);
505 g_variant_builder_unref(builder);
509 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
510 error->code, error->message);
511 g_clear_error(&error);
516 return BLUETOOTH_ERROR_NONE;
519 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
522 GDBusConnection *conn;
524 media_metadata_attributes_t meta_data;
526 GVariantBuilder *builder = NULL;
527 GVariant *children[1];
529 conn = bt_gdbus_conn;
530 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
534 value = properties->repeat;
535 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
536 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
537 g_variant_new_string(loopstatus_settings[value].property))) {
538 BT_ERR("Error sending the PropertyChanged signal \n");
539 return BLUETOOTH_ERROR_INTERNAL;
543 value = properties->shuffle;
544 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
549 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
550 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
551 g_variant_new_boolean(shuffle))) {
552 BT_ERR("Error sending the PropertyChanged signal \n");
553 return BLUETOOTH_ERROR_INTERNAL;
557 value = properties->status;
558 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
559 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
560 g_variant_new_string(player_status[value].property))) {
561 BT_ERR("Error sending the PropertyChanged signal \n");
562 return BLUETOOTH_ERROR_INTERNAL;
566 value = properties->position;
567 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
568 BT_MEDIA_PLAYER_INTERFACE, "Position",
569 g_variant_new_uint32(value))) {
570 BT_ERR("Error sending the PropertyChanged signal \n");
571 return BLUETOOTH_ERROR_INTERNAL;
575 meta_data = properties->metadata;
577 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
578 g_variant_builder_add(builder, "{sv}",
579 "xesam:title", g_variant_new_string(meta_data.title));
581 children[0] = g_variant_new_string(meta_data.artist);
582 g_variant_builder_add(builder, "{sv}",
583 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
586 g_variant_builder_add(builder, "{sv}",
587 "xesam:album", g_variant_new_string(meta_data.album));
589 children[0] = g_variant_new_string(meta_data.genre);
590 g_variant_builder_add(builder, "{sv}",
591 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
594 g_variant_builder_add(builder, "{sv}",
595 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
597 g_variant_builder_add(builder, "{sv}",
598 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
600 g_variant_builder_add(builder, "{sv}",
601 "mpris:lenght", g_variant_new_int64(meta_data.duration));
603 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
604 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
605 g_variant_new("a{sv}", builder))) {
606 BT_ERR("Error sending the PropertyChanged signal \n");
607 g_variant_builder_unref(builder);
608 return BLUETOOTH_ERROR_INTERNAL;
610 g_variant_builder_unref(builder);
613 BT_ERR("Invalid Type\n");
614 return BLUETOOTH_ERROR_INTERNAL;
617 return BLUETOOTH_ERROR_NONE;
620 int _bt_avrcp_set_properties(media_player_settings_t *properties)
624 if (_bt_avrcp_set_interal_property(REPEAT,
625 properties) != BLUETOOTH_ERROR_NONE) {
626 return BLUETOOTH_ERROR_INTERNAL;
628 if (_bt_avrcp_set_interal_property(SHUFFLE,
629 properties) != BLUETOOTH_ERROR_NONE) {
630 return BLUETOOTH_ERROR_INTERNAL;
633 if (_bt_avrcp_set_interal_property(STATUS,
634 properties) != BLUETOOTH_ERROR_NONE) {
635 return BLUETOOTH_ERROR_INTERNAL;
638 if (_bt_avrcp_set_interal_property(POSITION,
639 properties) != BLUETOOTH_ERROR_NONE) {
640 return BLUETOOTH_ERROR_INTERNAL;
643 if (_bt_avrcp_set_interal_property(METADATA,
644 properties) != BLUETOOTH_ERROR_NONE) {
645 return BLUETOOTH_ERROR_INTERNAL;
648 return BLUETOOTH_ERROR_NONE;
651 int _bt_avrcp_set_property(int type, unsigned int value)
654 media_player_settings_t properties;
658 properties.repeat = value;
661 properties.shuffle = value;
664 properties.status = value;
667 properties.position = value;
670 BT_DBG("Invalid Type\n");
671 return BLUETOOTH_ERROR_INTERNAL;
674 if (_bt_avrcp_set_interal_property(type,
675 &properties) != BLUETOOTH_ERROR_NONE)
676 return BLUETOOTH_ERROR_INTERNAL;
680 return BLUETOOTH_ERROR_NONE;