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 #if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT)
29 #include <syspopup_caller.h>
31 #include <dbus/dbus.h>
33 #include "bluetooth-api.h"
34 #include "bt-internal-types.h"
35 #include "bt-service-common.h"
36 #include "bt-service-avrcp.h"
37 #include "bt-service-event.h"
38 #include "bt-service-util.h"
39 #include "bt-service-audio.h"
41 static bt_player_settinngs_t loopstatus_settings[] = {
42 { REPEAT_INVALID, "" },
43 { REPEAT_MODE_OFF, "None" },
44 { REPEAT_SINGLE_TRACK, "Track" },
45 { REPEAT_ALL_TRACK, "Playlist" },
46 { REPEAT_INVALID, "" }
49 static bt_player_settinngs_t shuffle_settings[] = {
50 { SHUFFLE_INVALID, "" },
51 { SHUFFLE_MODE_OFF, "off" },
52 { SHUFFLE_ALL_TRACK, "alltracks" },
53 { SHUFFLE_GROUP, "group" },
54 { SHUFFLE_INVALID, "" }
57 static bt_player_settinngs_t player_status[] = {
58 { STATUS_STOPPED, "stopped" },
59 { STATUS_PLAYING, "playing" },
60 { STATUS_PAUSED, "paused" },
61 { STATUS_FORWARD_SEEK, "forward-seek" },
62 { STATUS_REVERSE_SEEK, "reverse-seek" },
63 { STATUS_ERROR, "error" },
64 { STATUS_INVALID, "" }
67 GDBusConnection *bt_gdbus_conn = NULL;
68 static guint avrcp_reg_id = 0;
69 static GDBusProxy *service_gproxy = NULL;
71 /* Introspection data exposed from bt-service */
72 static const gchar bt_avrcp_bluez_introspection_xml[] =
74 " <interface name='org.freedesktop.DBus.Properties'>"
75 " <method name='Set'>"
76 " <arg type='s' name='interface' direction='in'/>"
77 " <arg type='s' name='property' direction='in'/>"
78 " <arg type='v' name='value' direction='in'/>"
83 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
84 const char *path, const char *interface, const char *name,
85 const GVariant *variant)
87 GVariantBuilder *builder = NULL;
90 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
91 g_variant_builder_add(builder, "{sv}", name, variant);
93 g_dbus_connection_emit_signal(connection, NULL, path,
94 DBUS_INTERFACE_PROPERTIES,
96 g_variant_new("(sa{sv})",
100 g_variant_builder_unref(builder);
102 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
103 error->code, error->message);
104 g_clear_error(&error);
111 static GQuark __bt_avrcp_error_quark(void)
113 static GQuark quark = 0;
116 quark = g_quark_from_static_string("bt-avrcp");
121 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
123 BT_ERR("error[%d]\n", error);
126 case BT_AVRCP_ERROR_INVALID_PARAM:
127 return g_error_new(BT_AVRCP_ERROR, error,
128 BT_ERROR_INVALID_PARAM);
129 case BT_AVRCP_ERROR_INVALID_INTERFACE:
130 return g_error_new(BT_AVRCP_ERROR, error,
131 BT_ERROR_INVALID_INTERFACE);
132 case BT_AVRCP_ERROR_INTERNAL:
134 return g_error_new(BT_AVRCP_ERROR, error,
139 static void __bt_avrcp_agent_method(GDBusConnection *connection,
141 const gchar *object_path,
142 const gchar *interface_name,
143 const gchar *method_name,
144 GVariant *parameters,
145 GDBusMethodInvocation *invocation,
149 BT_INFO("method %s", method_name);
150 BT_INFO("object_path %s", object_path);
151 int ret = BT_AVRCP_ERROR_NONE;
153 gboolean shuffle_status;
155 gchar *interface = NULL;
156 gchar *property = NULL;
157 gchar *loop_status = NULL;
158 GVariant *value = NULL;
160 if (g_strcmp0(method_name, "Set") == 0) {
161 g_variant_get(parameters, "(&s&sv)", &interface, &property,
164 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
165 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
171 BT_ERR("value is NULL");
175 BT_DBG("Property: %s\n", property);
176 if (g_strcmp0(property, "Shuffle") == 0) {
178 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
180 ret = BT_AVRCP_ERROR_INVALID_PARAM;
184 shuffle_status = g_variant_get_boolean(value);
185 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
186 if (shuffle_status == TRUE)
187 status = SHUFFLE_ALL_TRACK;
189 status = SHUFFLE_MODE_OFF;
191 _bt_send_event(BT_AVRCP_EVENT,
192 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
193 g_variant_new("(u)", status));
194 } else if (g_strcmp0(property, "LoopStatus") == 0) {
196 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
198 ret = BT_AVRCP_ERROR_INVALID_PARAM;
202 loop_status = (gchar *)g_variant_get_string(value, NULL);
203 BT_DBG("Value: %s\n", loop_status);
205 if (g_strcmp0(loop_status, "Track") == 0)
206 status = REPEAT_SINGLE_TRACK;
207 else if (g_strcmp0(loop_status, "Playlist") == 0)
208 status = REPEAT_ALL_TRACK;
209 else if (g_strcmp0(loop_status, "None") == 0)
210 status = REPEAT_MODE_OFF;
212 status = REPEAT_INVALID;
214 _bt_send_event(BT_AVRCP_EVENT,
215 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
216 g_variant_new("(u)", status));
224 g_variant_unref(value);
225 err = __bt_avrcp_set_error(ret);
226 g_dbus_method_invocation_return_gerror(invocation, err);
231 static const GDBusInterfaceVTable method_table = {
232 __bt_avrcp_agent_method,
237 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
238 (const gchar *introspection_data)
241 GDBusNodeInfo *node_info = NULL;
243 if (introspection_data == NULL)
246 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
249 BT_ERR("Unable to create node: %s", err->message);
256 static GDBusProxy *__bt_avrcp_gdbus_init_service_proxy(void)
263 if (bt_gdbus_conn == NULL)
264 bt_gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
266 if (!bt_gdbus_conn) {
268 BT_ERR("Unable to connect to gdbus: %s", err->message);
274 adapter_path = _bt_get_adapter_path();
275 retv_if(adapter_path == NULL, NULL);
277 proxy = g_dbus_proxy_new_sync(bt_gdbus_conn,
278 G_DBUS_PROXY_FLAGS_NONE, NULL,
279 BT_BLUEZ_NAME, adapter_path,
280 BT_MEDIA_INTERFACE, NULL, &err);
281 g_free(adapter_path);
284 BT_ERR("Unable to create proxy");
286 BT_ERR("Error: %s", err->message);
296 static GDBusProxy *__bt_avrcp_gdbus_get_service_proxy(void)
298 return (service_gproxy) ? service_gproxy :
299 __bt_avrcp_gdbus_init_service_proxy();
302 int _bt_register_media_player(void)
306 gboolean shuffle_status;
308 GDBusConnection *conn;
309 GDBusNodeInfo *node_info;
311 GVariantBuilder *builder;
313 GError *error = NULL;
315 media_player_settings_t player_settings = {0,};
317 player_settings.repeat = REPEAT_MODE_OFF;
318 player_settings.status = STATUS_STOPPED;
319 player_settings.position = 0;
320 shuffle_status = FALSE;
322 conn = _bt_get_system_gconn();
323 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
324 bt_gdbus_conn = conn;
326 node_info = __bt_avrcp_create_method_node_info(
327 bt_avrcp_bluez_introspection_xml);
328 if (node_info == NULL)
329 return BLUETOOTH_ERROR_INTERNAL;
331 avrcp_reg_id = g_dbus_connection_register_object(bt_gdbus_conn,
332 BT_MEDIA_OBJECT_PATH,
333 node_info->interfaces[0],
336 g_dbus_node_info_unref(node_info);
338 if (avrcp_reg_id == 0) {
339 BT_ERR("Failed to register: %s", error->message);
340 g_clear_error(&error);
341 return BLUETOOTH_ERROR_INTERNAL;
344 adapter_path = _bt_get_adapter_path();
345 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
347 proxy = g_dbus_proxy_new_sync(conn,
348 G_DBUS_PROXY_FLAGS_NONE, NULL,
349 BT_BLUEZ_NAME, adapter_path,
350 BT_MEDIA_INTERFACE, NULL, &error);
351 g_free(adapter_path);
354 BT_ERR("Unable to create proxy");
356 BT_ERR("Error: %s", error->message);
357 g_clear_error(&error);
359 return BLUETOOTH_ERROR_INTERNAL;
362 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
364 g_variant_builder_add(builder, "{sv}", "LoopStatus",
366 loopstatus_settings[player_settings.repeat].property));
367 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
369 g_variant_builder_add(builder, "{sv}", "Shuffle",
370 g_variant_new("b", shuffle_status));
372 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
374 player_status[player_settings.status].property));
375 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
377 g_variant_builder_add(builder, "{sv}", "Position",
378 g_variant_new("u", player_settings.position));
380 path = g_strdup(BT_MEDIA_OBJECT_PATH);
381 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
382 g_variant_new("(oa{sv})", path, builder),
383 G_DBUS_CALL_FLAGS_NONE, -1,
386 g_object_unref(proxy);
388 g_variant_builder_unref(builder);
391 BT_ERR("Call RegisterPlayer Failed");
393 BT_ERR("errCode[%x], message[%s]",
394 error->code, error->message);
395 g_clear_error(&error);
397 return BLUETOOTH_ERROR_INTERNAL;
400 g_variant_unref(ret);
401 return BLUETOOTH_ERROR_NONE;
404 static void __bt_avrcp_unregister_object_path(void)
406 if (avrcp_reg_id > 0) {
407 g_dbus_connection_unregister_object(bt_gdbus_conn,
413 int _bt_unregister_media_player(void)
418 GError *error = NULL;
419 GDBusConnection *conn;
422 conn = bt_gdbus_conn;
423 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
425 proxy = __bt_avrcp_gdbus_get_service_proxy();
427 return BLUETOOTH_ERROR_INTERNAL;
429 path = g_strdup(BT_MEDIA_OBJECT_PATH);
430 BT_DBG("path is [%s]", path);
432 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
433 g_variant_new("(o)", path),
434 G_DBUS_CALL_FLAGS_NONE, -1,
439 BT_ERR("UnregisterPlayer failed");
441 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
442 error->code, error->message);
443 g_clear_error(&error);
445 return BLUETOOTH_ERROR_INTERNAL;
448 __bt_avrcp_unregister_object_path();
450 g_variant_unref(ret);
451 g_object_unref(bt_gdbus_conn);
452 bt_gdbus_conn = NULL;
455 return BLUETOOTH_ERROR_NONE;
458 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
461 char *interface = BT_MEDIA_PLAYER_INTERFACE;
462 GDBusConnection *conn;
463 GError *error = NULL;
464 GVariantBuilder *builder = NULL;
465 GVariantBuilder *inner_builder = NULL;
466 GVariant *children[1];
469 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
471 conn = bt_gdbus_conn;
472 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
474 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
475 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
477 g_variant_builder_add(inner_builder, "{sv}",
478 "xesam:title", g_variant_new_string(meta_data->title));
480 children[0] = g_variant_new_string(meta_data->artist);
481 g_variant_builder_add(inner_builder, "{sv}",
482 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
485 g_variant_builder_add(inner_builder, "{sv}",
486 "xesam:album", g_variant_new_string(meta_data->album));
488 children[0] = g_variant_new_string(meta_data->genre);
489 g_variant_builder_add(inner_builder, "{sv}",
490 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
493 g_variant_builder_add(inner_builder, "{sv}",
494 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
496 g_variant_builder_add(inner_builder, "{sv}",
497 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
499 g_variant_builder_add(inner_builder, "{sv}",
500 "mpris:lenght", g_variant_new_int64(meta_data->duration));
502 g_variant_builder_add(builder, "{sv}",
503 "Metadata", g_variant_new("a{sv}", inner_builder));
505 ret = g_dbus_connection_emit_signal(conn, NULL, BT_MEDIA_OBJECT_PATH,
506 DBUS_INTERFACE_PROPERTIES,
508 g_variant_new("(sa{sv})",
512 g_variant_builder_unref(inner_builder);
513 g_variant_builder_unref(builder);
517 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
518 error->code, error->message);
519 g_clear_error(&error);
524 return BLUETOOTH_ERROR_NONE;
527 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
530 GDBusConnection *conn;
532 media_metadata_attributes_t meta_data;
534 GVariantBuilder *builder = NULL;
535 GVariant *children[1];
537 conn = bt_gdbus_conn;
538 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
542 value = properties->repeat;
543 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
544 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
545 g_variant_new_string(loopstatus_settings[value].property))) {
546 BT_ERR("Error sending the PropertyChanged signal \n");
547 return BLUETOOTH_ERROR_INTERNAL;
551 value = properties->shuffle;
552 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
557 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
558 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
559 g_variant_new_boolean(shuffle))) {
560 BT_ERR("Error sending the PropertyChanged signal \n");
561 return BLUETOOTH_ERROR_INTERNAL;
565 value = properties->status;
566 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
567 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
568 g_variant_new_string(player_status[value].property))) {
569 BT_ERR("Error sending the PropertyChanged signal \n");
570 return BLUETOOTH_ERROR_INTERNAL;
574 value = properties->position;
575 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
576 BT_MEDIA_PLAYER_INTERFACE, "Position",
577 g_variant_new_uint32(value))) {
578 BT_ERR("Error sending the PropertyChanged signal \n");
579 return BLUETOOTH_ERROR_INTERNAL;
583 meta_data = properties->metadata;
585 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
586 g_variant_builder_add(builder, "{sv}",
587 "xesam:title", g_variant_new_string(meta_data.title));
589 children[0] = g_variant_new_string(meta_data.artist);
590 g_variant_builder_add(builder, "{sv}",
591 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
594 g_variant_builder_add(builder, "{sv}",
595 "xesam:album", g_variant_new_string(meta_data.album));
597 children[0] = g_variant_new_string(meta_data.genre);
598 g_variant_builder_add(builder, "{sv}",
599 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
602 g_variant_builder_add(builder, "{sv}",
603 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
605 g_variant_builder_add(builder, "{sv}",
606 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
608 g_variant_builder_add(builder, "{sv}",
609 "mpris:lenght", g_variant_new_int64(meta_data.duration));
611 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
612 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
613 g_variant_new("a{sv}", builder))) {
614 BT_ERR("Error sending the PropertyChanged signal \n");
615 g_variant_builder_unref(builder);
616 return BLUETOOTH_ERROR_INTERNAL;
618 g_variant_builder_unref(builder);
621 BT_ERR("Invalid Type\n");
622 return BLUETOOTH_ERROR_INTERNAL;
625 return BLUETOOTH_ERROR_NONE;
628 int _bt_avrcp_set_properties(media_player_settings_t *properties)
632 if (_bt_avrcp_set_interal_property(REPEAT,
633 properties) != BLUETOOTH_ERROR_NONE) {
634 return BLUETOOTH_ERROR_INTERNAL;
636 if (_bt_avrcp_set_interal_property(SHUFFLE,
637 properties) != BLUETOOTH_ERROR_NONE) {
638 return BLUETOOTH_ERROR_INTERNAL;
641 if (_bt_avrcp_set_interal_property(STATUS,
642 properties) != BLUETOOTH_ERROR_NONE) {
643 return BLUETOOTH_ERROR_INTERNAL;
646 if (_bt_avrcp_set_interal_property(POSITION,
647 properties) != BLUETOOTH_ERROR_NONE) {
648 return BLUETOOTH_ERROR_INTERNAL;
651 if (_bt_avrcp_set_interal_property(METADATA,
652 properties) != BLUETOOTH_ERROR_NONE) {
653 return BLUETOOTH_ERROR_INTERNAL;
656 return BLUETOOTH_ERROR_NONE;
659 int _bt_avrcp_set_property(int type, unsigned int value)
662 media_player_settings_t properties;
666 properties.repeat = value;
669 properties.shuffle = value;
672 properties.status = value;
675 properties.position = value;
678 BT_DBG("Invalid Type\n");
679 return BLUETOOTH_ERROR_INTERNAL;
682 if (_bt_avrcp_set_interal_property(type,
683 &properties) != BLUETOOTH_ERROR_NONE)
684 return BLUETOOTH_ERROR_INTERNAL;
688 return BLUETOOTH_ERROR_NONE;