There is possibility to register more then one player,so this patch allow to change active player to the freely chosen previously registered player. It is working in compatibility of AVRCP 1.3. --- audio/avrcp.c | 37 +++++++++++++++++++++++++++++ audio/avrcp.h | 1 + audio/media.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/media-api.txt | 14 +++++++++++ 4 files changed, 118 insertions(+), 0 deletions(-) diff --git a/audio/avrcp.c b/audio/avrcp.c index f0c9665..12016b3 100644 --- a/audio/avrcp.c +++ b/audio/avrcp.c @@ -1327,3 +1327,40 @@ void avrcp_unregister_player(struct avrcp_player *player) player_destroy(player); } + +void avrcp_set_active_player(struct avrcp_player *player) +{ + struct avrcp_server *server = player->server; + uint8_t status; + uint64_t uid; + + status = player->cb->get_status(player->user_data); + uid = player->cb->get_uid(player->user_data); + + player_abort_pending_pdu(server->active_player); + + if (status != + server->active_player->cb->get_status(server->active_player->user_data)) + avrcp_player_event(server->active_player, AVRCP_EVENT_STATUS_CHANGED, + &status); + avrcp_player_event(server->active_player, AVRCP_EVENT_TRACK_CHANGED, + &uid); + + player->registered_events = server->active_player->registered_events; + server->active_player->registered_events = 0; + memcpy(player->transaction_events, + server->active_player->transaction_events, AVRCP_EVENT_LAST); + + player->session = server->active_player->session; + server->active_player->session = NULL; + + if (server->active_player->handler) { + avctp_unregister_pdu_handler(server->active_player->handler); + server->active_player->handler = 0; + } + + player->handler = avctp_register_pdu_handler(AVC_OP_VENDORDEP, + handle_vendordep_pdu, player); + + server->active_player = player; +} diff --git a/audio/avrcp.h b/audio/avrcp.h index 8a09546..f2041a7 100644 --- a/audio/avrcp.h +++ b/audio/avrcp.h @@ -96,6 +96,7 @@ struct avrcp_player *avrcp_register_player(const bdaddr_t *src, void *user_data, GDestroyNotify destroy); void avrcp_unregister_player(struct avrcp_player *player); +void avrcp_set_active_player(struct avrcp_player *player); int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data); diff --git a/audio/media.c b/audio/media.c index c0fd0c3..99f1a9a 100644 --- a/audio/media.c +++ b/audio/media.c @@ -1705,11 +1705,77 @@ static DBusMessage *unregister_player(DBusConnection *conn, DBusMessage *msg, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +static DBusMessage *set_active_player(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + struct media_adapter *adapter = data; + struct media_player *player; + const char *sender, *path; + DBusMessage *signal_msg; + GSList *l; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + return NULL; + + sender = dbus_message_get_sender(msg); + + player = media_adapter_find_player(adapter, sender, path); + if (player == NULL) + return btd_error_does_not_exist(msg); + + avrcp_set_active_player(player->player); + + for (l = adapter->players; l; l = l->next) { + struct media_player *mp = l->data; + + if (path && g_strcmp0(mp->path, path) == 0) { + DBG("Activate player: %s", mp->path); + + signal_msg = dbus_message_new_signal(mp->path, + MEDIA_PLAYER_INTERFACE, + "Activated"); + + if (signal_msg == NULL) { + DBG("Message null"); + return NULL; + } + + if (!dbus_connection_send(conn, signal_msg, NULL)) { + DBG("Out of memory"); + return NULL; + } + + dbus_message_unref(signal_msg); + } else { + signal_msg = dbus_message_new_signal(mp->path, + MEDIA_PLAYER_INTERFACE, + "Deactivated"); + + if (signal_msg == NULL) { + DBG("Message null"); + return NULL; + } + + if (!dbus_connection_send(conn, signal_msg, NULL)) { + DBG("Out of memory"); + return NULL; + } + + dbus_message_unref(signal_msg); + } + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + static GDBusMethodTable media_methods[] = { { "RegisterEndpoint", "oa{sv}", "", register_endpoint }, { "UnregisterEndpoint", "o", "", unregister_endpoint }, { "RegisterPlayer", "oa{sv}a{sv}","", register_player }, { "UnregisterPlayer", "o", "", unregister_player }, + { "SetActivePlayer", "o", "", set_active_player }, { }, }; diff --git a/doc/media-api.txt b/doc/media-api.txt index c53ab7b..c64d1f5 100644 --- a/doc/media-api.txt +++ b/doc/media-api.txt @@ -123,6 +123,11 @@ Methods void RegisterEndpoint(object endpoint, dict properties) Unregister sender media player. + void SetActivePlayer(object player) + + Set active media player. Only one active player may be used + by remote controller. + MediaPlayer hierarchy ===================== @@ -188,6 +193,15 @@ Signals PropertyChanged(string setting, variant value) Track duration in milliseconds + Activated() + + This signal indicates one player to be currently used. + + Deactivated() + + This signal sends to all non-active players and indicates that + player lose focus. + Properties string Equalizer [readwrite] Possible values: "off" or "on" -- on behalf of ST-Ericsson -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html