#define CONNMAN_BLUETOOTH_TECHNOLOGY_PATH "/net/connman/technology/bluetooth"
#define CONNMAN_BLUETOTOH_TECHNOLOGY_INTERFACE "net.connman.Technology"
+#define BLUEZ_AGENT_SERVICE "org.bluezlib.agent"
+#define AGENT_INTERFACE "org.bluez.Agent1"
+#define AGENT_OBJECT_PATH "/org/bluezlib/agent"
+
static bool initialized;
static bool bt_service_init;
+static guint bluetooth_agent_id;
+static guint profile_id;
+static GDBusConnection *conn;
+
static bluez_adapter_t *default_adapter;
static void profile_connect_callback(bluez_device_t *device,
static void profile_disconnect_callback(bluez_device_t *device,
enum device_profile_state state);
+static int request_name_on_dbus(const char *name);
+static void release_name_on_dbus(const char *name);
+
struct device_connect_cb_node {
bt_device_gatt_state_changed_cb cb;
void *user_data;
bluez_avrcp_target_state_changed,
avrcp_target_state_node);
- if (avrcp_repeat_node)
- bluez_set_avrcp_repeat_changed_cb(
- bluez_avrcp_repeat_changed,
- avrcp_repeat_node);
-
- if (avrcp_shuffle_node)
- bluez_set_avrcp_shuffle_changed_cb(
- bluez_avrcp_shuffle_changed,
- avrcp_shuffle_node);
if (device_connect_node)
bluez_set_device_connect_changed_cb(
bluez_device_connect_changed,
return BT_SUCCESS;
}
+static gboolean media_handle_set_property(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ DBG("property_name = %s", property_name);
+
+ if (g_strcmp0(property_name, "LoopStatus") == 0) {
+ const gchar *loopstatus = g_variant_get_string(value, NULL);
+ DBG("loopstatus = %s", loopstatus);
+
+ if (avrcp_repeat_node)
+ bluez_avrcp_repeat_changed(loopstatus,
+ avrcp_repeat_node);
+ } else if (g_strcmp0(property_name, "Shuffle") == 0) {
+ gboolean shuffle_mode = g_variant_get_boolean(value);
+ if (shuffle_mode == TRUE)
+ DBG("shuffle_mode TRUE");
+ else
+ DBG("shuffle_mode FALSE");
+
+ if (avrcp_shuffle_node)
+ bluez_avrcp_shuffle_changed(shuffle_mode,
+ avrcp_shuffle_node);
+ }
+
+ return *error == NULL;
+}
+
+static const gchar media_xml[] =
+"<node>"
+" <interface name='org.mpris.MediaPlayer2.Player'>"
+" <property type='b' name='Shuffle' access='readwrite'/>"
+" <property type='s' name='LoopStatus' access='readwrite'/>"
+" </interface>"
+"</node>";
+
+static const GDBusInterfaceVTable media_handle = {
+ NULL,
+ NULL,
+ media_handle_set_property
+};
+
+static GDBusNodeInfo *media_data;
+static int bluetooth_media_agent_id;
+
+static int destory_media_agent(void)
+{
+ if (bluetooth_media_agent_id > 0) {
+ comms_bluetooth_unregister_media_agent(AGENT_OBJECT_PATH,
+ NULL, NULL);
+
+ g_dbus_connection_unregister_object(conn,
+ bluetooth_media_agent_id);
+
+ bluetooth_media_agent_id = 0;
+
+ release_name_on_dbus(BLUEZ_AGENT_SERVICE);
+ }
+
+ return 0;
+}
+
+static int create_media_agent(void)
+{
+ int ret;
+
+ if (bluetooth_media_agent_id)
+ return BT_ERROR_ALREADY_DONE;
+
+ media_data =
+ g_dbus_node_info_new_for_xml(media_xml, NULL);
+
+ ret = request_name_on_dbus(BLUEZ_AGENT_SERVICE);
+ if (ret != 0)
+ return -1;
+
+ DBG("%s requested success", BLUEZ_AGENT_SERVICE);
+
+ bluetooth_media_agent_id = g_dbus_connection_register_object(
+ conn,
+ AGENT_OBJECT_PATH,
+ media_data->
+ interfaces[0],
+ &media_handle,
+ NULL,
+ NULL,
+ NULL);
+
+ if (bluetooth_media_agent_id == 0)
+ return BT_ERROR_OPERATION_FAILED;
+
+ ret = comms_bluetooth_register_media_agent_sync(AGENT_OBJECT_PATH,
+ NULL);
+
+ DBG("ret = %d", ret);
+
+ if (ret != BT_SUCCESS) {
+ destory_media_agent();
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ return BT_SUCCESS;
+}
+
int bt_avrcp_target_initialize(
bt_avrcp_target_connection_state_changed_cb callback,
void *user_data)
{
struct avrcp_target_connection_state_changed_node *node_data = NULL;
+ int ret;
DBG("default_adpater: %p", default_adapter);
return BT_ERROR_ALREADY_DONE;
}
+ ret = create_media_agent();
+
+ if (ret != BT_SUCCESS)
+ return ret;
+
node_data =
g_new0(struct avrcp_target_connection_state_changed_node, 1);
if (node_data == NULL) {
g_free(avrcp_target_state_node);
avrcp_target_state_node = NULL;
+ destory_media_agent();
+
return BT_SUCCESS;
}
avrcp_repeat_node = node_data;
- _bt_update_bluetooth_callbacks();
-
return BT_SUCCESS;
}
if (!avrcp_repeat_node)
return BT_SUCCESS;
- bluez_unset_avrcp_repeat_changed_cb();
-
g_free(avrcp_repeat_node);
avrcp_repeat_node = NULL;
avrcp_shuffle_node = node_data;
- _bt_update_bluetooth_callbacks();
-
return BT_SUCCESS;
}
if (!avrcp_shuffle_node)
return BT_SUCCESS;
- bluez_unset_avrcp_shuffle_changed_cb();
-
g_free(avrcp_shuffle_node);
avrcp_shuffle_node = NULL;
/* Agent Function */
-#define BLUEZ_AGENT_SERVICE "org.bluezlib.agent"
-#define AGENT_INTERFACE "org.bluez.Agent1"
-#define AGENT_OBJECT_PATH "/org/bluezlib/agent"
-
static bt_agent *this_agent;
static GDBusNodeInfo *introspection_data;
NULL
};
-static guint bluetooth_agent_id;
-static guint profile_id;
-static GDBusConnection *conn;
static void release_dbus_connection(void)
{
Interface org.tizen.comms.mediaplayer
Object path /org/tizen/comms/bluetooth
-Methods void MediaPlayerChangeProperty(uint32 type, uint32 value)
+Methods void RegisterMediaAgent(object agent)
+
+ Registers an Media agent handler.
+
+ Object path agent defines the path of the agent
+ that will be called when authorize each received object
+
+ Possible errors: org.bluez.Error.AlreadyExists
+
+ void UnregisterMediaAgent(object agent)
+
+ Unregisters the registiered Media agent.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ void MediaPlayerChangeProperty(uint32 type, uint32 value)
Set AVRCP property.
bluetooth_simple_callback cb,
void *user_data);
+int comms_bluetooth_register_pairing_agent_sync(
+ const char *agent_path,
+ void *user_data);
+
void comms_bluetooth_unregister_pairing_agent(
const char *agent_path,
bluetooth_simple_callback cb,
bluetooth_simple_callback cb,
void *user_data);
+int comms_bluetooth_register_opp_agent_sync(
+ const char *agent_path,
+ void *user_data);
+
void comms_bluetooth_unregister_opp_agent(
const char *agent_path,
bluetooth_simple_callback cb,
void *track_data,
bluetooth_simple_callback cb,
void *user_data);
+
+void comms_bluetooth_register_media_agent(
+ const char *agent_path,
+ bluetooth_simple_callback cb,
+ void *user_data);
+
+int comms_bluetooth_register_media_agent_sync(
+ const char *agent_path,
+ void *user_data);
+
+void comms_bluetooth_unregister_media_agent(
+ const char *agent_path,
+ bluetooth_simple_callback cb,
+ void *user_data);
#endif
void bluez_unset_hdp_state_changed_cb(struct _bluez_device *device);
-typedef void (*bluez_avrcp_repeat_changed_cb_t)(
- const gchar *repeat,
- gpointer user_data);
-
-void bluez_set_avrcp_repeat_changed_cb(
- bluez_avrcp_repeat_changed_cb_t cb,
- gpointer user_data);
-
-void bluez_unset_avrcp_repeat_changed_cb();
-
-typedef void (*bluez_avrcp_shuffle_changed_cb_t)(
- gboolean shuffle_mode,
- gpointer user_data);
-
-void bluez_set_avrcp_shuffle_changed_cb(
- bluez_avrcp_shuffle_changed_cb_t cb,
- gpointer user_data);
-void bluez_unset_avrcp_shuffle_changed_cb();
-
typedef void (*bluez_avrcp_target_cb_t)(
const char *remote_address,
gboolean connected,
async_result_node);
}
+int comms_bluetooth_register_pairing_agent_sync(const char *agent_path,
+ void *user_data)
+{
+ GError *error = NULL;
+
+ if (this_bluetooth == NULL) {
+ ERROR("bluetooth not register");
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ g_dbus_proxy_call_sync(this_bluetooth->pairing.proxy,
+ "RegisterPairingAgent",
+ g_variant_new("(o)", agent_path),
+ 0, -1, NULL, &error);
+
+ if (error) {
+ ERROR("%s", error->message);
+ g_error_free(error);
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ return BT_SUCCESS;
+}
+
void comms_bluetooth_unregister_pairing_agent(const char *agent_path,
bluetooth_simple_callback cb,
void *user_data)
async_result_node);
}
+void comms_bluetooth_register_media_agent(const char *agent_path,
+ bluetooth_simple_callback cb,
+ void *user_data)
+{
+ struct _bluetooth_simple_async_result *async_result_node;
+
+ if (this_bluetooth == NULL) {
+ ERROR("bluetooth not register");
+ return;
+ }
+
+ async_result_node = g_new0(struct _bluetooth_simple_async_result, 1);
+ if (async_result_node == NULL) {
+ ERROR("no memory");
+ return;
+ }
+
+ async_result_node->callback = cb;
+ async_result_node->user_data = user_data;
+
+ g_dbus_proxy_call(this_bluetooth->mediaplayer.proxy,
+ "RegisterMediaAgent",
+ g_variant_new("(o)", agent_path),
+ 0, -1, NULL,
+ bluetooth_simple_async_cb,
+ async_result_node);
+}
+
+int comms_bluetooth_register_media_agent_sync(const char *agent_path,
+ void *user_data)
+{
+ GError *error = NULL;
+
+ if (this_bluetooth == NULL) {
+ ERROR("bluetooth not register");
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ g_dbus_proxy_call_sync(this_bluetooth->mediaplayer.proxy,
+ "RegisterMediaAgent",
+ g_variant_new("(o)", agent_path),
+ 0, -1, NULL, &error);
+
+ if (error) {
+ ERROR("%s", error->message);
+ g_error_free(error);
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ return BT_SUCCESS;
+}
+
+void comms_bluetooth_unregister_media_agent(const char *agent_path,
+ bluetooth_simple_callback cb,
+ void *user_data)
+{
+ struct _bluetooth_simple_async_result *async_result_node;
+
+ if (this_bluetooth == NULL) {
+ ERROR("bluetooth not register");
+ return;
+ }
+
+ async_result_node = g_new0(struct _bluetooth_simple_async_result, 1);
+ if (async_result_node == NULL) {
+ ERROR("no memory");
+ return;
+ }
+
+ async_result_node->callback = cb;
+ async_result_node->user_data = user_data;
+
+ g_dbus_proxy_call(this_bluetooth->mediaplayer.proxy,
+ "UnregisterMediaAgent",
+ g_variant_new("(o)", agent_path),
+ 0, -1, NULL,
+ bluetooth_simple_async_cb,
+ async_result_node);
+}
+
void comms_bluetooth_register_opp_agent(const char *agent_path,
bluetooth_simple_callback cb,
void *user_data)
async_result_node);
}
+int comms_bluetooth_register_opp_agent_sync(const char *agent_path,
+ void *user_data)
+{
+ GError *error = NULL;
+
+ if (this_bluetooth == NULL) {
+ ERROR("bluetooth not register");
+ return BT_ERROR_OPERATION_FAILED;
+ }
+
+ g_dbus_proxy_call_sync(this_bluetooth->opp.proxy,
+ "RegisterObexAgent",
+ g_variant_new("(o)", agent_path),
+ 0, -1, NULL, &error);
+
+ if (error) {
+ ERROR("%s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ return BT_SUCCESS;
+}
+
void comms_bluetooth_unregister_opp_agent(const char *agent_path,
bluetooth_simple_callback cb,
void *user_data)
static gpointer adapter_added_cb_data;
static bluez_agent_added_cb_t agent_added_cb;
static gpointer agent_added_cb_data;
-static bluez_avrcp_repeat_changed_cb_t avrcp_repeat_changed_cb;
-static gpointer avrcp_repeat_changed_data;
-static bluez_avrcp_shuffle_changed_cb_t avrcp_shuffle_changed_cb;
-static gpointer avrcp_shuffle_changed_data;
static bluez_avrcp_target_cb_t avrcp_target_cb;
static gpointer avrcp_target_cb_data;
static bluez_audio_state_cb_t audio_state_cb;
static device_disconnect_cb_t dev_disconnect_cb;
static gpointer dev_disconnect_data;
-static GDBusNodeInfo *introspection_data;
-static guint bt_register_avrcp_property(struct _bluez_adapter *adapter);
-
static struct _bluez_object *get_object_from_path(const char *path)
{
return g_hash_table_lookup(bluez_object_hash, (gpointer) path);
dev_disconnect_data = user_data;
}
-void bluez_set_avrcp_repeat_changed_cb(bluez_avrcp_repeat_changed_cb_t cb,
- gpointer user_data)
-{
- avrcp_repeat_changed_cb = cb;
- avrcp_repeat_changed_data = user_data;
-}
-
-void bluez_unset_avrcp_repeat_changed_cb()
-{
- avrcp_repeat_changed_cb = NULL;
- avrcp_repeat_changed_data = NULL;
-}
-
-void bluez_set_avrcp_shuffle_changed_cb(bluez_avrcp_shuffle_changed_cb_t cb,
- gpointer user_data)
-{
- avrcp_shuffle_changed_cb = cb;
- avrcp_shuffle_changed_data = user_data;
-}
-
-void bluez_unset_avrcp_shuffle_changed_cb()
-{
- avrcp_shuffle_changed_cb = NULL;
- avrcp_shuffle_changed_data = NULL;
-}
-
void bluez_set_avrcp_target_cb(bluez_avrcp_target_cb_t cb,
gpointer user_data)
{
return BT_SUCCESS;
}
-static void handle_media_proxy_cb(GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GVariant *ret;
- GError *error = NULL;
- enum bluez_error_type error_type = ERROR_NONE;
- gchar *adapter_object_path = user_data;
- struct _bluez_adapter *adapter;
-
- DBG("");
-
- if (!adapter_object_path)
- return;
-
- adapter = g_hash_table_lookup(bluez_adapter_hash,
- adapter_object_path);
-
- if (adapter == NULL)
- goto done;
-
- ret = g_dbus_proxy_call_finish(adapter->media_proxy, res,
- &error);
- if (ret == NULL) {
- error_type = get_error_type(error);
- DBG("error_type = %d", error_type);
- g_error_free(error);
- } else
- g_variant_unref(ret);
-
-done:
- g_free(adapter_object_path);
-}
-
-void bt_media_register_player(struct _bluez_adapter *adapter)
-{
- GVariant *str_array[1];
- GVariant *val_array;
- GVariant *val_metadata;
-
- GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
- GVariantBuilder *builder_array =
- g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
-
- GVariant *val = g_variant_new("s", "None");
- g_variant_builder_add(builder, "{sv}", "LoopStatus", val);
-
- val = g_variant_new("b", FALSE);
- g_variant_builder_add(builder, "{sv}", "Shuffle", val);
-
- val = g_variant_new("s", "Stopped");
- g_variant_builder_add(builder, "{sv}", "PlaybackStatus", val);
-
- val = g_variant_new("x", 0);
- g_variant_builder_add(builder, "{sv}", "Position", val);
-
- val = g_variant_new_string("\0");
- str_array[0] = val;
- val_array = g_variant_new_array(G_VARIANT_TYPE_STRING, str_array, 1);
- g_variant_builder_add(builder_array, "{sv}", "xesam:artist", val_array);
-
- val = g_variant_new_string("\0");
- str_array[0] = val;
- val_array = g_variant_new_array(G_VARIANT_TYPE_STRING, str_array, 1);
- g_variant_builder_add(builder_array, "{sv}", "xesam:genre", val_array);
-
- val = g_variant_new("s", "\0");
- g_variant_builder_add(builder_array, "{sv}", "xesam:title", val);
-
- val = g_variant_new("i", 0);
- g_variant_builder_add(builder_array, "{sv}", "xesam:trackNumber", val);
-
- val = g_variant_new("s", "\0");
- g_variant_builder_add(builder_array, "{sv}", "xesam:album", val);
-
- val = g_variant_new("x", 0);
- g_variant_builder_add(builder_array, "{sv}", "mpris:length", val);
-
- val_metadata = g_variant_new("a{sv}", builder_array);
- g_variant_builder_add(builder, "{sv}", "Metadata", val_metadata);
-
- DBG("+");
-
- if (adapter == NULL) {
- ERROR("adapter is NULL");
- return;
- }
-
- if (adapter->media_proxy == NULL) {
- ERROR("adapter->mediaprooxy is NULL");
- return;
- }
-
- if (adapter->avrcp_registration_id == 0)
- adapter->avrcp_registration_id =
- bt_register_avrcp_property(adapter);
-
- g_dbus_proxy_call(adapter->media_proxy,
- "RegisterPlayer",
- g_variant_new("(oa{sv})",
- BT_MEDIA_OBJECT_PATH, builder),
- 0, -1, NULL,
- handle_media_proxy_cb,
- g_strdup(adapter->object_path));
-
- DBG("-");
- return;
-}
-
-void bt_media_unregister_player(struct _bluez_adapter *adapter)
-{
- GDBusConnection *conn;
-
- DBG("+");
-
- if (adapter == NULL) {
- ERROR("adapter is NULL");
- return;
- }
-
- if (adapter->media_proxy == NULL) {
- ERROR("adapter->mediaprooxy is NULL");
- return;
- }
-
- g_dbus_proxy_call(adapter->media_proxy,
- "UnregisterPlayer",
- g_variant_new("(o)", BT_MEDIA_OBJECT_PATH),
- 0, -1, NULL,
- handle_media_proxy_cb,
- g_strdup(adapter->object_path));
-
- conn = g_dbus_proxy_get_connection(adapter->media_proxy);
-
- g_dbus_connection_unregister_object(conn,
- adapter->avrcp_registration_id);
-
- adapter->avrcp_registration_id = 0;
-
- DBG("-");
- return;
-}
-
-static const gchar introspection_xml[] =
-"<node>"
-" <interface name='org.mpris.MediaPlayer2.Player'>"
-" <property type='b' name='Shuffle' access='readwrite'/>"
-" <property type='s' name='LoopStatus' access='readwrite'/>"
-" </interface>"
-"</node>";
-
-static gboolean handle_set_property(GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GVariant *value,
- GError **error,
- gpointer user_data)
-{
- DBG("property_name = %s", property_name);
-
- if (g_strcmp0(property_name, "LoopStatus") == 0) {
- const gchar *loopstatus = g_variant_get_string(value, NULL);
- DBG("loopstatus = %s", loopstatus);
-
- if (avrcp_repeat_changed_cb)
- avrcp_repeat_changed_cb(loopstatus,
- avrcp_repeat_changed_data);
-
- } else if (g_strcmp0(property_name, "Shuffle") == 0) {
- gboolean shuffle_mode = g_variant_get_boolean(value);
- if (shuffle_mode == TRUE)
- DBG("shuffle_mode TRUE");
- else
- DBG("shuffle_mode FALSE");
-
- if (avrcp_shuffle_changed_cb)
- avrcp_shuffle_changed_cb(shuffle_mode,
- avrcp_shuffle_changed_data);
- }
-
- return *error == NULL;
-}
-
-static const GDBusInterfaceVTable interface_vtable = {
- NULL,
- NULL,
- handle_set_property
-};
-
-static guint bt_register_avrcp_property(struct _bluez_adapter *adapter)
-{
- guint rid;
- GDBusConnection *conn;
-
- conn = g_dbus_proxy_get_connection(adapter->media_proxy);
-
- introspection_data = g_dbus_node_info_new_for_xml(introspection_xml,
- NULL);
-
- rid = g_dbus_connection_register_object(conn, BT_MEDIA_OBJECT_PATH,
- introspection_data->interfaces[0],
- &interface_vtable,
- NULL,
- NULL,
- NULL);
-
- return rid;
-}
-
static void bluez_device_connect_cb(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
#include "vertical.h"
#define BLUETOOTH_OBJECT "/org/tizen/comms/bluetooth"
+#define BT_MEDIA_OBJECT_PATH "/Musicplayer"
+#define MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
+
+struct agent {
+ gchar *owner;
+ gchar *object_path;
+ guint watch_id;
+};
+
+struct _bluez_adapter {
+ char *interface_name;
+ char *object_path;
+ GDBusInterface *interface;
+ GDBusInterface *media_interface;
+ guint avrcp_registration_id;
+ GDBusProxy *proxy;
+ GDBusProxy *media_proxy;
+ struct _bluez_object *parent;
+ struct _device_head *device_head;
+ bluez_adapter_powered_cb_t powered_cb;
+ gpointer powered_cb_data;
+ bluez_adapter_device_cb_t device_created_cb;
+ gpointer device_created_data;
+ bluez_adapter_device_cb_t device_removed_cb;
+ gpointer device_removed_data;
+ bluez_adapter_alias_cb_t alias_cb;
+ gpointer alias_cb_data;
+ bluez_adapter_discovering_cb_t discovering_cb;
+ gpointer discovering_cb_data;
+ bluez_adapter_discoverable_cb_t discoverable_cb;
+ gpointer discoverable_cb_data;
+ bluez_adapter_discoverable_tm_cb_t discoverable_timeout_cb;
+ gpointer discoverable_timeout_cb_data;
+};
+
+static struct agent *relay_agent;
static const GDBusMethodInfo *_media_method_info_pointers[] =
{
+ GDBUS_METHOD("RegisterMediaAgent",
+ GDBUS_ARGS(_ARG("agent", "o")), NULL),
+ GDBUS_METHOD("UnregisterMediaAgent",
+ GDBUS_ARGS(_ARG("agent", "o")), NULL),
GDBUS_METHOD("MediaPlayerChangeProperty",
GDBUS_ARGS(_ARG("type", "u"),
_ARG("value", "u")), NULL),
media_interface);
}
+static void free_relay_agent(struct agent *agent)
+{
+ g_free(agent->owner);
+ g_free(agent->object_path);
+
+ g_free(agent);
+}
+
+static void relay_agent_disconnected(GDBusConnection *connection,
+ const gchar *name, gpointer user_data)
+{
+ DBG("");
+
+ if (!relay_agent)
+ return;
+
+ free_relay_agent(relay_agent);
+
+ relay_agent = NULL;
+}
+
+static struct agent *create_relay_agent(const gchar *sender,
+ const gchar *path,
+ guint watch_id)
+{
+ struct agent *agent;
+
+ agent = g_new0(struct agent, 1);
+ if (agent == NULL) {
+ ERROR("no memory");
+ return NULL;
+ }
+
+ agent->owner = g_strdup(sender);
+ agent->object_path = g_strdup(path);
+ agent->watch_id = watch_id;
+
+ return agent;
+}
+
+static void register_relay_agent_handler(
+ GDBusConnection *connection,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ const gchar *sender;
+ gchar *agent_path;
+ guint relay_agent_watch_id;
+
+ DBG("");
+
+ if (relay_agent)
+ return comms_error_already_exists(invocation);
+
+ g_variant_get(parameters, "(o)", &agent_path);
+ if (agent_path == NULL)
+ return comms_error_invalid_args(invocation);
+
+ sender = g_dbus_method_invocation_get_sender(invocation);
+
+ relay_agent_watch_id =
+ g_bus_watch_name_on_connection(connection, sender,
+ G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+ NULL, relay_agent_disconnected,
+ NULL, NULL);
+
+ relay_agent = create_relay_agent(sender, agent_path,
+ relay_agent_watch_id);
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+static void unregister_relay_agent_handler(
+ GDBusConnection *connection,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ gchar *relay_agent_path;
+
+ DBG("");
+
+ if (relay_agent == NULL)
+ return comms_error_does_not_exist(invocation);
+
+ g_variant_get(parameters, "(o)", &relay_agent_path);
+ if (relay_agent_path == NULL)
+ return comms_error_invalid_args(invocation);
+
+ if (g_strcmp0(relay_agent_path, relay_agent->object_path))
+ return comms_error_does_not_exist(invocation);
+
+ g_free(relay_agent_path);
+
+ free_relay_agent(relay_agent);
+ relay_agent = NULL;
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
static void handle_change_track(GVariant *parameters)
{
GVariantIter *valueIter;
return;
}
- if (g_strcmp0(method_name, "MediaPlayerChangeProperty") == 0) {
+ if (g_strcmp0(method_name, "RegisterMediaAgent") == 0) {
+ register_relay_agent_handler(connection, parameters,
+ invocation, user_data);
+ return;
+ } else if (g_strcmp0(method_name, "UnregisterMediaAgent") == 0) {
+ unregister_relay_agent_handler(connection, parameters,
+ invocation, user_data);
+ return;
+ } else if (g_strcmp0(method_name, "MediaPlayerChangeProperty") == 0) {
guint32 type, value;
g_variant_get(parameters, "(uu)", &type, &value);
return (MediaSkeleton *)g_object_new(TYPE_MEDIA_SKELETON, NULL);
}
+static gboolean handle_set_property(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ GVariantBuilder *builder;
+ GVariant *val, *signal_variant;
+
+ DBG("property_name = %s", property_name);
+
+ if (relay_agent == NULL) {
+ DBG("relay_agent == NULL");
+ return false;
+ }
+
+ if (g_strcmp0(property_name, "LoopStatus") == 0) {
+ const gchar *loopstatus = g_variant_get_string(value, NULL);
+ DBG("loopstatus = %s", loopstatus);
+
+ val = g_variant_new("s", loopstatus);
+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(builder, "{sv}", "LoopStatus", val);
+
+ signal_variant = g_variant_ref_sink(g_variant_new("(sa{sv}as)",
+ MEDIA_PLAYER_INTERFACE,
+ builder, NULL));
+
+ g_dbus_connection_emit_signal(connection, NULL,
+ relay_agent->object_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ signal_variant, NULL);
+
+ g_variant_unref(signal_variant);
+ } else if (g_strcmp0(property_name, "Shuffle") == 0) {
+ gboolean shuffle_mode = g_variant_get_boolean(value);
+ if (shuffle_mode == TRUE)
+ DBG("shuffle_mode TRUE");
+ else
+ DBG("shuffle_mode FALSE");
+
+ val = g_variant_new("b", shuffle_mode);
+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(builder, "{sv}", "Shuffle", val);
+
+ signal_variant = g_variant_ref_sink(g_variant_new("(sa{sv}as)",
+ MEDIA_PLAYER_INTERFACE,
+ builder, NULL));
+
+ g_dbus_connection_emit_signal(connection, NULL,
+ relay_agent->object_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ signal_variant, NULL);
+
+ g_variant_unref(signal_variant);
+ }
+
+ return *error == NULL;
+}
+
+static const gchar introspection_xml[] =
+"<node>"
+" <interface name='org.mpris.MediaPlayer2.Player'>"
+" <property type='b' name='Shuffle' access='readwrite'/>"
+" <property type='s' name='LoopStatus' access='readwrite'/>"
+" </interface>"
+"</node>";
+
+static const GDBusInterfaceVTable interface_vtable = {
+ NULL,
+ NULL,
+ handle_set_property
+};
+
+static GDBusNodeInfo *introspection_data;
+
+static guint bt_register_avrcp_property(struct _bluez_adapter *adapter)
+{
+ guint rid;
+ GDBusConnection *conn;
+
+ conn = g_dbus_proxy_get_connection(adapter->media_proxy);
+
+ introspection_data = g_dbus_node_info_new_for_xml(introspection_xml,
+ NULL);
+
+ rid = g_dbus_connection_register_object(conn, BT_MEDIA_OBJECT_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL,
+ NULL,
+ NULL);
+
+ return rid;
+}
+
+static void bt_unregister_avrcp_property(struct _bluez_adapter *adapter,
+ int avrcp_registration_id)
+{
+ GDBusConnection *conn;
+
+ conn = g_dbus_proxy_get_connection(adapter->media_proxy);
+
+ g_dbus_connection_unregister_object(conn,
+ avrcp_registration_id);
+}
+
+static void handle_media_proxy_cb(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GVariant *ret;
+ GError *error = NULL;
+ struct _bluez_adapter *adapter = user_data;
+ enum bluez_error_type error_type = ERROR_NONE;
+
+ DBG("");
+
+ if (adapter == NULL)
+ return;
+
+ ret = g_dbus_proxy_call_finish(adapter->media_proxy, res,
+ &error);
+ if (ret == NULL) {
+ error_type = get_error_type(error);
+ DBG("error_type = %d", error_type);
+ g_error_free(error);
+ } else
+ g_variant_unref(ret);
+}
+
+void bt_media_register_player(struct _bluez_adapter *adapter)
+{
+ GVariant *str_array[1];
+ GVariant *val_array;
+ GVariant *val_metadata;
+
+ GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ GVariantBuilder *builder_array =
+ g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+
+ GVariant *val = g_variant_new("s", "None");
+ g_variant_builder_add(builder, "{sv}", "LoopStatus", val);
+
+ val = g_variant_new("b", FALSE);
+ g_variant_builder_add(builder, "{sv}", "Shuffle", val);
+
+ val = g_variant_new("s", "Stopped");
+ g_variant_builder_add(builder, "{sv}", "PlaybackStatus", val);
+
+ val = g_variant_new("x", 0);
+ g_variant_builder_add(builder, "{sv}", "Position", val);
+
+ val = g_variant_new_string("\0");
+ str_array[0] = val;
+ val_array = g_variant_new_array(G_VARIANT_TYPE_STRING, str_array, 1);
+ g_variant_builder_add(builder_array, "{sv}", "xesam:artist", val_array);
+
+ val = g_variant_new_string("\0");
+ str_array[0] = val;
+ val_array = g_variant_new_array(G_VARIANT_TYPE_STRING, str_array, 1);
+ g_variant_builder_add(builder_array, "{sv}", "xesam:genre", val_array);
+
+ val = g_variant_new("s", "\0");
+ g_variant_builder_add(builder_array, "{sv}", "xesam:title", val);
+
+ val = g_variant_new("i", 0);
+ g_variant_builder_add(builder_array, "{sv}", "xesam:trackNumber", val);
+
+ val = g_variant_new("s", "\0");
+ g_variant_builder_add(builder_array, "{sv}", "xesam:album", val);
+
+ val = g_variant_new("x", 0);
+ g_variant_builder_add(builder_array, "{sv}", "mpris:length", val);
+
+ val_metadata = g_variant_new("a{sv}", builder_array);
+ g_variant_builder_add(builder, "{sv}", "Metadata", val_metadata);
+
+ DBG("+");
+
+ if (adapter == NULL) {
+ ERROR("adapter is NULL");
+ return;
+ }
+
+ if (adapter->media_proxy == NULL) {
+ ERROR("adapter->mediaprooxy is NULL");
+ return;
+ }
+
+ if (adapter->avrcp_registration_id == 0)
+ adapter->avrcp_registration_id =
+ bt_register_avrcp_property(adapter);
+
+ g_dbus_proxy_call(adapter->media_proxy,
+ "RegisterPlayer",
+ g_variant_new("(oa{sv})",
+ BT_MEDIA_OBJECT_PATH, builder),
+ 0, -1, NULL,
+ handle_media_proxy_cb,
+ adapter);
+
+ DBG("-");
+ return;
+}
+
+void bt_media_unregister_player(struct _bluez_adapter *adapter)
+{
+ DBG("+");
+
+ if (adapter == NULL) {
+ ERROR("adapter is NULL");
+ return;
+ }
+
+ if (adapter->media_proxy == NULL) {
+ ERROR("adapter->mediaprooxy is NULL");
+ return;
+ }
+
+ g_dbus_proxy_call(adapter->media_proxy,
+ "UnregisterPlayer",
+ g_variant_new("(o)", BT_MEDIA_OBJECT_PATH),
+ 0, -1, NULL,
+ handle_media_proxy_cb,
+ adapter);
+
+ if (adapter->avrcp_registration_id)
+ bt_unregister_avrcp_property(adapter,
+ adapter->avrcp_registration_id);
+
+ adapter->avrcp_registration_id = 0;
+
+ DBG("-");
+ return;
+}
+
void bt_service_media_init(GDBusObjectSkeleton *gdbus_object_skeleton,
GDBusConnection *connection,
bluez_adapter_t *adapter)