[mpd] Fix outputs enable/disable/toggle not working in v28.10
Also simplify code by using new speaker index from player and remove some code duplication. Regression from PR #1779. Fixes #1814.
This commit is contained in:
parent
a983302b03
commit
17ef308489
194
src/mpd.c
194
src/mpd.c
|
@ -208,29 +208,12 @@ struct mpd_command
|
||||||
int wants_num;
|
int wants_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output
|
struct param_output
|
||||||
{
|
{
|
||||||
unsigned short shortid;
|
struct evbuffer *evbuf;
|
||||||
uint64_t id;
|
uint32_t last_shortid;
|
||||||
char *name;
|
|
||||||
|
|
||||||
unsigned selected;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_get_param
|
|
||||||
{
|
|
||||||
unsigned short curid;
|
|
||||||
unsigned short shortid;
|
|
||||||
struct output *output;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct output_outputs_param
|
|
||||||
{
|
|
||||||
unsigned short nextid;
|
|
||||||
struct evbuffer *buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------- Globals ------------------------------- */
|
/* ---------------------------------- Globals ------------------------------- */
|
||||||
|
|
||||||
static pthread_t tid_mpd;
|
static pthread_t tid_mpd;
|
||||||
|
@ -240,6 +223,7 @@ static struct evhttp *evhttpd;
|
||||||
static struct evconnlistener *mpd_listener;
|
static struct evconnlistener *mpd_listener;
|
||||||
static int mpd_sockfd;
|
static int mpd_sockfd;
|
||||||
static bool mpd_plugin_httpd;
|
static bool mpd_plugin_httpd;
|
||||||
|
static int mpd_plugin_httpd_shortid = -1;
|
||||||
|
|
||||||
// Virtual path to the default playlist directory
|
// Virtual path to the default playlist directory
|
||||||
static char *default_pl_dir;
|
static char *default_pl_dir;
|
||||||
|
@ -382,16 +366,6 @@ client_ctx_add(void)
|
||||||
return client_ctx;
|
return client_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
free_output(struct output *output)
|
|
||||||
{
|
|
||||||
if (!output)
|
|
||||||
return;
|
|
||||||
|
|
||||||
free(output->name);
|
|
||||||
free(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a new string for the given path that starts with a '/'.
|
* Creates a new string for the given path that starts with a '/'.
|
||||||
* If 'path' already starts with a '/' the returned string is a duplicate
|
* If 'path' already starts with a '/' the returned string is a duplicate
|
||||||
|
@ -3100,107 +3074,30 @@ mpd_command_binarylimit(struct mpd_command_output *out, struct mpd_command_input
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Callback function for the 'player_speaker_enumerate' function.
|
* Command handler function for 'disableoutput', 'enableoutput', 'toggleoutput'
|
||||||
* Expect a struct output_get_param as argument and allocates a struct output if
|
* Expects argument argv[1] to be the id of the output.
|
||||||
* the shortid of output_get_param matches the given speaker/output spk.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
output_get_cb(struct player_speaker_info *spk, void *arg)
|
|
||||||
{
|
|
||||||
struct output_get_param *param = arg;
|
|
||||||
|
|
||||||
if (!param->output
|
|
||||||
&& param->shortid == param->curid)
|
|
||||||
{
|
|
||||||
CHECK_NULL(L_MPD, param->output = calloc(1, sizeof(struct output)));
|
|
||||||
|
|
||||||
param->output->id = spk->id;
|
|
||||||
param->output->shortid = param->shortid;
|
|
||||||
param->output->name = strdup(spk->name);
|
|
||||||
param->output->selected = spk->selected;
|
|
||||||
|
|
||||||
param->curid++;
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_MPD, "Output found: shortid %d, id %" PRIu64 ", name '%s', selected %d\n",
|
|
||||||
param->output->shortid, param->output->id, param->output->name, param->output->selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command handler function for 'disableoutput'
|
|
||||||
* Expects argument argv[1] to be the id of the speaker to disable.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mpd_command_disableoutput(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
mpd_command_xoutput(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
||||||
{
|
{
|
||||||
uint32_t num = in->argv_u32val[1];
|
const char *action = in->argv[0];
|
||||||
struct output_get_param param = { .shortid = num };
|
uint32_t shortid = in->argv_u32val[1];
|
||||||
|
struct player_speaker_info spk;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
player_speaker_enumerate(output_get_cb, ¶m);
|
if (shortid == mpd_plugin_httpd_shortid)
|
||||||
|
RETURN_ERROR(ACK_ERROR_ARG, "Output cannot be toggled");
|
||||||
|
|
||||||
if (param.output && param.output->selected)
|
ret = player_speaker_get_byindex(&spk, shortid);
|
||||||
{
|
if (ret < 0)
|
||||||
ret = player_speaker_disable(param.output->id);
|
RETURN_ERROR(ACK_ERROR_ARG, "Unknown output");
|
||||||
free_output(param.output);
|
|
||||||
|
|
||||||
if (ret < 0)
|
if ((spk.selected && strcasecmp(action, "enable") == 0) || (!spk.selected && strcasecmp(action, "disable") == 0))
|
||||||
RETURN_ERROR(ACK_ERROR_UNKNOWN, "Speakers deactivation failed: %d", num);
|
return 0; // Nothing to do
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
ret = spk.selected ? player_speaker_disable(spk.id) : player_speaker_enable(spk.id);
|
||||||
}
|
if (ret < 0)
|
||||||
|
RETURN_ERROR(ACK_ERROR_UNKNOWN, "Output error, see log");
|
||||||
/*
|
|
||||||
* Command handler function for 'enableoutput'
|
|
||||||
* Expects argument argv[1] to be the id of the speaker to enable.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
mpd_command_enableoutput(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
|
||||||
{
|
|
||||||
uint32_t num = in->argv_u32val[1];
|
|
||||||
struct output_get_param param = { .shortid = num };
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
player_speaker_enumerate(output_get_cb, ¶m);
|
|
||||||
|
|
||||||
if (param.output && !param.output->selected)
|
|
||||||
{
|
|
||||||
ret = player_speaker_enable(param.output->id);
|
|
||||||
free_output(param.output);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
RETURN_ERROR(ACK_ERROR_UNKNOWN, "Speakers deactivation failed: %d", num);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command handler function for 'toggleoutput'
|
|
||||||
* Expects argument argv[1] to be the id of the speaker to enable/disable.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
mpd_command_toggleoutput(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
|
||||||
{
|
|
||||||
uint32_t num = in->argv_u32val[1];
|
|
||||||
struct output_get_param param = { .shortid = num };
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
player_speaker_enumerate(output_get_cb, ¶m);
|
|
||||||
|
|
||||||
if (param.output)
|
|
||||||
{
|
|
||||||
if (param.output->selected)
|
|
||||||
ret = player_speaker_disable(param.output->id);
|
|
||||||
else
|
|
||||||
ret = player_speaker_enable(param.output->id);
|
|
||||||
|
|
||||||
free_output(param.output);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
RETURN_ERROR(ACK_ERROR_UNKNOWN, "Toggle speaker failed: %d", num);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3219,8 +3116,7 @@ mpd_command_toggleoutput(struct mpd_command_output *out, struct mpd_command_inpu
|
||||||
static void
|
static void
|
||||||
speaker_enum_cb(struct player_speaker_info *spk, void *arg)
|
speaker_enum_cb(struct player_speaker_info *spk, void *arg)
|
||||||
{
|
{
|
||||||
struct output_outputs_param *param = arg;
|
struct param_output *param = arg;
|
||||||
struct evbuffer *evbuf = param->buf;
|
|
||||||
char plugin[sizeof(spk->output_type)];
|
char plugin[sizeof(spk->output_type)];
|
||||||
char *p;
|
char *p;
|
||||||
char *q;
|
char *q;
|
||||||
|
@ -3235,16 +3131,17 @@ speaker_enum_cb(struct player_speaker_info *spk, void *arg)
|
||||||
}
|
}
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
|
|
||||||
evbuffer_add_printf(evbuf,
|
evbuffer_add_printf(param->evbuf,
|
||||||
"outputid: %u\n"
|
"outputid: %u\n"
|
||||||
"outputname: %s\n"
|
"outputname: %s\n"
|
||||||
"plugin: %s\n"
|
"plugin: %s\n"
|
||||||
"outputenabled: %d\n",
|
"outputenabled: %d\n",
|
||||||
param->nextid,
|
spk->index,
|
||||||
spk->name,
|
spk->name,
|
||||||
plugin,
|
plugin,
|
||||||
spk->selected);
|
spk->selected);
|
||||||
param->nextid++;
|
|
||||||
|
param->last_shortid = spk->index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3254,28 +3151,25 @@ speaker_enum_cb(struct player_speaker_info *spk, void *arg)
|
||||||
static int
|
static int
|
||||||
mpd_command_outputs(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
mpd_command_outputs(struct mpd_command_output *out, struct mpd_command_input *in, struct mpd_client_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct output_outputs_param param = { 0 };
|
struct param_output param = { .evbuf = out->evbuf, .last_shortid = -1 };
|
||||||
|
|
||||||
/* Reference:
|
/* Reference:
|
||||||
* https://mpd.readthedocs.io/en/latest/protocol.html#audio-output-devices
|
* https://mpd.readthedocs.io/en/latest/protocol.html#audio-output-devices
|
||||||
* the ID returned by mpd may change between excutions, so what we do
|
* the ID returned by mpd may change between excutions (!!), so what we do
|
||||||
* is simply enumerate the speakers, and for get/set commands we count
|
* is simply enumerate the speakers with the speaker index */
|
||||||
* ID times to the output referenced. */
|
|
||||||
param.buf = out->evbuf;
|
|
||||||
|
|
||||||
player_speaker_enumerate(speaker_enum_cb, ¶m);
|
player_speaker_enumerate(speaker_enum_cb, ¶m);
|
||||||
|
|
||||||
/* streaming output is not in the speaker list, so add it as pseudo
|
/* streaming output is not in the speaker list, so add it as pseudo
|
||||||
* element when configured to do so */
|
* element when configured to do so */
|
||||||
if (mpd_plugin_httpd)
|
if (mpd_plugin_httpd)
|
||||||
{
|
{
|
||||||
evbuffer_add_printf(out->evbuf,
|
mpd_plugin_httpd_shortid = param.last_shortid + 1;
|
||||||
"outputid: %u\n"
|
evbuffer_add_printf(param.evbuf,
|
||||||
"outputname: MP3 stream\n"
|
"outputid: %u\n"
|
||||||
"plugin: httpd\n"
|
"outputname: MP3 stream\n"
|
||||||
"outputenabled: 1\n",
|
"plugin: httpd\n"
|
||||||
param.nextid);
|
"outputenabled: 1\n",
|
||||||
param.nextid++;
|
mpd_plugin_httpd_shortid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3284,18 +3178,14 @@ mpd_command_outputs(struct mpd_command_output *out, struct mpd_command_input *in
|
||||||
static int
|
static int
|
||||||
outputvolume_set(uint32_t shortid, int volume)
|
outputvolume_set(uint32_t shortid, int volume)
|
||||||
{
|
{
|
||||||
struct output_get_param param = { .shortid = shortid };
|
struct player_speaker_info spk;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
player_speaker_enumerate(output_get_cb, ¶m);
|
ret = player_speaker_get_byindex(&spk, shortid);
|
||||||
|
if (ret < 0)
|
||||||
if (!param.output)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = player_volume_setabs_speaker(param.output->id, volume);
|
return player_volume_setabs_speaker(spk.id, volume);
|
||||||
|
|
||||||
free_output(param.output);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -3687,9 +3577,9 @@ static struct mpd_command mpd_handlers[] =
|
||||||
{ "binarylimit", mpd_command_binarylimit, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
{ "binarylimit", mpd_command_binarylimit, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
||||||
|
|
||||||
// Audio output devices
|
// Audio output devices
|
||||||
{ "disableoutput", mpd_command_disableoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
{ "disableoutput", mpd_command_xoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
||||||
{ "enableoutput", mpd_command_enableoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
{ "enableoutput", mpd_command_xoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
||||||
{ "toggleoutput", mpd_command_toggleoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
{ "toggleoutput", mpd_command_xoutput, 2, MPD_WANTS_NUM_ARG1_UVAL },
|
||||||
{ "outputs", mpd_command_outputs, -1 },
|
{ "outputs", mpd_command_outputs, -1 },
|
||||||
|
|
||||||
// Custom command outputvolume (not supported by mpd)
|
// Custom command outputvolume (not supported by mpd)
|
||||||
|
|
Loading…
Reference in New Issue