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.volume", dacp_propget_volume, dacp_propset_volume
|
||||||
"dmcp.device-volume", NULL, dacp_propset_devicevolume
|
"dmcp.device-volume", NULL, dacp_propset_devicevolume
|
||||||
|
"dmcp.device-prevent-playback", NULL, dacp_propset_devicepreventplayback
|
||||||
"dacp.playerstate", dacp_propget_playerstate, NULL
|
"dacp.playerstate", dacp_propget_playerstate, NULL
|
||||||
"dacp.nowplaying", dacp_propget_nowplaying, NULL
|
"dacp.nowplaying", dacp_propget_nowplaying, NULL
|
||||||
"dacp.playingtime", dacp_propget_playingtime, dacp_propset_playingtime
|
"dacp.playingtime", dacp_propget_playingtime, dacp_propset_playingtime
|
||||||
|
@ -112,6 +112,8 @@ dacp_propset_volume(const char *value, struct httpd_request *hreq);
|
|||||||
static void
|
static void
|
||||||
dacp_propset_devicevolume(const char *value, struct httpd_request *hreq);
|
dacp_propset_devicevolume(const char *value, struct httpd_request *hreq);
|
||||||
static void
|
static void
|
||||||
|
dacp_propset_devicepreventplayback(const char *value, struct httpd_request *hreq);
|
||||||
|
static void
|
||||||
dacp_propset_playingtime(const char *value, struct httpd_request *hreq);
|
dacp_propset_playingtime(const char *value, struct httpd_request *hreq);
|
||||||
static void
|
static void
|
||||||
dacp_propset_shufflestate(const char *value, struct httpd_request *hreq);
|
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)
|
dacp_propset_devicevolume(const char *value, struct httpd_request *hreq)
|
||||||
{
|
{
|
||||||
struct evkeyvalq *headers;
|
struct evkeyvalq *headers;
|
||||||
|
struct player_speaker_info spk_info;
|
||||||
const char *remote;
|
const char *remote;
|
||||||
uint32_t id;
|
uint32_t active_remote;
|
||||||
|
int ret;
|
||||||
|
|
||||||
headers = evhttp_request_get_input_headers(hreq->req);
|
headers = evhttp_request_get_input_headers(hreq->req);
|
||||||
remote = evhttp_find_header(headers, "Active-Remote");
|
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);
|
DPRINTF(E_LOG, L_DACP, "Request for setting device-volume has invalid Active-Remote: '%s'\n", remote);
|
||||||
return;
|
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
|
static void
|
||||||
@ -2433,11 +2484,12 @@ dacp_reply_setproperty(struct httpd_request *hreq)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Known properties (see dacp_prop.gperf):
|
/* Known properties (see dacp_prop.gperf):
|
||||||
* dacp.shufflestate 0/1
|
* dacp.shufflestate 0/1
|
||||||
* dacp.repeatstate 0/1/2
|
* dacp.repeatstate 0/1/2
|
||||||
* dacp.playingtime seek to time in ms
|
* dacp.playingtime seek to time in ms
|
||||||
* dmcp.volume 0-100, float
|
* dmcp.volume 0-100, float
|
||||||
* dmcp.device-volume -144-0, float (raop volume)
|
* dmcp.device-volume -144-0, float (raop volume)
|
||||||
|
* dmcp.device-prevent-playback 0/1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* /ctrl-int/1/setproperty?dacp.shufflestate=1&session-id=100 */
|
/* /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
|
//#define DEBUG_PLAYER 1
|
||||||
|
|
||||||
struct volume_param {
|
struct volume_param {
|
||||||
int volume;
|
|
||||||
uint64_t spk_id;
|
uint64_t spk_id;
|
||||||
};
|
int volume;
|
||||||
|
|
||||||
struct activeremote_param {
|
|
||||||
uint32_t activeremote;
|
|
||||||
const char *value;
|
const char *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -137,6 +133,7 @@ struct speaker_set_param
|
|||||||
struct speaker_get_param
|
struct speaker_get_param
|
||||||
{
|
{
|
||||||
uint64_t spk_id;
|
uint64_t spk_id;
|
||||||
|
uint32_t active_remote;
|
||||||
struct player_speaker_info *spk_info;
|
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));
|
memset(spk, 0, sizeof(struct player_speaker_info));
|
||||||
spk->id = device->id;
|
spk->id = device->id;
|
||||||
|
spk->active_remote = (uint32_t)device->id;
|
||||||
strncpy(spk->name, device->name, sizeof(spk->name));
|
strncpy(spk->name, device->name, sizeof(spk->name));
|
||||||
spk->name[sizeof(spk->name) - 1] = '\0';
|
spk->name[sizeof(spk->name) - 1] = '\0';
|
||||||
strncpy(spk->output_type, device->type_name, sizeof(spk->output_type));
|
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;
|
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
|
static int
|
||||||
speaker_activate(struct output_device *device)
|
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)
|
// Just updates internal volume params (does not make actual requests to the speaker)
|
||||||
static enum command_state
|
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;
|
struct output_device *device;
|
||||||
uint32_t activeremote;
|
|
||||||
int volume;
|
int volume;
|
||||||
|
|
||||||
*retval = 0;
|
device = outputs_device_get(vol_param->spk_id);
|
||||||
activeremote = ar_param->activeremote;
|
|
||||||
|
|
||||||
for (device = output_device_list; device; device = device->next)
|
|
||||||
{
|
|
||||||
if ((uint32_t)device->id == activeremote)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!device)
|
if (!device)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_DACP, "Could not find speaker with Active-Remote id %d\n", activeremote);
|
|
||||||
*retval = -1;
|
*retval = -1;
|
||||||
return COMMAND_END;
|
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)
|
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;
|
*retval = -1;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
}
|
}
|
||||||
@ -2811,6 +2820,7 @@ volume_byactiveremote(void *arg, int *retval)
|
|||||||
|
|
||||||
listener_notify(LISTENER_VOLUME);
|
listener_notify(LISTENER_VOLUME);
|
||||||
|
|
||||||
|
*retval = 0;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3111,6 +3121,19 @@ player_speaker_get_byid(uint64_t id, struct player_speaker_info *spk)
|
|||||||
return ret;
|
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
|
int
|
||||||
player_speaker_enable(uint64_t id)
|
player_speaker_enable(uint64_t id)
|
||||||
{
|
{
|
||||||
@ -3192,15 +3215,15 @@ player_volume_setabs_speaker(uint64_t id, int vol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
int ret;
|
||||||
|
|
||||||
ar_param.activeremote = activeremote;
|
vol_param.spk_id = id;
|
||||||
ar_param.value = value;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ enum player_seek_mode {
|
|||||||
|
|
||||||
struct player_speaker_info {
|
struct player_speaker_info {
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
uint32_t active_remote;
|
||||||
char name[255];
|
char name[255];
|
||||||
char output_type[50];
|
char output_type[50];
|
||||||
int relvol;
|
int relvol;
|
||||||
@ -92,6 +93,9 @@ player_speaker_set(uint64_t *ids);
|
|||||||
int
|
int
|
||||||
player_speaker_get_byid(uint64_t id, struct player_speaker_info *spk);
|
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
|
int
|
||||||
player_speaker_enable(uint64_t id);
|
player_speaker_enable(uint64_t id);
|
||||||
|
|
||||||
@ -132,7 +136,7 @@ int
|
|||||||
player_volume_setabs_speaker(uint64_t id, int vol);
|
player_volume_setabs_speaker(uint64_t id, int vol);
|
||||||
|
|
||||||
int
|
int
|
||||||
player_volume_byactiveremote(uint32_t activeremote, const char *value);
|
player_volume_update_speaker(uint64_t id, const char *value);
|
||||||
|
|
||||||
int
|
int
|
||||||
player_repeat_set(enum repeat_mode mode);
|
player_repeat_set(enum repeat_mode mode);
|
||||||
|
Loading…
Reference in New Issue
Block a user