Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2016 The Chromium Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 #include <dbus/dbus.h>
      6 #include <errno.h>
      7 #include <stdlib.h>
      8 #include <syslog.h>
      9 
     10 #include "cras_bt_constants.h"
     11 #include "cras_bt_adapter.h"
     12 #include "cras_bt_player.h"
     13 #include "cras_dbus_util.h"
     14 #include "utlist.h"
     15 
     16 #define CRAS_DEFAULT_PLAYER "/org/chromium/Cras/Bluetooth/DefaultPlayer"
     17 
     18 
     19 static void cras_bt_on_player_registered(DBusPendingCall *pending_call,
     20 					 void *data)
     21 {
     22 	DBusMessage *reply;
     23 
     24 	reply = dbus_pending_call_steal_reply(pending_call);
     25 	dbus_pending_call_unref(pending_call);
     26 
     27 	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
     28 		syslog(LOG_ERR, "RegisterPlayer returned error: %s",
     29 		       dbus_message_get_error_name(reply));
     30 		dbus_message_unref(reply);
     31 		return;
     32 	}
     33 
     34 	dbus_message_unref(reply);
     35 }
     36 
     37 static int cras_bt_add_player(DBusConnection *conn,
     38 			      const struct cras_bt_adapter *adapter,
     39 			      struct cras_bt_player *player)
     40 {
     41 	const char *adapter_path;
     42 	DBusMessage *method_call;
     43 	DBusMessageIter message_iter, dict;
     44 	DBusPendingCall *pending_call;
     45 
     46 	adapter_path = cras_bt_adapter_object_path(adapter);
     47 	method_call = dbus_message_new_method_call(BLUEZ_SERVICE,
     48 						   adapter_path,
     49 						   BLUEZ_INTERFACE_MEDIA,
     50 						   "RegisterPlayer");
     51 	if (!method_call)
     52 		return -ENOMEM;
     53 
     54 	dbus_message_iter_init_append(method_call, &message_iter);
     55 	dbus_message_iter_append_basic(&message_iter,
     56 				       DBUS_TYPE_OBJECT_PATH,
     57 				       &player->object_path);
     58 
     59 	dbus_message_iter_open_container(&message_iter,
     60 					 DBUS_TYPE_ARRAY,
     61 					 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
     62 					 DBUS_TYPE_STRING_AS_STRING
     63 					 DBUS_TYPE_VARIANT_AS_STRING
     64 					 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
     65 					 &dict);
     66 
     67 	append_key_value(&dict, "PlaybackStatus", DBUS_TYPE_STRING,
     68 			 DBUS_TYPE_STRING_AS_STRING,
     69 			 &player->playback_status);
     70 	append_key_value(&dict, "Identity", DBUS_TYPE_STRING,
     71 			 DBUS_TYPE_STRING_AS_STRING,
     72 			 &player->identity);
     73 	append_key_value(&dict, "LoopStatus", DBUS_TYPE_STRING,
     74 			 DBUS_TYPE_STRING_AS_STRING,
     75 			 &player->loop_status);
     76 	append_key_value(&dict, "Position", DBUS_TYPE_INT64,
     77 			 DBUS_TYPE_INT64_AS_STRING, &player->position);
     78 	append_key_value(&dict, "Shuffle", DBUS_TYPE_BOOLEAN,
     79 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->shuffle);
     80 	append_key_value(&dict, "CanGoNext", DBUS_TYPE_BOOLEAN,
     81 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->can_go_next);
     82 	append_key_value(&dict, "CanGoPrevious", DBUS_TYPE_BOOLEAN,
     83 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->can_go_prev);
     84 	append_key_value(&dict, "CanPlay", DBUS_TYPE_BOOLEAN,
     85 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->can_play);
     86 	append_key_value(&dict, "CanPause", DBUS_TYPE_BOOLEAN,
     87 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->can_pause);
     88 	append_key_value(&dict, "CanControl", DBUS_TYPE_BOOLEAN,
     89 			 DBUS_TYPE_BOOLEAN_AS_STRING, &player->can_control);
     90 
     91 	dbus_message_iter_close_container(&message_iter, &dict);
     92 
     93 	if (!dbus_connection_send_with_reply(conn, method_call, &pending_call,
     94 					     DBUS_TIMEOUT_USE_DEFAULT)) {
     95 		dbus_message_unref(method_call);
     96 		return -ENOMEM;
     97 	}
     98 
     99 	dbus_message_unref(method_call);
    100 	if (!pending_call)
    101 		return -EIO;
    102 
    103 	if (!dbus_pending_call_set_notify(pending_call,
    104 					  cras_bt_on_player_registered,
    105 					  player, NULL)) {
    106 		dbus_pending_call_cancel(pending_call);
    107 		dbus_pending_call_unref(pending_call);
    108 		return -ENOMEM;
    109 	}
    110 	return 0;
    111 }
    112 
    113 
    114 /* Note that player properties will be used mostly for AVRCP qualification and
    115  * not for normal use cases. The corresponding media events won't be routed by
    116  * CRAS until we have a plan to provide general system API to handle media
    117  * control.
    118  */
    119 static struct cras_bt_player player = {
    120 	.object_path = CRAS_DEFAULT_PLAYER,
    121 	.playback_status = "playing",
    122 	.identity = "DefaultPlayer",
    123 	.loop_status = "None",
    124 	.shuffle = 0,
    125 	.position = 0,
    126 	.can_go_next = 0,
    127 	.can_go_prev = 0,
    128 	.can_play = 0,
    129 	.can_pause = 0,
    130 	.can_control = 0,
    131 	.message_cb = NULL,
    132 };
    133 
    134 static DBusHandlerResult cras_bt_player_handle_message(DBusConnection *conn,
    135 						       DBusMessage *message,
    136 						       void *arg)
    137 {
    138 	const char *msg = dbus_message_get_member(message);
    139 
    140 	if (player.message_cb)
    141 		player.message_cb(msg);
    142 
    143 	return DBUS_HANDLER_RESULT_HANDLED;
    144 }
    145 
    146 int cras_bt_player_create(DBusConnection *conn)
    147 {
    148 	static const DBusObjectPathVTable player_vtable = {
    149 	        .message_function = cras_bt_player_handle_message
    150 	};
    151 
    152 	DBusError dbus_error;
    153 	struct cras_bt_adapter **adapters;
    154 	size_t num_adapters, i;
    155 
    156 	dbus_error_init(&dbus_error);
    157 
    158 	if (!dbus_connection_register_object_path(conn,
    159 						  player.object_path,
    160 						  &player_vtable,
    161 						  &dbus_error)) {
    162 		syslog(LOG_ERR, "Cannot register player %s",
    163 		       player.object_path);
    164 		dbus_error_free(&dbus_error);
    165 		return -ENOMEM;
    166 	}
    167 
    168 	num_adapters = cras_bt_adapter_get_list(&adapters);
    169 	for (i = 0; i < num_adapters; ++i)
    170 		cras_bt_add_player(conn, adapters[i], &player);
    171 	free(adapters);
    172 	return 0;
    173 }
    174 
    175 int cras_bt_register_player(DBusConnection *conn,
    176 			    const struct cras_bt_adapter *adapter)
    177 {
    178 	return cras_bt_add_player(conn, adapter, &player);
    179 }
    180