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 #include <syspopup_caller.h>
23 #include <dbus/dbus.h>
25 #include "bluetooth-api.h"
26 #include "bt-internal-types.h"
27 #include "bt-service-common.h"
28 #include "bt-service-avrcp.h"
29 #include "bt-service-event.h"
30 #include "bt-service-util.h"
31 #include "bt-service-audio.h"
33 static bt_player_settinngs_t loopstatus_settings[] = {
34 { REPEAT_INVALID, "" },
35 { REPEAT_MODE_OFF, "None" },
36 { REPEAT_SINGLE_TRACK, "Track" },
37 { REPEAT_ALL_TRACK, "Playlist" },
38 { REPEAT_INVALID, "" }
41 static bt_player_settinngs_t shuffle_settings[] = {
42 { SHUFFLE_INVALID, "" },
43 { SHUFFLE_MODE_OFF, "off" },
44 { SHUFFLE_ALL_TRACK, "alltracks" },
45 { SHUFFLE_GROUP, "group" },
46 { SHUFFLE_INVALID, "" }
49 static bt_player_settinngs_t player_status[] = {
50 { STATUS_STOPPED, "stopped" },
51 { STATUS_PLAYING, "playing" },
52 { STATUS_PAUSED, "paused" },
53 { STATUS_FORWARD_SEEK, "forward-seek" },
54 { STATUS_REVERSE_SEEK, "reverse-seek" },
55 { STATUS_ERROR, "error" },
56 { STATUS_INVALID, "" }
59 static GDBusConnection *bt_gdbus_conn = NULL;
60 static guint avrcp_reg_id = 0;
62 /* Introspection data exposed from bt-service */
63 static const gchar bt_avrcp_bluez_introspection_xml[] =
65 " <interface name='org.freedesktop.DBus.Properties'>"
66 " <method name='Set'>"
67 " <arg type='s' name='interface' direction='in'/>"
68 " <arg type='s' name='property' direction='in'/>"
69 " <arg type='v' name='value' direction='in'/>"
74 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
75 const char *path, const char *interface, const char *name,
76 const GVariant *variant)
78 GVariantBuilder *builder = NULL;
81 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
82 g_variant_builder_add(builder, "{sv}", name, variant);
84 g_dbus_connection_emit_signal(connection, NULL, path,
85 DBUS_INTERFACE_PROPERTIES,
87 g_variant_new("(sa{sv})",
91 g_variant_builder_unref(builder);
93 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
94 error->code, error->message);
95 g_clear_error(&error);
102 static GQuark __bt_avrcp_error_quark(void)
104 static GQuark quark = 0;
107 quark = g_quark_from_static_string("bt-avrcp");
112 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
114 BT_ERR("error[%d]\n", error);
117 case BT_AVRCP_ERROR_INVALID_PARAM:
118 return g_error_new(BT_AVRCP_ERROR, error,
119 BT_ERROR_INVALID_PARAM);
120 case BT_AVRCP_ERROR_INVALID_INTERFACE:
121 return g_error_new(BT_AVRCP_ERROR, error,
122 BT_ERROR_INVALID_INTERFACE);
123 case BT_AVRCP_ERROR_INTERNAL:
125 return g_error_new(BT_AVRCP_ERROR, error,
130 static void __bt_avrcp_agent_method(GDBusConnection *connection,
132 const gchar *object_path,
133 const gchar *interface_name,
134 const gchar *method_name,
135 GVariant *parameters,
136 GDBusMethodInvocation *invocation,
140 BT_INFO("method %s", method_name);
141 BT_INFO("object_path %s", object_path);
142 int ret = BT_AVRCP_ERROR_NONE;
144 gboolean shuffle_status;
146 gchar *interface = NULL;
147 gchar *property = NULL;
148 gchar *loop_status = NULL;
149 GVariant *value = NULL;
151 if (g_strcmp0(method_name, "Set") == 0) {
152 g_variant_get(parameters, "(&s&sv)", &interface, &property,
155 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
156 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
162 BT_ERR("value is NULL");
166 BT_DBG("Property: %s\n", property);
167 if (g_strcmp0(property, "Shuffle") == 0) {
169 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
171 ret = BT_AVRCP_ERROR_INVALID_PARAM;
175 shuffle_status = g_variant_get_boolean(value);
176 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
177 if (shuffle_status == TRUE)
178 status = SHUFFLE_ALL_TRACK;
180 status = SHUFFLE_MODE_OFF;
182 _bt_send_event(BT_AVRCP_EVENT,
183 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
184 g_variant_new("(u)", status));
185 } else if (g_strcmp0(property, "LoopStatus") == 0) {
187 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
189 ret = BT_AVRCP_ERROR_INVALID_PARAM;
193 loop_status = (gchar *)g_variant_get_string(value, NULL);
194 BT_DBG("Value: %s\n", loop_status);
196 if (g_strcmp0(loop_status, "Track") == 0)
197 status = REPEAT_SINGLE_TRACK;
198 else if (g_strcmp0(loop_status, "Playlist") == 0)
199 status = REPEAT_ALL_TRACK;
200 else if (g_strcmp0(loop_status, "None") == 0)
201 status = REPEAT_MODE_OFF;
203 status = REPEAT_INVALID;
205 _bt_send_event(BT_AVRCP_EVENT,
206 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
207 g_variant_new("(u)", status));
215 g_variant_unref(value);
216 err = __bt_avrcp_set_error(ret);
217 g_dbus_method_invocation_return_gerror(invocation, err);
222 static const GDBusInterfaceVTable method_table = {
223 __bt_avrcp_agent_method,
228 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
229 (const gchar *introspection_data)
232 GDBusNodeInfo *node_info = NULL;
234 if (introspection_data == NULL)
237 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
240 BT_ERR("Unable to create node: %s", err->message);
247 int _bt_register_media_player(void)
251 gboolean shuffle_status;
253 GDBusNodeInfo *node_info;
255 GVariantBuilder *builder;
257 GError *error = NULL;
259 media_player_settings_t player_settings = {0,};
261 player_settings.repeat = REPEAT_MODE_OFF;
262 player_settings.status = STATUS_STOPPED;
263 player_settings.position = 0;
264 shuffle_status = FALSE;
266 if (bt_gdbus_conn == NULL) {
267 bt_gdbus_conn = _bt_get_system_gconn();
268 retv_if(bt_gdbus_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
271 node_info = __bt_avrcp_create_method_node_info(
272 bt_avrcp_bluez_introspection_xml);
273 if (node_info == NULL)
274 return BLUETOOTH_ERROR_INTERNAL;
276 avrcp_reg_id = g_dbus_connection_register_object(bt_gdbus_conn,
277 BT_MEDIA_OBJECT_PATH,
278 node_info->interfaces[0],
281 g_dbus_node_info_unref(node_info);
283 if (avrcp_reg_id == 0) {
284 BT_ERR("Failed to register: %s", error->message);
285 g_clear_error(&error);
286 return BLUETOOTH_ERROR_INTERNAL;
289 adapter_path = _bt_get_adapter_path();
290 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
292 proxy = g_dbus_proxy_new_sync(bt_gdbus_conn,
293 G_DBUS_PROXY_FLAGS_NONE, NULL,
294 BT_BLUEZ_NAME, adapter_path,
295 BT_MEDIA_INTERFACE, NULL, &error);
296 g_free(adapter_path);
299 BT_ERR("Unable to create proxy");
301 BT_ERR("Error: %s", error->message);
302 g_clear_error(&error);
304 return BLUETOOTH_ERROR_INTERNAL;
307 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
309 g_variant_builder_add(builder, "{sv}", "LoopStatus",
311 loopstatus_settings[player_settings.repeat].property));
312 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
314 g_variant_builder_add(builder, "{sv}", "Shuffle",
315 g_variant_new("b", shuffle_status));
317 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
319 player_status[player_settings.status].property));
320 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
322 g_variant_builder_add(builder, "{sv}", "Position",
323 g_variant_new("u", player_settings.position));
325 path = g_strdup(BT_MEDIA_OBJECT_PATH);
326 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
327 g_variant_new("(oa{sv})", path, builder),
328 G_DBUS_CALL_FLAGS_NONE, -1,
331 g_object_unref(proxy);
333 g_variant_builder_unref(builder);
336 BT_ERR("Call RegisterPlayer Failed");
338 BT_ERR("errCode[%x], message[%s]",
339 error->code, error->message);
340 g_clear_error(&error);
342 return BLUETOOTH_ERROR_INTERNAL;
345 g_variant_unref(ret);
346 return BLUETOOTH_ERROR_NONE;
349 static void __bt_avrcp_unregister_object_path(void)
351 if (avrcp_reg_id > 0) {
352 g_dbus_connection_unregister_object(bt_gdbus_conn,
358 int _bt_unregister_media_player(void)
364 GError *error = NULL;
366 int result = BLUETOOTH_ERROR_NONE;
368 retv_if(bt_gdbus_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
370 adapter_path = _bt_get_adapter_path();
371 if (adapter_path == NULL) {
372 result = BLUETOOTH_ERROR_INTERNAL;
376 proxy = g_dbus_proxy_new_sync(bt_gdbus_conn,
377 G_DBUS_PROXY_FLAGS_NONE, NULL,
378 BT_BLUEZ_NAME, adapter_path,
379 BT_MEDIA_INTERFACE, NULL, &error);
380 g_free(adapter_path);
383 BT_ERR("Unable to create proxy");
385 BT_ERR("Error: %s", error->message);
386 g_clear_error(&error);
388 result = BLUETOOTH_ERROR_INTERNAL;
392 path = g_strdup(BT_MEDIA_OBJECT_PATH);
393 BT_DBG("path is [%s]", path);
395 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
396 g_variant_new("(o)", path),
397 G_DBUS_CALL_FLAGS_NONE, -1,
400 g_object_unref(proxy);
403 BT_ERR("UnregisterPlayer failed");
405 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
406 error->code, error->message);
407 g_clear_error(&error);
409 result = BLUETOOTH_ERROR_INTERNAL;
411 g_variant_unref(ret);
414 __bt_avrcp_unregister_object_path();
417 g_object_unref(bt_gdbus_conn);
418 bt_gdbus_conn = NULL;
425 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
428 char *interface = BT_MEDIA_PLAYER_INTERFACE;
429 GDBusConnection *conn;
430 GError *error = NULL;
431 GVariantBuilder *builder = NULL;
432 GVariantBuilder *inner_builder = NULL;
433 GVariant *children[1];
436 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
438 conn = bt_gdbus_conn;
439 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
441 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
442 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
444 g_variant_builder_add(inner_builder, "{sv}",
445 "xesam:title", g_variant_new_string(meta_data->title));
447 children[0] = g_variant_new_string(meta_data->artist);
448 g_variant_builder_add(inner_builder, "{sv}",
449 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
452 g_variant_builder_add(inner_builder, "{sv}",
453 "xesam:album", g_variant_new_string(meta_data->album));
455 children[0] = g_variant_new_string(meta_data->genre);
456 g_variant_builder_add(inner_builder, "{sv}",
457 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
460 g_variant_builder_add(inner_builder, "{sv}",
461 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
463 g_variant_builder_add(inner_builder, "{sv}",
464 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
466 g_variant_builder_add(inner_builder, "{sv}",
467 "mpris:length", g_variant_new_int64(meta_data->duration));
469 g_variant_builder_add(builder, "{sv}",
470 "Metadata", g_variant_new("a{sv}", inner_builder));
472 ret = g_dbus_connection_emit_signal(conn, NULL, BT_MEDIA_OBJECT_PATH,
473 DBUS_INTERFACE_PROPERTIES,
475 g_variant_new("(sa{sv})",
479 g_variant_builder_unref(inner_builder);
480 g_variant_builder_unref(builder);
484 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
485 error->code, error->message);
486 g_clear_error(&error);
491 return BLUETOOTH_ERROR_NONE;
494 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
497 GDBusConnection *conn;
499 media_metadata_attributes_t meta_data;
501 GVariantBuilder *builder = NULL;
502 GVariant *children[1];
504 conn = bt_gdbus_conn;
505 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
509 value = properties->repeat;
510 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
511 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
512 g_variant_new_string(loopstatus_settings[value].property))) {
513 BT_ERR("Error sending the PropertyChanged signal \n");
514 return BLUETOOTH_ERROR_INTERNAL;
518 value = properties->shuffle;
519 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
524 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
525 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
526 g_variant_new_boolean(shuffle))) {
527 BT_ERR("Error sending the PropertyChanged signal \n");
528 return BLUETOOTH_ERROR_INTERNAL;
532 value = properties->status;
533 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
534 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
535 g_variant_new_string(player_status[value].property))) {
536 BT_ERR("Error sending the PropertyChanged signal \n");
537 return BLUETOOTH_ERROR_INTERNAL;
541 value = properties->position;
542 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
543 BT_MEDIA_PLAYER_INTERFACE, "Position",
544 g_variant_new_uint32(value))) {
545 BT_ERR("Error sending the PropertyChanged signal \n");
546 return BLUETOOTH_ERROR_INTERNAL;
550 meta_data = properties->metadata;
552 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
553 g_variant_builder_add(builder, "{sv}",
554 "xesam:title", g_variant_new_string(meta_data.title));
556 children[0] = g_variant_new_string(meta_data.artist);
557 g_variant_builder_add(builder, "{sv}",
558 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
561 g_variant_builder_add(builder, "{sv}",
562 "xesam:album", g_variant_new_string(meta_data.album));
564 children[0] = g_variant_new_string(meta_data.genre);
565 g_variant_builder_add(builder, "{sv}",
566 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
569 g_variant_builder_add(builder, "{sv}",
570 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
572 g_variant_builder_add(builder, "{sv}",
573 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
575 g_variant_builder_add(builder, "{sv}",
576 "mpris:lenght", g_variant_new_int64(meta_data.duration));
578 if (!__bt_media_emit_property_changed(conn, BT_MEDIA_OBJECT_PATH,
579 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
580 g_variant_new("a{sv}", builder))) {
581 BT_ERR("Error sending the PropertyChanged signal \n");
582 g_variant_builder_unref(builder);
583 return BLUETOOTH_ERROR_INTERNAL;
585 g_variant_builder_unref(builder);
588 BT_ERR("Invalid Type\n");
589 return BLUETOOTH_ERROR_INTERNAL;
592 return BLUETOOTH_ERROR_NONE;
595 int _bt_avrcp_set_properties(media_player_settings_t *properties)
599 if (_bt_avrcp_set_interal_property(REPEAT,
600 properties) != BLUETOOTH_ERROR_NONE) {
601 return BLUETOOTH_ERROR_INTERNAL;
603 if (_bt_avrcp_set_interal_property(SHUFFLE,
604 properties) != BLUETOOTH_ERROR_NONE) {
605 return BLUETOOTH_ERROR_INTERNAL;
608 if (_bt_avrcp_set_interal_property(STATUS,
609 properties) != BLUETOOTH_ERROR_NONE) {
610 return BLUETOOTH_ERROR_INTERNAL;
613 if (_bt_avrcp_set_interal_property(POSITION,
614 properties) != BLUETOOTH_ERROR_NONE) {
615 return BLUETOOTH_ERROR_INTERNAL;
618 if (_bt_avrcp_set_interal_property(METADATA,
619 properties) != BLUETOOTH_ERROR_NONE) {
620 return BLUETOOTH_ERROR_INTERNAL;
623 return BLUETOOTH_ERROR_NONE;
626 int _bt_avrcp_set_property(int type, unsigned int value)
629 media_player_settings_t properties;
633 properties.repeat = value;
636 properties.shuffle = value;
639 properties.status = value;
642 properties.position = value;
645 BT_DBG("Invalid Type\n");
646 return BLUETOOTH_ERROR_INTERNAL;
649 if (_bt_avrcp_set_interal_property(type,
650 &properties) != BLUETOOTH_ERROR_NONE)
651 return BLUETOOTH_ERROR_INTERNAL;
655 return BLUETOOTH_ERROR_NONE;