2 * bluetooth-media-control
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>
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
30 #include <sys/types.h>
34 #include "bluetooth-control-api.h"
36 #define BLUEZ_SERVICE "org.bluez"
37 #define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager"
39 #define BLUEZ_MEDIA_INTERFACE "org.bluez.Media"
40 #define BLUEZ_MEDIA_PLAYER_OBJECT_PATH "/Musicplayer"
43 #define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer"
46 #define BT_EXPORT_API __attribute__((visibility("default")))
49 #define BT_CONTROL "BT_CONTROL"
50 #define DBG(fmt, args...) SLOG(LOG_DEBUG, BT_CONTROL, \
51 "%s():%d "fmt, __func__, __LINE__, ##args)
52 #define ERR(fmt, args...) SLOG(LOG_ERROR, BT_CONTROL, \
53 "%s():%d "fmt, __func__, __LINE__, ##args)
56 DBusGConnection *avrcp_conn;
57 char avrcp_obj_path[MEDIA_OBJECT_PATH_LENGTH];
60 static avrcp_dbus_info_t g_avrcp_dbus_info;
61 static DBusConnection *g_avrcp_connection = NULL;
63 struct player_settinngs_t {
68 static struct player_settinngs_t equilizer_settings[] = {
69 { EQUILIZER_OFF, "off" },
70 { EQUILIZER_ON, "on" },
71 { EQUILIZER_INVALID, "" }
74 static struct player_settinngs_t repeat_settings[] = {
75 { REPEAT_MODE_OFF, "off" },
76 { REPEAT_SINGLE_TRACK, "singletrack" },
77 { REPEAT_ALL_TRACK, "alltracks" },
78 { REPEAT_GROUP, "group" },
79 { REPEAT_INVALID, "" }
82 static struct player_settinngs_t shuffle_settings[] = {
83 { SHUFFLE_MODE_OFF, "off" },
84 { SHUFFLE_ALL_TRACK, "alltracks" },
85 { SHUFFLE_GROUP, "group" },
86 { SHUFFLE_INVALID, "" }
89 static struct player_settinngs_t scan_settings[] = {
90 { SCAN_MODE_OFF, "off" },
91 { SCAN_ALL_TRACK, "alltracks" },
92 { SCAN_GROUP, "group" },
96 static struct player_settinngs_t player_status[] = {
97 { STATUS_PLAYING, "playing" },
98 { STATUS_STOPPED, "stopped" },
99 { STATUS_PAUSED, "paused" },
100 { STATUS_FORWARD_SEEK, "forward-seek" },
101 { STATUS_REVERSE_SEEK, "reverse-seek" },
102 { STATUS_ERROR, "error" },
103 { STATUS_INVALID, "" }
106 static int __bluetooth_media_get_avrcp_adapter_path(
107 DBusGConnection *gconn, char *path)
110 DBusGProxy *manager_proxy = NULL;
111 char *adapter_path = NULL;
114 DBG("__bluetooth_media_get_avrcp_adapter_path +\n");
116 manager_proxy = dbus_g_proxy_new_for_name(gconn, BLUEZ_SERVICE, "/",
117 BLUEZ_MANAGER_INTERFACE);
119 if (manager_proxy == NULL) {
120 DBG("Could not create a dbus proxy\n");
121 return BLUETOOTH_CONTROL_ERROR;
124 if (!dbus_g_proxy_call(manager_proxy, "DefaultAdapter", &err,
125 G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH,
126 &adapter_path, G_TYPE_INVALID)) {
127 DBG("Getting DefaultAdapter failed: [%s]\n", err->message);
129 ret = BLUETOOTH_CONTROL_ERROR;
133 if (strlen(adapter_path) >= MEDIA_OBJECT_PATH_LENGTH) {
134 DBG("Path too long.\n");
135 ret = BLUETOOTH_CONTROL_ERROR;
138 DBG("path = %s\n", adapter_path);
139 g_strlcpy(path, adapter_path, MEDIA_OBJECT_PATH_LENGTH);
142 g_object_unref(manager_proxy);
144 DBG("Adapter [%s]\n", path);
146 DBG("__bluetooth_media_get_avrcp_adapter_path -\n");
150 static void __bluetooth_media_append_variant(DBusMessageIter *iter,
153 DBusMessageIter value_iter;
154 const char *contained_signature;
158 contained_signature = DBUS_TYPE_BYTE_AS_STRING;
160 case DBUS_TYPE_STRING:
161 contained_signature = DBUS_TYPE_STRING_AS_STRING;
163 case DBUS_TYPE_BOOLEAN:
164 contained_signature = DBUS_TYPE_BOOLEAN_AS_STRING;
166 case DBUS_TYPE_INT16:
167 contained_signature = DBUS_TYPE_INT16_AS_STRING;
169 case DBUS_TYPE_UINT16:
170 contained_signature = DBUS_TYPE_UINT16_AS_STRING;
172 case DBUS_TYPE_INT32:
173 contained_signature = DBUS_TYPE_INT32_AS_STRING;
175 case DBUS_TYPE_UINT32:
176 contained_signature = DBUS_TYPE_UINT32_AS_STRING;
178 case DBUS_TYPE_OBJECT_PATH:
179 contained_signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
182 contained_signature = DBUS_TYPE_VARIANT_AS_STRING;
186 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
187 contained_signature, &value_iter);
188 dbus_message_iter_append_basic(&value_iter, type, val);
189 dbus_message_iter_close_container(iter, &value_iter);
192 static void __bluetooth_media_append_dict_entry(DBusMessageIter *dict,
193 const char *key, int type, void *property)
195 DBusMessageIter iter;
197 if (type == DBUS_TYPE_STRING) {
198 const char *str_ptr = *((const char **)property);
203 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
205 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
207 __bluetooth_media_append_variant(&iter, type, property);
209 dbus_message_iter_close_container(dict, &iter);
212 static dbus_bool_t __bluetooth_media_emit_property_changed(
213 DBusConnection *conn, const char *path,
214 const char *interface, const char *name,
215 int type, void *value)
217 DBusMessage *message = NULL;
218 DBusMessageIter iter;
221 message = dbus_message_new_signal(path, interface, "PropertyChanged");
226 dbus_message_iter_init_append(message, &iter);
227 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
229 __bluetooth_media_append_variant(&iter, type, value);
231 result = dbus_connection_send(conn, message, NULL);
232 dbus_message_unref(message);
237 static void __bluetooth_handle_trackchanged(
240 const char *path = dbus_message_get_path(msg);
241 media_metadata_attributes_t metadata = {0,};
242 DBusMessage *signal = NULL;
243 DBusMessageIter iter;
244 DBusMessageIter metadata_dict;
246 DBG("Path = %s\n", path);
248 if (!dbus_message_get_args(msg, NULL,
249 DBUS_TYPE_STRING, &metadata.title,
250 DBUS_TYPE_STRING, &metadata.artist,
251 DBUS_TYPE_STRING, &metadata.album,
252 DBUS_TYPE_STRING, &metadata.genre,
253 DBUS_TYPE_UINT32, &metadata.total_tracks,
254 DBUS_TYPE_UINT32, &metadata.number,
255 DBUS_TYPE_UINT32, &metadata.duration,
256 DBUS_TYPE_INVALID)) {
257 DBG("Unexpected parameters in signal");
261 signal = dbus_message_new_signal(BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
262 BLUEZ_MEDIA_PLAYER_INTERFACE, "TrackChanged");
264 DBG("Unable to allocate TrackChanged signal\n");
268 dbus_message_iter_init_append(signal, &iter);
270 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
271 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
272 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
273 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata_dict);
275 if (NULL != metadata.title) {
276 __bluetooth_media_append_dict_entry(&metadata_dict,
278 DBUS_TYPE_STRING, &metadata.title);
281 if (NULL != metadata.artist) {
282 __bluetooth_media_append_dict_entry(&metadata_dict,
284 DBUS_TYPE_STRING, &metadata.artist);
287 if (NULL != metadata.album) {
288 __bluetooth_media_append_dict_entry(&metadata_dict,
290 DBUS_TYPE_STRING, &metadata.album);
293 if (NULL != metadata.genre) {
294 __bluetooth_media_append_dict_entry(&metadata_dict,
296 DBUS_TYPE_STRING, &metadata.genre);
299 if (0 != metadata.total_tracks)
300 __bluetooth_media_append_dict_entry(&metadata_dict,
302 DBUS_TYPE_UINT32, &metadata.total_tracks);
304 if (0 != metadata.number)
305 __bluetooth_media_append_dict_entry(&metadata_dict,
307 DBUS_TYPE_UINT32, &metadata.number);
309 if (0 != metadata.duration)
310 __bluetooth_media_append_dict_entry(&metadata_dict,
312 DBUS_TYPE_UINT32, &metadata.duration);
314 dbus_message_iter_close_container(&iter, &metadata_dict);
316 if (!dbus_connection_send(g_avrcp_connection, signal, NULL))
317 DBG("Unable to send TrackChanged signal\n");
318 dbus_message_unref(signal);
322 static void __bluetooth_handle_property_changed(
325 const char *path = dbus_message_get_path(msg);
328 DBG("Path = %s\n", path);
330 if (!dbus_message_get_args(msg, NULL,
331 DBUS_TYPE_UINT32, &type,
332 DBUS_TYPE_UINT32, &value,
333 DBUS_TYPE_INVALID)) {
334 DBG("Unexpected parameters in signal");
338 DBG("type = [%d] and value = [%d]\n", type, value);
342 if (!__bluetooth_media_emit_property_changed(
344 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
345 BLUEZ_MEDIA_PLAYER_INTERFACE,
348 &equilizer_settings[value].property)) {
349 DBG("Error sending the PropertyChanged signal \n");
353 if (!__bluetooth_media_emit_property_changed(
355 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
356 BLUEZ_MEDIA_PLAYER_INTERFACE,
359 &repeat_settings[value].property)) {
360 DBG("Error sending the PropertyChanged signal \n");
364 if (!__bluetooth_media_emit_property_changed(
366 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
367 BLUEZ_MEDIA_PLAYER_INTERFACE,
370 &shuffle_settings[value].property)) {
371 DBG("Error sending the PropertyChanged signal \n");
375 if (!__bluetooth_media_emit_property_changed(
377 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
378 BLUEZ_MEDIA_PLAYER_INTERFACE,
381 &scan_settings[value].property)) {
382 DBG("Error sending the PropertyChanged signal \n");
386 if (!__bluetooth_media_emit_property_changed(
388 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
389 BLUEZ_MEDIA_PLAYER_INTERFACE,
392 &player_status[value].property)) {
393 DBG("Error sending the PropertyChanged signal \n");
397 if (!__bluetooth_media_emit_property_changed(
399 BLUEZ_MEDIA_PLAYER_OBJECT_PATH,
400 BLUEZ_MEDIA_PLAYER_INTERFACE,
404 DBG("Error sending the PropertyChanged signal \n");
408 DBG("Invalid Type\n");
413 static DBusHandlerResult __bluetooth_media_event_filter(
414 DBusConnection *sys_conn,
415 DBusMessage *msg, void *data)
417 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
418 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
420 if (dbus_message_is_signal(msg, BT_MEDIA_PLAYER_DBUS_INTERFACE,
422 __bluetooth_handle_trackchanged(msg);
423 } else if (dbus_message_is_signal(msg, BT_MEDIA_PLAYER_DBUS_INTERFACE,
424 "PropertyChanged")) {
425 __bluetooth_handle_property_changed(msg);
428 return DBUS_HANDLER_RESULT_HANDLED;
431 BT_EXPORT_API int bluetooth_media_init(void)
434 char default_obj_path[MEDIA_OBJECT_PATH_LENGTH] = {0,};
435 DBusError dbus_error;
437 DBG("bluetooth_media_init +\n");
439 g_avrcp_dbus_info.avrcp_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &err);
441 if (!g_avrcp_dbus_info.avrcp_conn) {
442 DBG("Can not get DBUS Gconnection [%s]\n", err->message);
444 return BLUETOOTH_CONTROL_ERROR;
447 DBG("bluetooth_media_init\n");
449 g_avrcp_connection = dbus_g_connection_get_connection(
450 g_avrcp_dbus_info.avrcp_conn);
452 dbus_error_init(&dbus_error);
454 dbus_connection_add_filter(g_avrcp_connection,
455 __bluetooth_media_event_filter, NULL, NULL);
457 dbus_bus_add_match(g_avrcp_connection,
458 "type='signal',interface=" \
459 BT_MEDIA_PLAYER_DBUS_INTERFACE,
462 if (dbus_error_is_set(&dbus_error)) {
463 DBG("Fail to add dbus filter signal\n");
464 dbus_error_free(&dbus_error);
465 return BLUETOOTH_CONTROL_ERROR;
468 if (__bluetooth_media_get_avrcp_adapter_path(
469 g_avrcp_dbus_info.avrcp_conn,
470 default_obj_path) < 0) {
471 DBG("Could not get adapter path\n");
475 DBG("bluetooth_media_init\n");
477 if (default_obj_path != NULL)
478 g_strlcpy(g_avrcp_dbus_info.avrcp_obj_path, default_obj_path,
479 MEDIA_OBJECT_PATH_LENGTH);
483 DBG("bluetooth_media_init -\n");
484 return BLUETOOTH_CONTROL_SUCCESS;
487 dbus_g_connection_unref(g_avrcp_dbus_info.avrcp_conn);
488 g_avrcp_dbus_info.avrcp_conn = NULL;
489 g_avrcp_connection = NULL;
490 return BLUETOOTH_CONTROL_ERROR;
493 BT_EXPORT_API int bluetooth_media_register_player(void)
495 DBusMessage *msg = NULL;
496 DBusMessage *reply = NULL;
497 DBusMessageIter iter;
498 DBusMessageIter property_dict;
499 DBusMessageIter metadata_dict;
503 media_player_settings_t player_settings = {0,};
504 media_metadata_attributes_t metadata = {0,};
506 player_settings.equilizer = EQUILIZER_OFF;
507 player_settings.repeat = REPEAT_MODE_OFF;
508 player_settings.shuffle = SHUFFLE_MODE_OFF;
509 player_settings.scan = SCAN_MODE_OFF;
510 player_settings.status = STATUS_STOPPED;
511 player_settings.position = 0;
513 metadata.title = "\0";
514 metadata.artist = "\0";
515 metadata.album = "\0";
516 metadata.genre = "\0";
518 if (strlen(g_avrcp_dbus_info.avrcp_obj_path) <= 0)
519 return BLUETOOTH_CONTROL_ERROR;
521 const char *object = g_strdup(BLUEZ_MEDIA_PLAYER_OBJECT_PATH);
523 DBG("bluetooth_media_register_player +\n");
525 msg = dbus_message_new_method_call(
527 g_avrcp_dbus_info.avrcp_obj_path,
528 BLUEZ_MEDIA_INTERFACE,
531 DBG("dbus_message_new_method_call failed\n");
532 g_free((void *)object);
533 return BLUETOOTH_CONTROL_ERROR;
536 DBG("object = [%s] \n", object);
538 dbus_message_iter_init_append(msg, &iter);
539 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object);
540 g_free((void *)object);
542 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
543 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
544 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
545 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &property_dict);
547 if (player_settings.equilizer < EQUILIZER_INVALID) {
548 __bluetooth_media_append_dict_entry(&property_dict,
552 player_settings.equilizer].property);
555 if (player_settings.repeat < REPEAT_INVALID) {
556 __bluetooth_media_append_dict_entry(&property_dict,
559 &repeat_settings[player_settings.repeat].property);
562 if (player_settings.shuffle < SHUFFLE_INVALID) {
563 __bluetooth_media_append_dict_entry(&property_dict,
566 &shuffle_settings[player_settings.shuffle].property);
569 if (player_settings.scan < SCAN_INVALID) {
570 __bluetooth_media_append_dict_entry(&property_dict,
573 &scan_settings[player_settings.scan].property);
576 if (player_settings.status < STATUS_INVALID) {
577 __bluetooth_media_append_dict_entry(&property_dict,
580 &player_status[player_settings.status].property);
583 if (0 != player_settings.position)
584 __bluetooth_media_append_dict_entry(&property_dict,
586 DBUS_TYPE_UINT32, &player_settings.position);
588 dbus_message_iter_close_container(&iter, &property_dict);
590 dbus_message_iter_init_append(msg, &iter);
591 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
592 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
593 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
594 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata_dict);
596 if (NULL != metadata.title) {
597 __bluetooth_media_append_dict_entry(&metadata_dict,
599 DBUS_TYPE_STRING, &metadata.title);
602 if (NULL != metadata.artist) {
603 __bluetooth_media_append_dict_entry(&metadata_dict,
605 DBUS_TYPE_STRING, &metadata.artist);
608 if (NULL != metadata.album) {
609 __bluetooth_media_append_dict_entry(&metadata_dict,
611 DBUS_TYPE_STRING, &metadata.album);
614 if (NULL != metadata.genre) {
615 __bluetooth_media_append_dict_entry(&metadata_dict,
617 DBUS_TYPE_STRING, &metadata.genre);
620 if (0 != metadata.total_tracks)
621 __bluetooth_media_append_dict_entry(&metadata_dict,
623 DBUS_TYPE_UINT32, &metadata.total_tracks);
625 if (0 != metadata.number)
626 __bluetooth_media_append_dict_entry(&metadata_dict,
628 DBUS_TYPE_UINT32, &metadata.number);
630 if (0 != metadata.duration)
631 __bluetooth_media_append_dict_entry(&metadata_dict,
633 DBUS_TYPE_UINT32, &metadata.duration);
635 dbus_message_iter_close_container(&iter, &metadata_dict);
637 dbus_error_init(&err);
638 reply = dbus_connection_send_with_reply_and_block(g_avrcp_connection,
640 dbus_message_unref(msg);
643 DBG("Error in registering the Music Player \n");
645 if (dbus_error_is_set(&err)) {
646 DBG("%s", err.message);
647 dbus_error_free(&err);
648 return BLUETOOTH_CONTROL_ERROR;
653 dbus_message_unref(reply);
655 DBG("bluetooth_media_register_player -\n");
657 return BLUETOOTH_CONTROL_SUCCESS;
660 BT_EXPORT_API int bluetooth_media_unregister_player(void)
662 DBusMessage *msg = NULL;
663 DBusMessage *reply = NULL;
665 const char *object = g_strdup(BLUEZ_MEDIA_PLAYER_OBJECT_PATH);
667 DBG("bluetooth_media_unregister_player +\n");
669 msg = dbus_message_new_method_call(BLUEZ_SERVICE,
670 g_avrcp_dbus_info.avrcp_obj_path,
671 BLUEZ_MEDIA_INTERFACE,
675 g_free((void *)object);
676 return BLUETOOTH_CONTROL_ERROR;
679 dbus_message_append_args(msg,
680 DBUS_TYPE_OBJECT_PATH, &object,
683 dbus_error_init(&err);
684 reply = dbus_connection_send_with_reply_and_block(g_avrcp_connection,
686 dbus_message_unref(msg);
687 g_free((void *)object);
690 DBG("Error in unregistering the Music Player \n");
692 if (dbus_error_is_set(&err)) {
693 DBG("%s", err.message);
694 dbus_error_free(&err);
695 return BLUETOOTH_CONTROL_ERROR;
698 dbus_message_unref(reply);
700 DBG("bluetooth_media_unregister_player -\n");
701 return BLUETOOTH_CONTROL_SUCCESS;
704 BT_EXPORT_API int bluetooth_media_deinit(void)
706 DBG("bluetooth_media_deinit +\n");
708 if (g_avrcp_dbus_info.avrcp_conn) {
709 dbus_g_connection_unref(g_avrcp_dbus_info.avrcp_conn);
710 g_avrcp_dbus_info.avrcp_conn = NULL;
713 DBG("bluetooth_media_deinit -\n");
714 return BLUETOOTH_CONTROL_SUCCESS;