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>
24 #include "bluetooth-api.h"
25 #include "bt-internal-types.h"
26 #include "bt-service-common.h"
27 #include "bt-service-avrcp.h"
28 #include "bt-service-event.h"
29 #include "bt-service-util.h"
30 #include "bt-service-audio.h"
32 static bt_player_settinngs_t loopstatus_settings[] = {
33 { REPEAT_INVALID, "" },
34 { REPEAT_MODE_OFF, "None" },
35 { REPEAT_SINGLE_TRACK, "Track" },
36 { REPEAT_ALL_TRACK, "Playlist" },
37 { REPEAT_INVALID, "" }
40 static bt_player_settinngs_t shuffle_settings[] = {
41 { SHUFFLE_INVALID, "" },
42 { SHUFFLE_MODE_OFF, "off" },
43 { SHUFFLE_ALL_TRACK, "alltracks" },
44 { SHUFFLE_GROUP, "group" },
45 { SHUFFLE_INVALID, "" }
48 static bt_player_settinngs_t player_status[] = {
49 { STATUS_STOPPED, "stopped" },
50 { STATUS_PLAYING, "playing" },
51 { STATUS_PAUSED, "paused" },
52 { STATUS_FORWARD_SEEK, "forward-seek" },
53 { STATUS_REVERSE_SEEK, "reverse-seek" },
54 { STATUS_ERROR, "error" },
55 { STATUS_INVALID, "" }
58 static guint avrcp_reg_id = 0;
60 /* Introspection data exposed from bt-service */
61 static const gchar bt_avrcp_bluez_introspection_xml[] =
63 " <interface name='org.freedesktop.DBus.Properties'>"
64 " <method name='Set'>"
65 " <arg type='s' name='interface' direction='in'/>"
66 " <arg type='s' name='property' direction='in'/>"
67 " <arg type='v' name='value' direction='in'/>"
72 static gboolean __bt_media_emit_property_changed(GDBusConnection *connection,
73 const char *path, const char *interface, const char *name,
74 const GVariant *variant)
76 GVariantBuilder *builder = NULL;
79 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
80 g_variant_builder_add(builder, "{sv}", name, variant);
82 g_dbus_connection_emit_signal(connection, NULL, path,
83 BT_PROPERTIES_INTERFACE,
85 g_variant_new("(sa{sv})",
89 g_variant_builder_unref(builder);
91 BT_ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
92 error->code, error->message);
93 g_clear_error(&error);
100 static GQuark __bt_avrcp_error_quark(void)
102 static GQuark quark = 0;
105 quark = g_quark_from_static_string("bt-avrcp");
110 static GError *__bt_avrcp_set_error(bt_avrcp_error_t error)
112 BT_ERR("error[%d]\n", error);
115 case BT_AVRCP_ERROR_INVALID_PARAM:
116 return g_error_new(BT_AVRCP_ERROR, error,
117 BT_ERROR_INVALID_PARAM);
118 case BT_AVRCP_ERROR_INVALID_INTERFACE:
119 return g_error_new(BT_AVRCP_ERROR, error,
120 BT_ERROR_INVALID_INTERFACE);
121 case BT_AVRCP_ERROR_INTERNAL:
123 return g_error_new(BT_AVRCP_ERROR, error,
128 static void __bt_avrcp_agent_method(GDBusConnection *connection,
130 const gchar *object_path,
131 const gchar *interface_name,
132 const gchar *method_name,
133 GVariant *parameters,
134 GDBusMethodInvocation *invocation,
138 BT_INFO("method %s", method_name);
139 BT_INFO("object_path %s", object_path);
140 int ret = BT_AVRCP_ERROR_NONE;
142 gboolean shuffle_status;
144 gchar *interface = NULL;
145 gchar *property = NULL;
146 gchar *loop_status = NULL;
147 GVariant *value = NULL;
149 if (g_strcmp0(method_name, "Set") == 0) {
150 g_variant_get(parameters, "(&s&sv)", &interface, &property,
153 if (g_strcmp0(interface, BT_MEDIA_PLAYER_INTERFACE) != 0) {
154 ret = BT_AVRCP_ERROR_INVALID_INTERFACE;
160 BT_ERR("value is NULL");
164 BT_DBG("Property: %s\n", property);
165 if (g_strcmp0(property, "Shuffle") == 0) {
167 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
169 ret = BT_AVRCP_ERROR_INVALID_PARAM;
173 shuffle_status = g_variant_get_boolean(value);
174 BT_DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
175 if (shuffle_status == TRUE)
176 status = SHUFFLE_ALL_TRACK;
178 status = SHUFFLE_MODE_OFF;
180 _bt_send_event(BT_AVRCP_EVENT,
181 BLUETOOTH_EVENT_AVRCP_SETTING_SHUFFLE_STATUS,
182 g_variant_new("(u)", status));
183 } else if (g_strcmp0(property, "LoopStatus") == 0) {
185 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
187 ret = BT_AVRCP_ERROR_INVALID_PARAM;
191 loop_status = (gchar *)g_variant_get_string(value, NULL);
192 BT_DBG("Value: %s\n", loop_status);
194 if (g_strcmp0(loop_status, "Track") == 0)
195 status = REPEAT_SINGLE_TRACK;
196 else if (g_strcmp0(loop_status, "Playlist") == 0)
197 status = REPEAT_ALL_TRACK;
198 else if (g_strcmp0(loop_status, "None") == 0)
199 status = REPEAT_MODE_OFF;
201 status = REPEAT_INVALID;
203 _bt_send_event(BT_AVRCP_EVENT,
204 BLUETOOTH_EVENT_AVRCP_SETTING_REPEAT_STATUS,
205 g_variant_new("(u)", status));
213 g_variant_unref(value);
214 err = __bt_avrcp_set_error(ret);
215 g_dbus_method_invocation_return_gerror(invocation, err);
220 static const GDBusInterfaceVTable method_table = {
221 __bt_avrcp_agent_method,
226 static GDBusNodeInfo *__bt_avrcp_create_method_node_info
227 (const gchar *introspection_data)
230 GDBusNodeInfo *node_info = NULL;
232 if (introspection_data == NULL)
235 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
238 BT_ERR("Unable to create node: %s", err->message);
245 int _bt_register_media_player(void)
248 GDBusConnection *g_conn;
250 gboolean shuffle_status;
252 GDBusNodeInfo *node_info;
254 GVariantBuilder *builder;
256 GError *error = NULL;
258 media_player_settings_t player_settings = {0,};
260 player_settings.repeat = REPEAT_MODE_OFF;
261 player_settings.status = STATUS_STOPPED;
262 player_settings.position = 0;
263 shuffle_status = FALSE;
265 g_conn = _bt_gdbus_get_system_gconn();
266 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
268 node_info = __bt_avrcp_create_method_node_info(
269 bt_avrcp_bluez_introspection_xml);
270 if (node_info == NULL)
271 return BLUETOOTH_ERROR_INTERNAL;
273 avrcp_reg_id = g_dbus_connection_register_object(g_conn,
274 BT_MEDIA_OBJECT_PATH,
275 node_info->interfaces[0],
278 g_dbus_node_info_unref(node_info);
280 if (avrcp_reg_id == 0) {
281 BT_ERR("Failed to register: %s", error->message);
282 g_clear_error(&error);
283 return BLUETOOTH_ERROR_INTERNAL;
286 adapter_path = _bt_get_adapter_path();
287 retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL);
289 proxy = g_dbus_proxy_new_sync(g_conn,
290 G_DBUS_PROXY_FLAGS_NONE, NULL,
291 BT_BLUEZ_NAME, adapter_path,
292 BT_MEDIA_INTERFACE, NULL, &error);
293 g_free(adapter_path);
296 BT_ERR("Unable to create proxy");
298 BT_ERR("Error: %s", error->message);
299 g_clear_error(&error);
301 return BLUETOOTH_ERROR_INTERNAL;
304 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
306 g_variant_builder_add(builder, "{sv}", "LoopStatus",
308 loopstatus_settings[player_settings.repeat].property));
309 BT_ERR("LoopStatus: %s", loopstatus_settings[player_settings.repeat].property);
311 g_variant_builder_add(builder, "{sv}", "Shuffle",
312 g_variant_new("b", shuffle_status));
314 g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
316 player_status[player_settings.status].property));
317 BT_ERR("PlaybackStatus: %s", player_status[player_settings.status].property);
319 g_variant_builder_add(builder, "{sv}", "Position",
320 g_variant_new("u", player_settings.position));
322 path = g_strdup(BT_MEDIA_OBJECT_PATH);
323 ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
324 g_variant_new("(oa{sv})", path, builder),
325 G_DBUS_CALL_FLAGS_NONE, -1,
328 g_object_unref(proxy);
330 g_variant_builder_unref(builder);
333 BT_ERR("Call RegisterPlayer Failed");
335 BT_ERR("errCode[%x], message[%s]",
336 error->code, error->message);
337 g_clear_error(&error);
339 return BLUETOOTH_ERROR_INTERNAL;
342 g_variant_unref(ret);
343 return BLUETOOTH_ERROR_NONE;
346 static void __bt_avrcp_unregister_object_path(void)
348 GDBusConnection *g_conn;
350 g_conn = _bt_gdbus_get_system_gconn();
351 ret_if(g_conn == NULL);
353 if (avrcp_reg_id > 0) {
354 g_dbus_connection_unregister_object(g_conn,
360 int _bt_unregister_media_player(void)
363 GDBusConnection *g_conn;
367 GError *error = NULL;
369 int result = BLUETOOTH_ERROR_NONE;
371 adapter_path = _bt_get_adapter_path();
372 if (adapter_path == NULL) {
373 result = BLUETOOTH_ERROR_INTERNAL;
377 g_conn = _bt_gdbus_get_system_gconn();
378 if (g_conn == NULL) {
379 BT_ERR("g_conn is NULL");
380 g_free(adapter_path);
381 result = BLUETOOTH_ERROR_INTERNAL;
385 proxy = g_dbus_proxy_new_sync(g_conn,
386 G_DBUS_PROXY_FLAGS_NONE, NULL,
387 BT_BLUEZ_NAME, adapter_path,
388 BT_MEDIA_INTERFACE, NULL, &error);
389 g_free(adapter_path);
392 BT_ERR("Unable to create proxy");
394 BT_ERR("Error: %s", error->message);
395 g_clear_error(&error);
397 result = BLUETOOTH_ERROR_INTERNAL;
401 path = g_strdup(BT_MEDIA_OBJECT_PATH);
402 BT_DBG("path is [%s]", path);
404 ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
405 g_variant_new("(o)", path),
406 G_DBUS_CALL_FLAGS_NONE, -1,
409 g_object_unref(proxy);
412 BT_ERR("UnregisterPlayer failed");
414 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
415 error->code, error->message);
416 g_clear_error(&error);
418 result = BLUETOOTH_ERROR_INTERNAL;
420 g_variant_unref(ret);
423 __bt_avrcp_unregister_object_path();
429 int _bt_avrcp_set_track_info(media_metadata_attributes_t *meta_data)
432 char *interface = BT_MEDIA_PLAYER_INTERFACE;
433 GDBusConnection *g_conn;
434 GError *error = NULL;
435 GVariantBuilder *builder = NULL;
436 GVariantBuilder *inner_builder = NULL;
437 GVariant *children[1];
440 retv_if(meta_data == NULL, BLUETOOTH_ERROR_INTERNAL);
442 g_conn = _bt_gdbus_get_system_gconn();;
443 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
445 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
446 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
448 g_variant_builder_add(inner_builder, "{sv}",
449 "xesam:title", g_variant_new_string(meta_data->title));
451 children[0] = g_variant_new_string(meta_data->artist);
452 g_variant_builder_add(inner_builder, "{sv}",
453 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
456 g_variant_builder_add(inner_builder, "{sv}",
457 "xesam:album", g_variant_new_string(meta_data->album));
459 children[0] = g_variant_new_string(meta_data->genre);
460 g_variant_builder_add(inner_builder, "{sv}",
461 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
464 g_variant_builder_add(inner_builder, "{sv}",
465 "xesam:totalTracks", g_variant_new_int32(meta_data->total_tracks));
467 g_variant_builder_add(inner_builder, "{sv}",
468 "xesam:trackNumber", g_variant_new_int32(meta_data->number));
470 g_variant_builder_add(inner_builder, "{sv}",
471 "mpris:length", g_variant_new_int64(meta_data->duration));
473 g_variant_builder_add(builder, "{sv}",
474 "Metadata", g_variant_new("a{sv}", inner_builder));
476 ret = g_dbus_connection_emit_signal(g_conn, NULL, BT_MEDIA_OBJECT_PATH,
477 BT_PROPERTIES_INTERFACE,
479 g_variant_new("(sa{sv})",
483 g_variant_builder_unref(inner_builder);
484 g_variant_builder_unref(builder);
488 BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
489 error->code, error->message);
490 g_clear_error(&error);
495 return BLUETOOTH_ERROR_NONE;
498 int _bt_avrcp_set_interal_property(int type, media_player_settings_t *properties)
501 GDBusConnection *g_conn;
503 media_metadata_attributes_t meta_data;
505 GVariantBuilder *builder = NULL;
506 GVariant *children[1];
508 g_conn = _bt_gdbus_get_system_gconn();;
509 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
513 value = properties->repeat;
514 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
515 BT_MEDIA_PLAYER_INTERFACE, "LoopStatus",
516 g_variant_new_string(loopstatus_settings[value].property))) {
517 BT_ERR("Error sending the PropertyChanged signal \n");
518 return BLUETOOTH_ERROR_INTERNAL;
522 value = properties->shuffle;
523 if (g_strcmp0(shuffle_settings[value].property, "off") == 0)
528 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
529 BT_MEDIA_PLAYER_INTERFACE, "Shuffle",
530 g_variant_new_boolean(shuffle))) {
531 BT_ERR("Error sending the PropertyChanged signal \n");
532 return BLUETOOTH_ERROR_INTERNAL;
536 value = properties->status;
537 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
538 BT_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
539 g_variant_new_string(player_status[value].property))) {
540 BT_ERR("Error sending the PropertyChanged signal \n");
541 return BLUETOOTH_ERROR_INTERNAL;
545 value = properties->position;
546 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
547 BT_MEDIA_PLAYER_INTERFACE, "Position",
548 g_variant_new_uint32(value))) {
549 BT_ERR("Error sending the PropertyChanged signal \n");
550 return BLUETOOTH_ERROR_INTERNAL;
554 meta_data = properties->metadata;
556 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
557 g_variant_builder_add(builder, "{sv}",
558 "xesam:title", g_variant_new_string(meta_data.title));
560 children[0] = g_variant_new_string(meta_data.artist);
561 g_variant_builder_add(builder, "{sv}",
562 "xesam:artist", g_variant_new_array(G_VARIANT_TYPE_STRING,
565 g_variant_builder_add(builder, "{sv}",
566 "xesam:album", g_variant_new_string(meta_data.album));
568 children[0] = g_variant_new_string(meta_data.genre);
569 g_variant_builder_add(builder, "{sv}",
570 "xesam:genre", g_variant_new_array(G_VARIANT_TYPE_STRING,
573 g_variant_builder_add(builder, "{sv}",
574 "xesam:totalTracks", g_variant_new_int32(meta_data.total_tracks));
576 g_variant_builder_add(builder, "{sv}",
577 "xesam:trackNumber", g_variant_new_int32(meta_data.number));
579 g_variant_builder_add(builder, "{sv}",
580 "mpris:length", g_variant_new_int64(meta_data.duration));
582 if (!__bt_media_emit_property_changed(g_conn, BT_MEDIA_OBJECT_PATH,
583 BT_MEDIA_PLAYER_INTERFACE, "Metadata",
584 g_variant_new("a{sv}", builder))) {
585 BT_ERR("Error sending the PropertyChanged signal \n");
586 g_variant_builder_unref(builder);
587 return BLUETOOTH_ERROR_INTERNAL;
589 g_variant_builder_unref(builder);
592 BT_ERR("Invalid Type\n");
593 return BLUETOOTH_ERROR_INTERNAL;
596 return BLUETOOTH_ERROR_NONE;
599 int _bt_avrcp_set_properties(media_player_settings_t *properties)
603 if (_bt_avrcp_set_interal_property(REPEAT,
604 properties) != BLUETOOTH_ERROR_NONE) {
605 return BLUETOOTH_ERROR_INTERNAL;
607 if (_bt_avrcp_set_interal_property(SHUFFLE,
608 properties) != BLUETOOTH_ERROR_NONE) {
609 return BLUETOOTH_ERROR_INTERNAL;
612 if (_bt_avrcp_set_interal_property(STATUS,
613 properties) != BLUETOOTH_ERROR_NONE) {
614 return BLUETOOTH_ERROR_INTERNAL;
617 if (_bt_avrcp_set_interal_property(POSITION,
618 properties) != BLUETOOTH_ERROR_NONE) {
619 return BLUETOOTH_ERROR_INTERNAL;
622 if (_bt_avrcp_set_interal_property(METADATA,
623 properties) != BLUETOOTH_ERROR_NONE) {
624 return BLUETOOTH_ERROR_INTERNAL;
627 return BLUETOOTH_ERROR_NONE;
630 int _bt_avrcp_set_property(int type, unsigned int value)
633 media_player_settings_t properties;
637 properties.repeat = value;
640 properties.shuffle = value;
643 properties.status = value;
646 properties.position = value;
649 BT_DBG("Invalid Type\n");
650 return BLUETOOTH_ERROR_INTERNAL;
653 if (_bt_avrcp_set_interal_property(type,
654 &properties) != BLUETOOTH_ERROR_NONE)
655 return BLUETOOTH_ERROR_INTERNAL;
659 return BLUETOOTH_ERROR_NONE;