2
* Copyright (C) 2010 Julien BLACHE <jb@jblache.org>
2
* Copyright (C) 2010-2011 Julien BLACHE <jb@jblache.org>
4
4
* This program is free software; you can redistribute it and/or modify
5
5
* it under the terms of the GNU General Public License as published by
118
116
dacp_propset_userrating(const char *value, struct evkeyvalq *query);
120
static struct dacp_prop_map dacp_props[] =
122
{ 0, "dmcp.volume", dacp_propget_volume, dacp_propset_volume },
123
{ 0, "dacp.playerstate", dacp_propget_playerstate, NULL },
124
{ 0, "dacp.nowplaying", dacp_propget_nowplaying, NULL },
125
{ 0, "dacp.playingtime", dacp_propget_playingtime, dacp_propset_playingtime },
126
{ 0, "dacp.volumecontrollable", dacp_propget_volumecontrollable, NULL },
127
{ 0, "dacp.availableshufflestates", dacp_propget_availableshufflestates, NULL },
128
{ 0, "dacp.availablerepeatstates", dacp_propget_availablerepeatstates, NULL },
129
{ 0, "dacp.shufflestate", dacp_propget_shufflestate, dacp_propset_shufflestate },
130
{ 0, "dacp.repeatstate", dacp_propget_repeatstate, dacp_propset_repeatstate },
131
{ 0, "dacp.userrating", NULL, dacp_propset_userrating },
133
{ 0, NULL, NULL, NULL }
119
/* gperf static hash, dacp_prop.gperf */
120
#include "dacp_prop_hash.c"
137
123
/* Play status update */
397
/* Properties helpers */
399
dacp_prop_map_compare(const void *aa, const void *bb)
401
struct dacp_prop_map *a = (struct dacp_prop_map *)aa;
402
struct dacp_prop_map *b = (struct dacp_prop_map *)bb;
404
if (a->hash < b->hash)
407
if (a->hash > b->hash)
413
static struct dacp_prop_map *
414
dacp_find_prop(uint32_t hash)
416
struct dacp_prop_map dpm;
421
node = avl_search(dacp_props_hash, &dpm);
425
return (struct dacp_prop_map *)node->item;
429
parse_properties(struct evhttp_request *req, char *tag, const char *param, uint32_t **out_prop, int *out_nprop)
440
propstr = strdup(param);
443
DPRINTF(E_LOG, L_DACP, "Could not duplicate properties parameter; out of memory\n");
445
dmap_send_error(req, tag, "Out of memory");
451
while ((ptr = strchr(ptr + 1, ',')))
454
DPRINTF(E_DBG, L_DACP, "Asking for %d properties\n", nprop);
456
hashes = (uint32_t *)malloc((nprop + 1) * sizeof(uint32_t));
459
DPRINTF(E_LOG, L_DACP, "Could not allocate properties array; out of memory\n");
461
dmap_send_error(req, tag, "Out of memory");
466
memset(hashes, 0, (nprop + 1) * sizeof(uint32_t));
468
prop = strtok_r(propstr, ",", &ptr);
469
for (i = 0; i < nprop; i++)
471
hashes[i] = djb_hash(prop, strlen(prop));
473
prop = strtok_r(NULL, ",", &ptr);
478
DPRINTF(E_DBG, L_DACP, "Found %d properties\n", nprop);
486
380
/* Properties getters */
488
382
dacp_propget_volume(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
1270
1165
goto no_artwork;
1272
ret = artwork_get_item(id, max_w, max_h, evbuf);
1167
ret = artwork_get_item(id, max_w, max_h, ART_CAN_PNG | ART_CAN_JPEG, evbuf);
1275
if (EVBUFFER_LENGTH(evbuf) > 0)
1276
evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf));
1171
ctype = "image/png";
1175
ctype = "image/jpeg";
1179
if (EVBUFFER_LENGTH(evbuf) > 0)
1180
evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf));
1281
1185
evhttp_remove_header(req->output_headers, "Content-Type");
1282
evhttp_add_header(req->output_headers, "Content-Type", "image/png");
1186
evhttp_add_header(req->output_headers, "Content-Type", ctype);
1283
1187
snprintf(clen, sizeof(clen), "%ld", (long)EVBUFFER_LENGTH(evbuf));
1284
1188
evhttp_add_header(req->output_headers, "Content-Length", clen);
1297
1201
struct player_status status;
1298
1202
struct daap_session *s;
1299
struct dacp_prop_map *dpm;
1203
const struct dacp_prop_map *dpm;
1300
1204
struct media_file_info *mfi;
1301
1205
struct evbuffer *proplist;
1302
1206
const char *param;
1308
1212
s = daap_session_find(req, query, evbuf);
1321
parse_properties(req, "cmgt", param, &prop, &nprop);
1225
propstr = strdup(param);
1324
DPRINTF(E_LOG, L_DACP, "Failed to parse properties parameter in getproperty call\n");
1228
DPRINTF(E_LOG, L_DACP, "Could not duplicate properties parameter; out of memory\n");
1230
dmap_send_error(req, "cmgt", "Out of memory");
1332
1237
DPRINTF(E_LOG, L_DACP, "Could not allocate evbuffer for properties list\n");
1334
1239
dmap_send_error(req, "cmgt", "Out of memory");
1240
goto out_free_propstr;
1338
1243
player_get_status(&status);
1354
for (i = 0; i < nprop; i++)
1259
prop = strtok_r(propstr, ",", &ptr);
1356
dpm = dacp_find_prop(prop[i]);
1262
dpm = dacp_find_prop(prop, strlen(prop));
1359
DPRINTF(E_LOG, L_DACP, "Could not find requested property (%d)\n", i + 1);
1265
DPRINTF(E_LOG, L_DACP, "Could not find requested property '%s'\n", prop);
1363
1269
if (dpm->propget)
1364
1270
dpm->propget(proplist, &status, mfi);
1366
DPRINTF(E_WARN, L_DACP, "No getter method for DACP property %s\n", dpm->desc);
1272
DPRINTF(E_WARN, L_DACP, "No getter method for DACP property %s\n", prop);
1274
prop = strtok_r(NULL, ",", &ptr);
1370
1280
free_mfi(mfi, 0);
1375
1282
dmap_add_container(evbuf, "cmgt", 12 + EVBUFFER_LENGTH(proplist)); /* 8 + len */
1376
1283
dmap_add_int(evbuf, "mstt", 200); /* 12 */
1392
1299
out_free_proplist:
1393
1300
evbuffer_free(proplist);
1401
1307
dacp_reply_setproperty(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
1403
1309
struct daap_session *s;
1404
struct dacp_prop_map *dpm;
1310
const struct dacp_prop_map *dpm;
1405
1311
struct evkeyval *param;
1408
1313
s = daap_session_find(req, query, evbuf);
1421
1326
TAILQ_FOREACH(param, query, next)
1423
hash = djb_hash(param->key, strlen(param->key));
1425
dpm = dacp_find_prop(hash);
1328
dpm = dacp_find_prop(param->key, strlen(param->key));
1444
speaker_enum_cb(uint64_t id, const char *name, int relvol, int selected, int has_password, void *arg)
1347
speaker_enum_cb(uint64_t id, const char *name, int relvol, struct spk_flags flags, void *arg)
1446
1349
struct evbuffer *evbuf;
1449
1352
evbuf = (struct evbuffer *)arg;
1451
1354
len = 8 + strlen(name) + 28;
1357
if (flags.has_password)
1359
if (flags.has_video)
1457
1362
dmap_add_container(evbuf, "mdcl", len); /* 8 + len */
1459
1364
dmap_add_char(evbuf, "caia", 1); /* 9 */
1365
if (flags.has_password)
1461
1366
dmap_add_char(evbuf, "cahp", 1); /* 9 */
1367
if (flags.has_video)
1368
dmap_add_char(evbuf, "caiv", 1); /* 9 */
1462
1369
dmap_add_string(evbuf, "minm", name); /* 8 + len */
1463
1370
dmap_add_long(evbuf, "msma", id); /* 16 */
1830
dacp_props_hash = avl_alloc_tree(dacp_prop_map_compare, NULL);
1831
if (!dacp_props_hash)
1833
DPRINTF(E_FATAL, L_DACP, "DACP init could not allocate DACP props AVL tree\n");
1835
goto dacp_avl_alloc_fail;
1838
for (i = 0; dacp_props[i].desc; i++)
1840
dacp_props[i].hash = djb_hash(dacp_props[i].desc, strlen(dacp_props[i].desc));
1842
node = avl_insert(dacp_props_hash, &dacp_props[i]);
1845
if (errno != EEXIST)
1846
DPRINTF(E_FATAL, L_DACP, "DACP init failed; AVL insert error: %s\n", strerror(errno));
1849
node = avl_search(dacp_props_hash, &dacp_props[i]);
1852
DPRINTF(E_FATAL, L_DACP, "DACP init failed; WARNING: duplicate hash key\n");
1853
DPRINTF(E_FATAL, L_DACP, "Hash %x, string %s\n", dacp_props[i].hash, dacp_props[i].desc);
1855
DPRINTF(E_FATAL, L_DACP, "Hash %x, string %s\n", dpm->hash, dpm->desc);
1858
goto dacp_avl_insert_fail;
1862
1735
#ifdef USE_EVENTFD
1863
1736
event_set(&updateev, update_efd, EV_READ, playstatusupdate_cb, NULL);