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.
22 #if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT)
23 #include <syspopup_caller.h>
25 #include <dbus/dbus.h>
27 #include "bluetooth-api.h"
28 #include "bt-internal-types.h"
29 #include "bt-service-common.h"
30 #include "bt-service-avrcp.h"
31 #include "bt-service-event.h"
32 #include "bt-service-util.h"
33 #include "bt-service-audio.h"
35 static bt_player_settinngs_t loopstatus_settings[] = {
36 { REPEAT_INVALID, "" },
37 { REPEAT_MODE_OFF, "None" },
38 { REPEAT_SINGLE_TRACK, "Track" },
39 { REPEAT_ALL_TRACK, "Playlist" },
40 { REPEAT_INVALID, "" }
43 static bt_player_settinngs_t shuffle_settings[] = {
44 { SHUFFLE_INVALID, "" },
45 { SHUFFLE_MODE_OFF, "off" },
46 { SHUFFLE_ALL_TRACK, "alltracks" },
47 { SHUFFLE_GROUP, "group" },
48 { SHUFFLE_INVALID, "" }
51 static bt_player_settinngs_t player_status[] = {
52 { STATUS_STOPPED, "stopped" },
53 { STATUS_PLAYING, "playing" },
54 { STATUS_PAUSED, "paused" },
55 { STATUS_FORWARD_SEEK, "forward-seek" },
56 { STATUS_REVERSE_SEEK, "reverse-seek" },
57 { STATUS_ERROR, "error" },
58 { STATUS_INVALID, "" }
61 GDBusConnection *bt_gdbus_conn = NULL;
62 static guint avrcp_reg_id = 0;
63 static GDBusProxy *service_gproxy = NULL;
65 /* Introspection data exposed from bt-service */
66 static const gchar bt_avrcp_bluez_introspection_xml[] =
68 " <interface name='org.freedesktop.DBus.Properties'>"
69 " <method name='Set'>"
70 " <arg type='s' name='interface' direction='in'/>"
71 " <arg type='s' name='property' direction='in'/>"
72 " <arg type='v' name='value' direction='in'/>"
77 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
78 const char *path, const char *interface, const char *name,
79 const GVariant *variant)
81 GVariantBuilder *builder = NULL;
84 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
85 g_variant_builder_add(builder, "{sv}", name, variant);
87 g_dbus_connection_emit_signal(connection, NULL, path,
88 DBUS_INTERFACE_PROPERTIES,
90 g_variant_new("(sa{sv})",
94 g_variant_builder_unref(builder);
96 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
97 error->code, error->message);
98 g_clear_error(&error);
105 static GQuark __bt_avrcp_error_quark(void)
107 static GQuark quark = 0;
110 quark = g_quark_from_static_string("bt-avrcp");
115 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
117 BT_ERR("error[%d]\n", error);
120 case BT_AVRCP_ERROR_INVALID_PARAM:
121 return g_error_new(BT_AVRCP_ERROR, error,
122 BT_ERROR_INVALID_PARAM);
123 case BT_AVRCP_ERROR_INVALID_INTERFACE:
124 return g_error_new(BT_AVRCP_ERROR, error,
125 BT_ERROR_INVALID_INTERFACE);
126 case BT_AVRCP_ERROR_INTERNAL:
128 return g_error_new(BT_AVRCP_ERROR, error,
133 static void __bt_avrcp_agent_method(GDBusConnection *connection,
135 const gchar *object_path,
136 const gchar *interface_name,
137 const gchar *method_name,
138 GVariant *parameters,
139 GDBusMethodInvocation *invocation,
143 BT_INFO("method %s", method_name);
144 BT_INFO("object_path %s", object_path);
145 int ret = BT_AVRCP_ERROR_NONE;
147 gboolean shuffle_status;
149 gchar *interface = NULL;
150 gchar *property = NULL;
151 gchar *loop_status = NULL;
152 GVariant *value = NULL;
154 if (g_strcmp0(method_name, "Set") == 0) {
155 g_variant_get(parameters, "(&s&sv)", &interface, &property,
158 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
159 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
165 BT_ERR("value is NULL");
169 BT_DBG("Property: %s\n", property);
170 if (g_strcmp0(property, "Shuffle") == 0) {
172 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
174 ret = BT_AVRCP_ERROR_INVALID_PARAM;
178 shuffle_status = g_variant_get_boolean(value);
179 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
180 if (shuffle_status == TRUE)
181 status = SHUFFLE_ALL_TRACK;
183 status = SHUFFLE_MODE_OFF;
185 _bt_send_event(BT_AVRCP_EVENT,
186 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
187 g_variant_new("(u)", status));
188 } else if (g_strcmp0(property, "LoopStatus") == 0) {
190 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
192 ret = BT_AVRCP_ERROR_INVALID_PARAM;
196 loop_status = (gchar *)g_variant_get_string(value, NULL);
197 BT_DBG("Value: %s\n", loop_status);
199 if (g_strcmp0(loop_status, "Track") == 0)
200 status = REPEAT_SINGLE_TRACK;
201 else if (g_strcmp0(loop_status, "Playlist") == 0)
202 status = REPEAT_ALL_TRACK;
203 else if (g_strcmp0(loop_status, "None") == 0)
204 status = REPEAT_MODE_OFF;
206 status = REPEAT_INVALID;
208 _bt_send_event(BT_AVRCP_EVENT,
209 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
210 g_variant_new("(u)", status));
218 g_variant_unref(value);
219 err = __bt_avrcp_set_error(ret);
220 g_dbus_method_invocation_return_gerror(invocation, err);
225 static const GDBusInterfaceVTable method_table = {
226 __bt_avrcp_agent_method,
231 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
232 (const gchar *introspection_data)
235 GDBusNodeInfo *node_info = NULL;
237 if (introspection_data == NULL)
240 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
243 BT_ERR("Unable to create node: %s", err->message);
250 static GDBusProxy *__bt_avrcp_gdbus_init_service_proxy(void)
257 if (bt_gdbus_conn == NULL)
258 bt_gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
260 if (!bt_gdbus_conn) {
262 BT_ERR("Unable to connect to gdbus: %s", err->message);
268 adapter_path = _bt_get_adapter_path();
269 retv_if(adapter_path == NULL, NULL);
271 proxy = g_dbus_proxy_new_sync(bt_gdbus_conn,
272 G_DBUS_PROXY_FLAGS_NONE, NULL,
273 BT_BLUEZ_NAME, adapter_path,
274 BT_MEDIA_INTERFACE, NULL, &err);
275 g_free(adapter_path);
278 BT_ERR("Unable to create proxy");
280 BT_ERR("Error: %s", err->message);
290 static GDBusProxy *__bt_avrcp_gdbus_get_service_proxy(void)
292 return (service_gproxy) ? service_gproxy :
293 __bt_avrcp_gdbus_init_service_proxy();
296 int _bt_register_media_player(void)
300 gboolean shuffle_status;
302 GDBusConnection *conn;
303 GDBusNodeInfo *node_info;
305 GVariantBuilder *builder;
307 GError *error = NULL;
309 media_player_settings_t player_settings = {0,};
311 player_settings.repeat = REPEAT_MODE_OFF;
312 player_settings.status = STATUS_STOPPED;
313 player_settings.position = 0;
314 shuffle_status = FALSE;
316 conn = _bt_get_system_gconn();
317 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
318 bt_gdbus_conn = conn;
320 node_info = __bt_avrcp_create_method_node_info(
321 bt_avrcp_bluez_introspection_xml);
322 if (node_info == NULL)
323 return BLUETOOTH_ERROR_INTERNAL;
325 avrcp_reg_id = g_dbus_connection_register_object(bt_gdbus_conn,
326 BT_MEDIA_OBJECT_PATH,
327 node_info->interfaces[0],
330 g_dbus_node_info_unref(node_info);
332 if (avrcp_reg_id == 0) {
333 BT_ERR("Failed to register: %s", error->message);
334 g_clear_error(&error);
335 return BLUETOOTH_ERROR_INTERNAL;
338 adapter_path = _bt_get_adapter_path();
339 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
341 proxy = g_dbus_proxy_new_sync(conn,
342 G_DBUS_PROXY_FLAGS_NONE, NULL,
343 BT_BLUEZ_NAME, adapter_path,
344 BT_MEDIA_INTERFACE, NULL, &error);
345 g_free(adapter_path);
348 BT_ERR("Unable to create proxy");
350 BT_ERR("Error: %s", error->message);
351 g_clear_error(&error);
353 return BLUETOOTH_ERROR_INTERNAL;
356 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
358 g_variant_builder_add(builder, "{sv}", "LoopStatus",
360 loopstatus_settings[player_settings.repeat].property));
361 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
363 g_variant_builder_add(builder, "{sv}", "Shuffle",
364 g_variant_new("b", shuffle_status));
366 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
368 player_status[player_settings.status].property));
369 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
371 g_variant_builder_add(builder, "{sv}", "Position",
372 g_variant_new("u", player_settings.position));
374 path = g_strdup(BT_MEDIA_OBJECT_PATH);
375 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
376 g_variant_new("(oa{sv})", path, builder),
377 G_DBUS_CALL_FLAGS_NONE, -1,
380 g_object_unref(proxy);
382 g_variant_builder_unref(builder);
385 BT_ERR("Call RegisterPlayer Failed");
387 BT_ERR("errCode[%x], message[%s]",
388 error->code, error->message);
389 g_clear_error(&error);
391 return BLUETOOTH_ERROR_INTERNAL;
394 g_variant_unref(ret);
395 return BLUETOOTH_ERROR_NONE;
398 static void __bt_avrcp_unregister_object_path(void)
400 if (avrcp_reg_id > 0) {
401 g_dbus_connection_unregister_object(bt_gdbus_conn,
407 int _bt_unregister_media_player(void)
412 GError *error = NULL;
413 GDBusConnection *conn;
416 conn = bt_gdbus_conn;
417 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
419 proxy = __bt_avrcp_gdbus_get_service_proxy();
421 return BLUETOOTH_ERROR_INTERNAL;
423 path = g_strdup(BT_MEDIA_OBJECT_PATH);
424 BT_DBG("path is [%s]", path);
426 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
427 g_variant_new("(o)", path),
428 G_DBUS_CALL_FLAGS_NONE, -1,
433 BT_ERR("UnregisterPlayer failed");
435 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
436 error->code, error->message);
437 g_clear_error(&error);
439 return BLUETOOTH_ERROR_INTERNAL;
442 __bt_avrcp_unregister_object_path();
444 g_variant_unref(ret);
445 g_object_unref(bt_gdbus_conn);
446 bt_gdbus_conn = NULL;
449 return BLUETOOTH_ERROR_NONE;
452 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
455 char *interface = BT_MEDIA_PLAYER_INTERFACE;
456 GDBusConnection *conn;
457 GError *error = NULL;
458 GVariantBuilder *builder = NULL;
459 GVariantBuilder *inner_builder = NULL;
460 GVariant *children[1];
463 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
465 conn = bt_gdbus_conn;
466 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
468 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
469 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
471 g_variant_builder_add(inner_builder, "{sv}",
472 "xesam:title", g_variant_new_string(meta_data->title));
474 children[0] = g_variant_new_string(meta_data->artist);
475 g_variant_builder_add(inner_builder, "{sv}",
476 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
479 g_variant_builder_add(inner_builder, "{sv}",
480 "xesam:album", g_variant_new_string(meta_data->album));
482 children[0] = g_variant_new_string(meta_data->genre);
483 g_variant_builder_add(inner_builder, "{sv}",
484 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
487 g_variant_builder_add(inner_builder, "{sv}",
488 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
490 g_variant_builder_add(inner_builder, "{sv}",
491 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
493 g_variant_builder_add(inner_builder, "{sv}",
494 "mpris:lenght", g_variant_new_int64(meta_data->duration));
496 g_variant_builder_add(builder, "{sv}",
497 "Metadata", g_variant_new("a{sv}", inner_builder));
499 ret = g_dbus_connection_emit_signal(conn, NULL, BT_MEDIA_OBJECT_PATH,
500 DBUS_INTERFACE_PROPERTIES,
502 g_variant_new("(sa{sv})",
506 g_variant_builder_unref(inner_builder);
507 g_variant_builder_unref(builder);
511 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
512 error->code, error->message);
513 g_clear_error(&error);
518 return BLUETOOTH_ERROR_NONE;
521 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
524 GDBusConnection *conn;
526 media_metadata_attributes_t meta_data;
528 GVariantBuilder *builder = NULL;
529 GVariant *children[1];
531 conn = bt_gdbus_conn;
532 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
536 value = properties->repeat;
537 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
538 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
539 g_variant_new_string(loopstatus_settings[value].property))) {
540 BT_ERR("Error sending the PropertyChanged signal \n");
541 return BLUETOOTH_ERROR_INTERNAL;
545 value = properties->shuffle;
546 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
551 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
552 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
553 g_variant_new_boolean(shuffle))) {
554 BT_ERR("Error sending the PropertyChanged signal \n");
555 return BLUETOOTH_ERROR_INTERNAL;
559 value = properties->status;
560 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
561 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
562 g_variant_new_string(player_status[value].property))) {
563 BT_ERR("Error sending the PropertyChanged signal \n");
564 return BLUETOOTH_ERROR_INTERNAL;
568 value = properties->position;
569 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
570 BT_MEDIA_PLAYER_INTERFACE, "Position",
571 g_variant_new_uint32(value))) {
572 BT_ERR("Error sending the PropertyChanged signal \n");
573 return BLUETOOTH_ERROR_INTERNAL;
577 meta_data = properties->metadata;
579 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
580 g_variant_builder_add(builder, "{sv}",
581 "xesam:title", g_variant_new_string(meta_data.title));
583 children[0] = g_variant_new_string(meta_data.artist);
584 g_variant_builder_add(builder, "{sv}",
585 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
588 g_variant_builder_add(builder, "{sv}",
589 "xesam:album", g_variant_new_string(meta_data.album));
591 children[0] = g_variant_new_string(meta_data.genre);
592 g_variant_builder_add(builder, "{sv}",
593 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
596 g_variant_builder_add(builder, "{sv}",
597 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
599 g_variant_builder_add(builder, "{sv}",
600 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
602 g_variant_builder_add(builder, "{sv}",
603 "mpris:lenght", g_variant_new_int64(meta_data.duration));
605 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
606 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
607 g_variant_new("a{sv}", builder))) {
608 BT_ERR("Error sending the PropertyChanged signal \n");
609 g_variant_builder_unref(builder);
610 return BLUETOOTH_ERROR_INTERNAL;
612 g_variant_builder_unref(builder);
615 BT_ERR("Invalid Type\n");
616 return BLUETOOTH_ERROR_INTERNAL;
619 return BLUETOOTH_ERROR_NONE;
622 int _bt_avrcp_set_properties(media_player_settings_t *properties)
626 if (_bt_avrcp_set_interal_property(REPEAT,
627 properties) != BLUETOOTH_ERROR_NONE) {
628 return BLUETOOTH_ERROR_INTERNAL;
630 if (_bt_avrcp_set_interal_property(SHUFFLE,
631 properties) != BLUETOOTH_ERROR_NONE) {
632 return BLUETOOTH_ERROR_INTERNAL;
635 if (_bt_avrcp_set_interal_property(STATUS,
636 properties) != BLUETOOTH_ERROR_NONE) {
637 return BLUETOOTH_ERROR_INTERNAL;
640 if (_bt_avrcp_set_interal_property(POSITION,
641 properties) != BLUETOOTH_ERROR_NONE) {
642 return BLUETOOTH_ERROR_INTERNAL;
645 if (_bt_avrcp_set_interal_property(METADATA,
646 properties) != BLUETOOTH_ERROR_NONE) {
647 return BLUETOOTH_ERROR_INTERNAL;
650 return BLUETOOTH_ERROR_NONE;
653 int _bt_avrcp_set_property(int type, unsigned int value)
656 media_player_settings_t properties;
660 properties.repeat = value;
663 properties.shuffle = value;
666 properties.status = value;
669 properties.position = value;
672 BT_DBG("Invalid Type\n");
673 return BLUETOOTH_ERROR_INTERNAL;
676 if (_bt_avrcp_set_interal_property(type,
677 &properties) != BLUETOOTH_ERROR_NONE)
678 return BLUETOOTH_ERROR_INTERNAL;
682 return BLUETOOTH_ERROR_NONE;