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 guint avrcp_reg_id = 0;
61 /* Introspection data exposed from bt-service */
62 static const gchar bt_avrcp_bluez_introspection_xml[] =
64 " <interface name='org.freedesktop.DBus.Properties'>"
65 " <method name='Set'>"
66 " <arg type='s' name='interface' direction='in'/>"
67 " <arg type='s' name='property' direction='in'/>"
68 " <arg type='v' name='value' direction='in'/>"
73 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
74 const char *path, const char *interface, const char *name,
75 const GVariant *variant)
77 GVariantBuilder *builder = NULL;
80 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
81 g_variant_builder_add(builder, "{sv}", name, variant);
83 g_dbus_connection_emit_signal(connection, NULL, path,
84 DBUS_INTERFACE_PROPERTIES,
86 g_variant_new("(sa{sv})",
90 g_variant_builder_unref(builder);
92 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
93 error->code, error->message);
94 g_clear_error(&error);
101 static GQuark __bt_avrcp_error_quark(void)
103 static GQuark quark = 0;
106 quark = g_quark_from_static_string("bt-avrcp");
111 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
113 BT_ERR("error[%d]\n", error);
116 case BT_AVRCP_ERROR_INVALID_PARAM:
117 return g_error_new(BT_AVRCP_ERROR, error,
118 BT_ERROR_INVALID_PARAM);
119 case BT_AVRCP_ERROR_INVALID_INTERFACE:
120 return g_error_new(BT_AVRCP_ERROR, error,
121 BT_ERROR_INVALID_INTERFACE);
122 case BT_AVRCP_ERROR_INTERNAL:
124 return g_error_new(BT_AVRCP_ERROR, error,
129 static void __bt_avrcp_agent_method(GDBusConnection *connection,
131 const gchar *object_path,
132 const gchar *interface_name,
133 const gchar *method_name,
134 GVariant *parameters,
135 GDBusMethodInvocation *invocation,
139 BT_INFO("method %s", method_name);
140 BT_INFO("object_path %s", object_path);
141 int ret = BT_AVRCP_ERROR_NONE;
143 gboolean shuffle_status;
145 gchar *interface = NULL;
146 gchar *property = NULL;
147 gchar *loop_status = NULL;
148 GVariant *value = NULL;
150 if (g_strcmp0(method_name, "Set") == 0) {
151 g_variant_get(parameters, "(&s&sv)", &interface, &property,
154 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
155 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
161 BT_ERR("value is NULL");
165 BT_DBG("Property: %s\n", property);
166 if (g_strcmp0(property, "Shuffle") == 0) {
168 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
170 ret = BT_AVRCP_ERROR_INVALID_PARAM;
174 shuffle_status = g_variant_get_boolean(value);
175 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
176 if (shuffle_status == TRUE)
177 status = SHUFFLE_ALL_TRACK;
179 status = SHUFFLE_MODE_OFF;
181 _bt_send_event(BT_AVRCP_EVENT,
182 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
183 g_variant_new("(u)", status));
184 } else if (g_strcmp0(property, "LoopStatus") == 0) {
186 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
188 ret = BT_AVRCP_ERROR_INVALID_PARAM;
192 loop_status = (gchar *)g_variant_get_string(value, NULL);
193 BT_DBG("Value: %s\n", loop_status);
195 if (g_strcmp0(loop_status, "Track") == 0)
196 status = REPEAT_SINGLE_TRACK;
197 else if (g_strcmp0(loop_status, "Playlist") == 0)
198 status = REPEAT_ALL_TRACK;
199 else if (g_strcmp0(loop_status, "None") == 0)
200 status = REPEAT_MODE_OFF;
202 status = REPEAT_INVALID;
204 _bt_send_event(BT_AVRCP_EVENT,
205 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
206 g_variant_new("(u)", status));
214 g_variant_unref(value);
215 err = __bt_avrcp_set_error(ret);
216 g_dbus_method_invocation_return_gerror(invocation, err);
221 static const GDBusInterfaceVTable method_table = {
222 __bt_avrcp_agent_method,
227 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
228 (const gchar *introspection_data)
231 GDBusNodeInfo *node_info = NULL;
233 if (introspection_data == NULL)
236 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
239 BT_ERR("Unable to create node: %s", err->message);
246 int _bt_register_media_player(void)
249 GDBusConnection *g_conn;
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 g_conn = _bt_gdbus_get_system_gconn();
267 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
269 node_info = __bt_avrcp_create_method_node_info(
270 bt_avrcp_bluez_introspection_xml);
271 if (node_info == NULL)
272 return BLUETOOTH_ERROR_INTERNAL;
274 avrcp_reg_id = g_dbus_connection_register_object(g_conn,
275 BT_MEDIA_OBJECT_PATH,
276 node_info->interfaces[0],
279 g_dbus_node_info_unref(node_info);
281 if (avrcp_reg_id == 0) {
282 BT_ERR("Failed to register: %s", error->message);
283 g_clear_error(&error);
284 return BLUETOOTH_ERROR_INTERNAL;
287 adapter_path = _bt_get_adapter_path();
288 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
290 proxy = g_dbus_proxy_new_sync(g_conn,
291 G_DBUS_PROXY_FLAGS_NONE, NULL,
292 BT_BLUEZ_NAME, adapter_path,
293 BT_MEDIA_INTERFACE, NULL, &error);
294 g_free(adapter_path);
297 BT_ERR("Unable to create proxy");
299 BT_ERR("Error: %s", error->message);
300 g_clear_error(&error);
302 return BLUETOOTH_ERROR_INTERNAL;
305 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
307 g_variant_builder_add(builder, "{sv}", "LoopStatus",
309 loopstatus_settings[player_settings.repeat].property));
310 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
312 g_variant_builder_add(builder, "{sv}", "Shuffle",
313 g_variant_new("b", shuffle_status));
315 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
317 player_status[player_settings.status].property));
318 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
320 g_variant_builder_add(builder, "{sv}", "Position",
321 g_variant_new("u", player_settings.position));
323 path = g_strdup(BT_MEDIA_OBJECT_PATH);
324 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
325 g_variant_new("(oa{sv})", path, builder),
326 G_DBUS_CALL_FLAGS_NONE, -1,
329 g_object_unref(proxy);
331 g_variant_builder_unref(builder);
334 BT_ERR("Call RegisterPlayer Failed");
336 BT_ERR("errCode[%x], message[%s]",
337 error->code, error->message);
338 g_clear_error(&error);
340 return BLUETOOTH_ERROR_INTERNAL;
343 g_variant_unref(ret);
344 return BLUETOOTH_ERROR_NONE;
347 static void __bt_avrcp_unregister_object_path(void)
349 GDBusConnection *g_conn;
351 g_conn = _bt_gdbus_get_system_gconn();
352 ret_if(g_conn == NULL);
354 if (avrcp_reg_id > 0) {
355 g_dbus_connection_unregister_object(g_conn,
361 int _bt_unregister_media_player(void)
364 GDBusConnection *g_conn;
368 GError *error = NULL;
370 int result = BLUETOOTH_ERROR_NONE;
372 adapter_path = _bt_get_adapter_path();
373 if (adapter_path == NULL) {
374 result = BLUETOOTH_ERROR_INTERNAL;
378 g_conn = _bt_gdbus_get_system_gconn();
379 if (g_conn == NULL) {
380 BT_ERR("g_conn is NULL");
381 g_free(adapter_path);
382 result = BLUETOOTH_ERROR_INTERNAL;
386 proxy = g_dbus_proxy_new_sync(g_conn,
387 G_DBUS_PROXY_FLAGS_NONE, NULL,
388 BT_BLUEZ_NAME, adapter_path,
389 BT_MEDIA_INTERFACE, NULL, &error);
390 g_free(adapter_path);
393 BT_ERR("Unable to create proxy");
395 BT_ERR("Error: %s", error->message);
396 g_clear_error(&error);
398 result = BLUETOOTH_ERROR_INTERNAL;
402 path = g_strdup(BT_MEDIA_OBJECT_PATH);
403 BT_DBG("path is [%s]", path);
405 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
406 g_variant_new("(o)", path),
407 G_DBUS_CALL_FLAGS_NONE, -1,
410 g_object_unref(proxy);
413 BT_ERR("UnregisterPlayer failed");
415 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
416 error->code, error->message);
417 g_clear_error(&error);
419 result = BLUETOOTH_ERROR_INTERNAL;
421 g_variant_unref(ret);
424 __bt_avrcp_unregister_object_path();
430 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
433 char *interface = BT_MEDIA_PLAYER_INTERFACE;
434 GDBusConnection *g_conn;
435 GError *error = NULL;
436 GVariantBuilder *builder = NULL;
437 GVariantBuilder *inner_builder = NULL;
438 GVariant *children[1];
441 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
443 g_conn = _bt_gdbus_get_system_gconn();;
444 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
446 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
447 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
449 g_variant_builder_add(inner_builder, "{sv}",
450 "xesam:title", g_variant_new_string(meta_data->title));
452 children[0] = g_variant_new_string(meta_data->artist);
453 g_variant_builder_add(inner_builder, "{sv}",
454 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
457 g_variant_builder_add(inner_builder, "{sv}",
458 "xesam:album", g_variant_new_string(meta_data->album));
460 children[0] = g_variant_new_string(meta_data->genre);
461 g_variant_builder_add(inner_builder, "{sv}",
462 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
465 g_variant_builder_add(inner_builder, "{sv}",
466 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
468 g_variant_builder_add(inner_builder, "{sv}",
469 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
471 g_variant_builder_add(inner_builder, "{sv}",
472 "mpris:length", g_variant_new_int64(meta_data->duration));
474 g_variant_builder_add(builder, "{sv}",
475 "Metadata", g_variant_new("a{sv}", inner_builder));
477 ret = g_dbus_connection_emit_signal(g_conn, NULL, BT_MEDIA_OBJECT_PATH,
478 DBUS_INTERFACE_PROPERTIES,
480 g_variant_new("(sa{sv})",
484 g_variant_builder_unref(inner_builder);
485 g_variant_builder_unref(builder);
489 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
490 error->code, error->message);
491 g_clear_error(&error);
496 return BLUETOOTH_ERROR_NONE;
499 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
502 GDBusConnection *g_conn;
504 media_metadata_attributes_t meta_data;
506 GVariantBuilder *builder = NULL;
507 GVariant *children[1];
509 g_conn = _bt_gdbus_get_system_gconn();;
510 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
514 value = properties->repeat;
515 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
516 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
517 g_variant_new_string(loopstatus_settings[value].property))) {
518 BT_ERR("Error sending the PropertyChanged signal \n");
519 return BLUETOOTH_ERROR_INTERNAL;
523 value = properties->shuffle;
524 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
529 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
530 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
531 g_variant_new_boolean(shuffle))) {
532 BT_ERR("Error sending the PropertyChanged signal \n");
533 return BLUETOOTH_ERROR_INTERNAL;
537 value = properties->status;
538 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
539 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
540 g_variant_new_string(player_status[value].property))) {
541 BT_ERR("Error sending the PropertyChanged signal \n");
542 return BLUETOOTH_ERROR_INTERNAL;
546 value = properties->position;
547 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
548 BT_MEDIA_PLAYER_INTERFACE, "Position",
549 g_variant_new_uint32(value))) {
550 BT_ERR("Error sending the PropertyChanged signal \n");
551 return BLUETOOTH_ERROR_INTERNAL;
555 meta_data = properties->metadata;
557 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
558 g_variant_builder_add(builder, "{sv}",
559 "xesam:title", g_variant_new_string(meta_data.title));
561 children[0] = g_variant_new_string(meta_data.artist);
562 g_variant_builder_add(builder, "{sv}",
563 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
566 g_variant_builder_add(builder, "{sv}",
567 "xesam:album", g_variant_new_string(meta_data.album));
569 children[0] = g_variant_new_string(meta_data.genre);
570 g_variant_builder_add(builder, "{sv}",
571 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
574 g_variant_builder_add(builder, "{sv}",
575 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
577 g_variant_builder_add(builder, "{sv}",
578 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
580 g_variant_builder_add(builder, "{sv}",
581 "mpris:length", g_variant_new_int64(meta_data.duration));
583 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
584 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
585 g_variant_new("a{sv}", builder))) {
586 BT_ERR("Error sending the PropertyChanged signal \n");
587 g_variant_builder_unref(builder);
588 return BLUETOOTH_ERROR_INTERNAL;
590 g_variant_builder_unref(builder);
593 BT_ERR("Invalid Type\n");
594 return BLUETOOTH_ERROR_INTERNAL;
597 return BLUETOOTH_ERROR_NONE;
600 int _bt_avrcp_set_properties(media_player_settings_t *properties)
604 if (_bt_avrcp_set_interal_property(REPEAT,
605 properties) != BLUETOOTH_ERROR_NONE) {
606 return BLUETOOTH_ERROR_INTERNAL;
608 if (_bt_avrcp_set_interal_property(SHUFFLE,
609 properties) != BLUETOOTH_ERROR_NONE) {
610 return BLUETOOTH_ERROR_INTERNAL;
613 if (_bt_avrcp_set_interal_property(STATUS,
614 properties) != BLUETOOTH_ERROR_NONE) {
615 return BLUETOOTH_ERROR_INTERNAL;
618 if (_bt_avrcp_set_interal_property(POSITION,
619 properties) != BLUETOOTH_ERROR_NONE) {
620 return BLUETOOTH_ERROR_INTERNAL;
623 if (_bt_avrcp_set_interal_property(METADATA,
624 properties) != BLUETOOTH_ERROR_NONE) {
625 return BLUETOOTH_ERROR_INTERNAL;
628 return BLUETOOTH_ERROR_NONE;
631 int _bt_avrcp_set_property(int type, unsigned int value)
634 media_player_settings_t properties;
638 properties.repeat = value;
641 properties.shuffle = value;
644 properties.status = value;
647 properties.position = value;
650 BT_DBG("Invalid Type\n");
651 return BLUETOOTH_ERROR_INTERNAL;
654 if (_bt_avrcp_set_interal_property(type,
655 &properties) != BLUETOOTH_ERROR_NONE)
656 return BLUETOOTH_ERROR_INTERNAL;
660 return BLUETOOTH_ERROR_NONE;