diff --git a/audio/avrcp.c b/audio/avrcp.c
index 884877e..57502ff 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
cid[2] = cid_in;
}
+static int player_get_attribute(struct avrcp_player *player, uint8_t attr)
+{
+ int value;
+
+ DBG("attr %u", attr);
+
+ if (player == NULL)
+ return -ENOENT;
+
+ value = player->cb->get_setting(attr, player->user_data);
+ if (value < 0)
+ DBG("attr %u not supported by player", attr);
+
+ return value;
+}
+
void avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data)
{
uint8_t buf[AVRCP_HEADER_LENGTH + 9];
struct avrcp_header *pdu = (void *) buf;
uint16_t size;
GSList *l;
+ GList *settings;
if (player->sessions == NULL)
return;
case AVRCP_EVENT_TRACK_REACHED_START:
size = 1;
break;
+ case AVRCP_EVENT_SETTINGS_CHANGED:
+ size = 2;
+ settings = data;
+ pdu->params[1] = g_list_length(settings);
+ for (; settings; settings = settings->next) {
+ uint8_t attr = GPOINTER_TO_UINT(settings->data);
+ int val;
+
+ val = player_get_attribute(player, attr);
+ if (val < 0)
+ continue;
+
+ pdu->params[++size] = attr;
+ pdu->params[++size] = val;
+ }
+ break;
default:
error("Unknown event %u", id);
return;
return AVC_CTYPE_STABLE;
case CAP_EVENTS_SUPPORTED:
- pdu->params[1] = 4;
+ pdu->params[1] = 5;
pdu->params[2] = AVRCP_EVENT_STATUS_CHANGED;
pdu->params[3] = AVRCP_EVENT_TRACK_CHANGED;
pdu->params[4] = AVRCP_EVENT_TRACK_REACHED_START;
pdu->params[5] = AVRCP_EVENT_TRACK_REACHED_END;
+ pdu->params[6] = AVRCP_EVENT_SETTINGS_CHANGED;
pdu->params_len = htons(2 + pdu->params[1]);
return AVC_CTYPE_STABLE;
return player->cb->get_uid(player->user_data);
}
+static GList *player_list_settings(struct avrcp_player *player)
+{
+ if (player == NULL)
+ return NULL;
+
+ return player->cb->list_settings(player->user_data);
+}
+
static uint8_t avrcp_handle_register_notification(struct avrcp *session,
struct avrcp_header *pdu,
uint8_t transaction)
struct avrcp_player *player = session->player;
uint16_t len = ntohs(pdu->params_len);
uint64_t uid;
+ GList *settings;
/*
* 1 byte for EventID, 4 bytes for Playback interval but the latest
case AVRCP_EVENT_TRACK_REACHED_START:
len = 1;
break;
+ case AVRCP_EVENT_SETTINGS_CHANGED:
+ settings = player_list_settings(player);
+
+ pdu->params[++len] = g_list_length(settings);
+ for (; settings; settings = settings->next) {
+ uint8_t attr = GPOINTER_TO_UINT(settings->data);
+ int val;
+
+ val = player_get_attribute(player, attr);
+ if (val < 0)
+ continue;
+
+ pdu->params[++len] = attr;
+ pdu->params[++len] = val;
+ }
+
+ break;
default:
/* All other events are not supported yet */
goto err;
diff --git a/audio/avrcp.h b/audio/avrcp.h
index 31fdf8d..7f54adb 100644
--- a/audio/avrcp.h
+++ b/audio/avrcp.h
#define AVRCP_EVENT_TRACK_CHANGED 0x02
#define AVRCP_EVENT_TRACK_REACHED_END 0x03
#define AVRCP_EVENT_TRACK_REACHED_START 0x04
+#define AVRCP_EVENT_SETTINGS_CHANGED 0x08
#define AVRCP_EVENT_VOLUME_CHANGED 0x0d
#define AVRCP_EVENT_LAST AVRCP_EVENT_VOLUME_CHANGED
struct avrcp_player_cb {
+ GList *(*list_settings) (void *user_data);
int (*get_setting) (uint8_t attr, void *user_data);
int (*set_setting) (uint8_t attr, uint8_t value, void *user_data);
uint64_t (*get_uid) (void *user_data);
diff --git a/audio/media.c b/audio/media.c
index ca08356..962fc97 100644
--- a/audio/media.c
+++ b/audio/media.c
return NULL;
}
+static GList *list_settings(void *user_data)
+{
+ struct media_player *mp = user_data;
+
+ DBG("");
+
+ if (mp->settings == NULL)
+ return NULL;
+
+ return g_hash_table_get_keys(mp->settings);
+}
+
static int get_setting(uint8_t attr, void *user_data)
{
struct media_player *mp = user_data;
}
static struct avrcp_player_cb player_cb = {
+ .list_settings = list_settings,
.get_setting = get_setting,
.set_setting = set_setting,
.list_metadata = list_metadata,
DBusMessageIter *entry)
{
DBusMessageIter var;
- const char *value;
+ const char *value, *curval;
int attr, val;
+ GList *settings;
if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
return FALSE;
if (val < 0)
return FALSE;
+ curval = g_hash_table_lookup(mp->settings, GUINT_TO_POINTER(attr));
+ if (g_strcmp0(curval, value) == 0)
+ return TRUE;
+
DBG("%s=%s", key, value);
g_hash_table_replace(mp->settings, GUINT_TO_POINTER(attr),
GUINT_TO_POINTER(val));
+ settings = list_settings(mp);
+
+ avrcp_player_event(mp->player, AVRCP_EVENT_SETTINGS_CHANGED, settings);
+
+ g_list_free(settings);
+
return TRUE;
}