mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-26 23:25:56 -05:00
[dacp] Support for dmcp.device-prevent-playback (issue #855)
This commit is contained in:
parent
80b183c7ff
commit
af1bc27dd5
@ -12,6 +12,7 @@ struct dacp_prop_map;
|
||||
%%
|
||||
"dmcp.volume", dacp_propget_volume, dacp_propset_volume
|
||||
"dmcp.device-volume", NULL, dacp_propset_devicevolume
|
||||
"dmcp.device-prevent-playback", NULL, dacp_propset_devicepreventplayback
|
||||
"dacp.playerstate", dacp_propget_playerstate, NULL
|
||||
"dacp.nowplaying", dacp_propget_nowplaying, NULL
|
||||
"dacp.playingtime", dacp_propget_playingtime, dacp_propset_playingtime
|
||||
|
@ -112,6 +112,8 @@ dacp_propset_volume(const char *value, struct httpd_request *hreq);
|
||||
static void
|
||||
dacp_propset_devicevolume(const char *value, struct httpd_request *hreq);
|
||||
static void
|
||||
dacp_propset_devicepreventplayback(const char *value, struct httpd_request *hreq);
|
||||
static void
|
||||
dacp_propset_playingtime(const char *value, struct httpd_request *hreq);
|
||||
static void
|
||||
dacp_propset_shufflestate(const char *value, struct httpd_request *hreq);
|
||||
@ -957,19 +959,68 @@ static void
|
||||
dacp_propset_devicevolume(const char *value, struct httpd_request *hreq)
|
||||
{
|
||||
struct evkeyvalq *headers;
|
||||
struct player_speaker_info spk_info;
|
||||
const char *remote;
|
||||
uint32_t id;
|
||||
uint32_t active_remote;
|
||||
int ret;
|
||||
|
||||
headers = evhttp_request_get_input_headers(hreq->req);
|
||||
remote = evhttp_find_header(headers, "Active-Remote");
|
||||
|
||||
if (!headers || !remote || (safe_atou32(remote, &id) < 0))
|
||||
if (!headers || !remote || (safe_atou32(remote, &active_remote) < 0))
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Request for setting device-volume has invalid Active-Remote: '%s'\n", remote);
|
||||
return;
|
||||
}
|
||||
|
||||
player_volume_byactiveremote(id, value);
|
||||
ret = player_speaker_get_byactiveremote(&spk_info, active_remote);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Request for setting device-volume from unknown Active-Remote: '%s'\n", remote);
|
||||
return;
|
||||
}
|
||||
|
||||
player_volume_update_speaker(spk_info.id, value);
|
||||
}
|
||||
|
||||
// iTunes seems to use this as way for a speaker to tell the server that it is
|
||||
// busy with something else. If the speaker makes the request with the value 1,
|
||||
// then iTunes will disable the speaker, and if it is the only speaker, then
|
||||
// playback will also be paused. It is not possible for the user to restart the
|
||||
// speaker until it has made a request with value 0 (if attempted, iTunes will
|
||||
// show it is waiting for the speaker). As you can see from the below, we
|
||||
// don't fully match this behaviour, instead we just enable/disable.
|
||||
static void
|
||||
dacp_propset_devicepreventplayback(const char *value, struct httpd_request *hreq)
|
||||
{
|
||||
struct evkeyvalq *headers;
|
||||
struct player_speaker_info spk_info;
|
||||
const char *remote;
|
||||
uint32_t active_remote;
|
||||
int ret;
|
||||
|
||||
headers = evhttp_request_get_input_headers(hreq->req);
|
||||
remote = evhttp_find_header(headers, "Active-Remote");
|
||||
|
||||
if (!headers || !remote || (safe_atou32(remote, &active_remote) < 0))
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Request for setting device-prevent-playback has invalid Active-Remote: '%s'\n", remote);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = player_speaker_get_byactiveremote(&spk_info, active_remote);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Request for setting device-prevent-playback from unknown Active-Remote: '%s'\n", remote);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value[0] == '1')
|
||||
player_speaker_disable(spk_info.id);
|
||||
else if (value[0] == '0')
|
||||
player_speaker_enable(spk_info.id);
|
||||
else
|
||||
DPRINTF(E_LOG, L_DACP, "Request for setting device-prevent-playback has invalid value: '%s'\n", value);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2438,6 +2489,7 @@ dacp_reply_setproperty(struct httpd_request *hreq)
|
||||
* dacp.playingtime seek to time in ms
|
||||
* dmcp.volume 0-100, float
|
||||
* dmcp.device-volume -144-0, float (raop volume)
|
||||
* dmcp.device-prevent-playback 0/1
|
||||
*/
|
||||
|
||||
/* /ctrl-int/1/setproperty?dacp.shufflestate=1&session-id=100 */
|
||||
|
73
src/player.c
73
src/player.c
@ -113,12 +113,8 @@
|
||||
//#define DEBUG_PLAYER 1
|
||||
|
||||
struct volume_param {
|
||||
int volume;
|
||||
uint64_t spk_id;
|
||||
};
|
||||
|
||||
struct activeremote_param {
|
||||
uint32_t activeremote;
|
||||
int volume;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
@ -137,6 +133,7 @@ struct speaker_set_param
|
||||
struct speaker_get_param
|
||||
{
|
||||
uint64_t spk_id;
|
||||
uint32_t active_remote;
|
||||
struct player_speaker_info *spk_info;
|
||||
};
|
||||
|
||||
@ -2392,6 +2389,7 @@ device_to_speaker_info(struct player_speaker_info *spk, struct output_device *de
|
||||
{
|
||||
memset(spk, 0, sizeof(struct player_speaker_info));
|
||||
spk->id = device->id;
|
||||
spk->active_remote = (uint32_t)device->id;
|
||||
strncpy(spk->name, device->name, sizeof(spk->name));
|
||||
spk->name[sizeof(spk->name) - 1] = '\0';
|
||||
strncpy(spk->output_type, device->type_name, sizeof(spk->output_type));
|
||||
@ -2445,6 +2443,27 @@ speaker_get_byid(void *arg, int *retval)
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
speaker_get_byactiveremote(void *arg, int *retval)
|
||||
{
|
||||
struct speaker_get_param *spk_param = arg;
|
||||
struct output_device *device;
|
||||
|
||||
for (device = output_device_list; device; device = device->next)
|
||||
{
|
||||
if ((uint32_t)device->id == spk_param->active_remote)
|
||||
{
|
||||
device_to_speaker_info(spk_param->spk_info, device);
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
}
|
||||
|
||||
// No output device found with matching id
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
speaker_activate(struct output_device *device)
|
||||
{
|
||||
@ -2770,33 +2789,23 @@ volume_setabs_speaker(void *arg, int *retval)
|
||||
|
||||
// Just updates internal volume params (does not make actual requests to the speaker)
|
||||
static enum command_state
|
||||
volume_byactiveremote(void *arg, int *retval)
|
||||
volume_update_speaker(void *arg, int *retval)
|
||||
{
|
||||
struct activeremote_param *ar_param = arg;
|
||||
struct volume_param *vol_param = arg;
|
||||
struct output_device *device;
|
||||
uint32_t activeremote;
|
||||
int volume;
|
||||
|
||||
*retval = 0;
|
||||
activeremote = ar_param->activeremote;
|
||||
|
||||
for (device = output_device_list; device; device = device->next)
|
||||
{
|
||||
if ((uint32_t)device->id == activeremote)
|
||||
break;
|
||||
}
|
||||
|
||||
device = outputs_device_get(vol_param->spk_id);
|
||||
if (!device)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not find speaker with Active-Remote id %d\n", activeremote);
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
volume = outputs_device_volume_to_pct(device, ar_param->value); // Only converts
|
||||
volume = outputs_device_volume_to_pct(device, vol_param->value); // Only converts
|
||||
if (volume < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not parse volume given by Active-Remote id %d\n", activeremote);
|
||||
DPRINTF(E_LOG, L_DACP, "Could not parse volume '%s' in update_volume() for speaker '%s'\n", vol_param->value, device->name);
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
@ -2811,6 +2820,7 @@ volume_byactiveremote(void *arg, int *retval)
|
||||
|
||||
listener_notify(LISTENER_VOLUME);
|
||||
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
@ -3111,6 +3121,19 @@ player_speaker_get_byid(uint64_t id, struct player_speaker_info *spk)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t active_remote)
|
||||
{
|
||||
struct speaker_get_param param;
|
||||
int ret;
|
||||
|
||||
param.active_remote = active_remote;
|
||||
param.spk_info = spk;
|
||||
|
||||
ret = commands_exec_sync(cmdbase, speaker_get_byactiveremote, NULL, ¶m);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
player_speaker_enable(uint64_t id)
|
||||
{
|
||||
@ -3192,15 +3215,15 @@ player_volume_setabs_speaker(uint64_t id, int vol)
|
||||
}
|
||||
|
||||
int
|
||||
player_volume_byactiveremote(uint32_t activeremote, const char *value)
|
||||
player_volume_update_speaker(uint64_t id, const char *value)
|
||||
{
|
||||
struct activeremote_param ar_param;
|
||||
struct volume_param vol_param;
|
||||
int ret;
|
||||
|
||||
ar_param.activeremote = activeremote;
|
||||
ar_param.value = value;
|
||||
vol_param.spk_id = id;
|
||||
vol_param.value = value;
|
||||
|
||||
ret = commands_exec_sync(cmdbase, volume_byactiveremote, NULL, &ar_param);
|
||||
ret = commands_exec_sync(cmdbase, volume_update_speaker, NULL, &vol_param);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ enum player_seek_mode {
|
||||
|
||||
struct player_speaker_info {
|
||||
uint64_t id;
|
||||
uint32_t active_remote;
|
||||
char name[255];
|
||||
char output_type[50];
|
||||
int relvol;
|
||||
@ -92,6 +93,9 @@ player_speaker_set(uint64_t *ids);
|
||||
int
|
||||
player_speaker_get_byid(uint64_t id, struct player_speaker_info *spk);
|
||||
|
||||
int
|
||||
player_speaker_get_byactiveremote(struct player_speaker_info *spk, uint32_t active_remote);
|
||||
|
||||
int
|
||||
player_speaker_enable(uint64_t id);
|
||||
|
||||
@ -132,7 +136,7 @@ int
|
||||
player_volume_setabs_speaker(uint64_t id, int vol);
|
||||
|
||||
int
|
||||
player_volume_byactiveremote(uint32_t activeremote, const char *value);
|
||||
player_volume_update_speaker(uint64_t id, const char *value);
|
||||
|
||||
int
|
||||
player_repeat_set(enum repeat_mode mode);
|
||||
|
Loading…
Reference in New Issue
Block a user