[Pulseaudio] Implement flush, avoid adding known sinks and misc fixing up

This commit is contained in:
ejurgensen 2016-08-24 23:06:25 +02:00
parent 9b243f855a
commit 84a5772439
1 changed files with 70 additions and 48 deletions

View File

@ -40,6 +40,8 @@
#include "outputs.h" #include "outputs.h"
#include "commands.h" #include "commands.h"
#define PULSE_MAX_DEVICES 64
struct pulse struct pulse
{ {
pa_threaded_mainloop *mainloop; pa_threaded_mainloop *mainloop;
@ -69,11 +71,6 @@ struct pulse_session
struct pulse_session *next; struct pulse_session *next;
}; };
union pulse_arg
{
struct pulse_session *ps;
};
// From player.c // From player.c
extern struct event_base *evbase_player; extern struct event_base *evbase_player;
@ -81,6 +78,9 @@ extern struct event_base *evbase_player;
static struct pulse pulse; static struct pulse pulse;
static struct pulse_session *sessions; static struct pulse_session *sessions;
// Internal list with indeces of the Pulseaudio devices (sinks) we have registered
static uint32_t pulse_known_devices[PULSE_MAX_DEVICES];
/* Forwards */ /* Forwards */
static void static void
defer_cb(int fd, short what, void *arg); defer_cb(int fd, short what, void *arg);
@ -212,18 +212,6 @@ pulse_status(struct pulse_session *ps)
ps->status_cb = NULL; ps->status_cb = NULL;
} }
// Callbacks from the Pulseaudio thread will invoke commands_async_exec(),
// which will trigger a status update in the player thread
static enum command_state
pulse_status_cmd_wrapper(void *arg, int *ret)
{
union pulse_arg *cmdarg = arg;
pulse_status(cmdarg->ps);
return COMMAND_END;
}
/* --------------------- CALLBACKS FROM PULSEAUDIO THREAD ------------------- */ /* --------------------- CALLBACKS FROM PULSEAUDIO THREAD ------------------- */
@ -232,16 +220,11 @@ stream_state_cb(pa_stream *s, void * userdata)
{ {
struct pulse *p = &pulse; struct pulse *p = &pulse;
struct pulse_session *ps = userdata; struct pulse_session *ps = userdata;
union pulse_arg *cmdarg;
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio stream state CB\n"); DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio stream state CB\n");
ps->state = pa_stream_get_state(s); ps->state = pa_stream_get_state(s);
cmdarg = calloc(1, sizeof(union pulse_arg));
cmdarg->ps = ps;
commands_exec_async(p->cmdbase, pulse_status_cmd_wrapper, cmdarg);
switch (ps->state) switch (ps->state)
{ {
case PA_STREAM_READY: case PA_STREAM_READY:
@ -283,15 +266,33 @@ success_cb(pa_stream *s, int success, void *userdata)
*/ */
static void static void
sinklist_cb(pa_context *ctx, const pa_sink_info *i, int eol, void *userdata) sinklist_cb(pa_context *ctx, const pa_sink_info *info, int eol, void *userdata)
{ {
struct output_device *device; struct output_device *device;
const char *name; const char *name;
int i;
int pos;
if (eol > 0) if (eol > 0)
return; return;
DPRINTF(E_DBG, L_LAUDIO, "Callback for Pulseaudio sink '%s' (id %" PRIu32 ")\n", i->name, i->index); DPRINTF(E_DBG, L_LAUDIO, "Callback for Pulseaudio sink '%s' (id %" PRIu32 ")\n", info->name, info->index);
pos = -1;
for (i = 0; i < PULSE_MAX_DEVICES; i++)
{
if (pulse_known_devices[i] == (info->index + 1))
return;
if (pulse_known_devices[i] == 0)
pos = i;
}
if (pos == -1)
{
DPRINTF(E_LOG, L_LAUDIO, "Maximum number of Pulseaudio devices reached (%d), cannot add '%s'\n", PULSE_MAX_DEVICES, info->name);
return;
}
device = calloc(1, sizeof(struct output_device)); device = calloc(1, sizeof(struct output_device));
if (!device) if (!device)
@ -300,25 +301,27 @@ sinklist_cb(pa_context *ctx, const pa_sink_info *i, int eol, void *userdata)
return; return;
} }
if (i->index == 0) if (info->index == 0)
{ {
name = cfg_getstr(cfg_getsec(cfg, "audio"), "nickname"); name = cfg_getstr(cfg_getsec(cfg, "audio"), "nickname");
DPRINTF(E_LOG, L_LAUDIO, "Adding Pulseaudio sink '%s' (%s) with name '%s'\n", i->description, i->name, name); DPRINTF(E_LOG, L_LAUDIO, "Adding Pulseaudio sink '%s' (%s) with name '%s'\n", info->description, info->name, name);
} }
else else
{ {
name = i->description; name = info->description;
DPRINTF(E_LOG, L_LAUDIO, "Adding Pulseaudio sink '%s' (%s)\n", i->description, i->name); DPRINTF(E_LOG, L_LAUDIO, "Adding Pulseaudio sink '%s' (%s)\n", info->description, info->name);
} }
device->id = i->index; pulse_known_devices[pos] = info->index + 1; // Array values of 0 mean no device, so we add 1 to make sure the value is > 0
device->id = info->index;
device->name = strdup(name); device->name = strdup(name);
device->type = OUTPUT_TYPE_PULSE; device->type = OUTPUT_TYPE_PULSE;
device->type_name = outputs_name(device->type); device->type_name = outputs_name(device->type);
device->advertised = 1; device->advertised = 1;
device->extra_device_info = strdup(i->name); device->extra_device_info = strdup(info->name);
player_device_add(device); player_device_add(device);
} }
@ -328,6 +331,7 @@ subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void
{ {
struct output_device *device; struct output_device *device;
pa_operation *o; pa_operation *o;
int i;
DPRINTF(E_DBG, L_LAUDIO, "Callback for Pulseaudio subscribe (id %" PRIu32 ", event %d)\n", index, t); DPRINTF(E_DBG, L_LAUDIO, "Callback for Pulseaudio subscribe (id %" PRIu32 ", event %d)\n", index, t);
@ -350,6 +354,12 @@ subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void
DPRINTF(E_LOG, L_LAUDIO, "Removing Pulseaudio sink with id %" PRIu32 "\n", index); DPRINTF(E_LOG, L_LAUDIO, "Removing Pulseaudio sink with id %" PRIu32 "\n", index);
for (i = 0; i < PULSE_MAX_DEVICES; i++)
{
if (pulse_known_devices[i] == index)
pulse_known_devices[i] = 0;
}
player_device_remove(device); player_device_remove(device);
return; return;
} }
@ -566,6 +576,8 @@ pulse_device_start(struct output_device *device, output_status_cb cb, uint64_t r
struct pulse_session *ps; struct pulse_session *ps;
int ret; int ret;
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio start\n");
ps = pulse_session_make(device, cb); ps = pulse_session_make(device, cb);
if (!ps) if (!ps)
return -1; return -1;
@ -584,6 +596,8 @@ pulse_device_stop(struct output_session *session)
{ {
struct pulse_session *ps = session->session; struct pulse_session *ps = session->session;
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio stop\n");
stream_close(&pulse, ps); stream_close(&pulse, ps);
pulse_status(ps); pulse_status(ps);
@ -595,6 +609,8 @@ pulse_device_probe(struct output_device *device, output_status_cb cb)
struct pulse_session *ps; struct pulse_session *ps;
int ret; int ret;
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio probe\n");
ps = pulse_session_make(device, cb); ps = pulse_session_make(device, cb);
if (!ps) if (!ps)
return -1; return -1;
@ -660,20 +676,6 @@ pulse_device_volume_set(struct output_device *device, output_status_cb cb)
return 1; return 1;
} }
static void
pulse_playback_start(uint64_t next_pkt, struct timespec *ts)
{
if (!sessions)
return;
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio playback start called\n");
}
static void
pulse_playback_stop(void)
{
}
static void static void
pulse_write(uint8_t *buf, uint64_t rtptime) pulse_write(uint8_t *buf, uint64_t rtptime)
{ {
@ -736,9 +738,31 @@ pulse_write(uint8_t *buf, uint64_t rtptime)
static int static int
pulse_flush(output_status_cb cb, uint64_t rtptime) pulse_flush(output_status_cb cb, uint64_t rtptime)
{ {
DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio flush called\n"); struct pulse *p = &pulse;
struct pulse_session *ps;
pa_operation* o;
int i;
return 0; DPRINTF(E_DBG, L_LAUDIO, "Pulseaudio flush\n");
pa_threaded_mainloop_lock(p->mainloop);
i = 0;
for (ps = sessions; ps; ps = ps->next)
{
i++;
o = pa_stream_flush(ps->stream, NULL, NULL);
if (o)
{
ps->status_cb = cb;
pulse_status(ps);
}
}
pa_threaded_mainloop_unlock(p->mainloop);
return i;
} }
static void static void
@ -841,8 +865,6 @@ struct output_definition output_pulse =
.device_probe = pulse_device_probe, .device_probe = pulse_device_probe,
.device_free_extra = pulse_device_free_extra, .device_free_extra = pulse_device_free_extra,
.device_volume_set = pulse_device_volume_set, .device_volume_set = pulse_device_volume_set,
.playback_start = pulse_playback_start,
.playback_stop = pulse_playback_stop,
.write = pulse_write, .write = pulse_write,
.flush = pulse_flush, .flush = pulse_flush,
.status_cb = pulse_set_status_cb, .status_cb = pulse_set_status_cb,