[pulseaudio] Misc improvements

- Set volume on stream startup
- Change cleanup on server exit
- README update
This commit is contained in:
ejurgensen 2016-10-07 22:35:04 +02:00
parent 8b842b18d5
commit 9bd2ef4f42
2 changed files with 27 additions and 20 deletions

View File

@ -235,6 +235,8 @@ Note that if you select Pulseaudio the "card" setting in the config file has
no effect. Instead all soundcards detected by Pulseaudio will be listed as no effect. Instead all soundcards detected by Pulseaudio will be listed as
speakers by forked-daapd. speakers by forked-daapd.
You can adjust the latency of Pulseaudio playback in the config file.
## MP3 network streaming (streaming to iOS) ## MP3 network streaming (streaming to iOS)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016 Espen Jürgensen <espenjurgensen@gmail.com> * Copyright (C) 2016- Espen Jürgensen <espenjurgensen@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,8 +42,8 @@
#define PULSE_LOG_MAX 10 #define PULSE_LOG_MAX 10
/* TODO for Pulseaudio /* TODO for Pulseaudio
- Get volume from Pulseaudio on startup and on callbacks - Add real sync with AirPlay
- Add sync with AirPlay with pa_buffer_attr - Allow per-sink latency config
*/ */
struct pulse struct pulse
@ -62,11 +62,11 @@ struct pulse_session
pa_stream *stream; pa_stream *stream;
pa_buffer_attr attr; pa_buffer_attr attr;
pa_volume_t volume;
int logcount; int logcount;
char *devname; char *devname;
int volume;
/* Do not dereference - only passed to the status cb */ /* Do not dereference - only passed to the status cb */
struct output_device *device; struct output_device *device;
@ -85,6 +85,13 @@ static struct pulse_session *sessions;
// Internal list with indeces of the Pulseaudio devices (sinks) we have registered // Internal list with indeces of the Pulseaudio devices (sinks) we have registered
static uint32_t pulse_known_devices[PULSE_MAX_DEVICES]; static uint32_t pulse_known_devices[PULSE_MAX_DEVICES];
// Converts from 0 - 100 to Pulseaudio's scale
static inline pa_volume_t
pulse_from_device_volume(int device_volume)
{
return (PA_VOLUME_MUTED + (device_volume * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 100);
}
/* ---------------------------- SESSION HANDLING ---------------------------- */ /* ---------------------------- SESSION HANDLING ---------------------------- */
static void static void
@ -153,7 +160,7 @@ pulse_session_make(struct output_device *device, output_status_cb cb)
ps->state = PA_STREAM_UNCONNECTED; ps->state = PA_STREAM_UNCONNECTED;
ps->device = device; ps->device = device;
ps->status_cb = cb; ps->status_cb = cb;
ps->volume = device->volume; ps->volume = pulse_from_device_volume(device->volume);
ps->devname = strdup(device->extra_device_info); ps->devname = strdup(device->extra_device_info);
ps->next = sessions; ps->next = sessions;
@ -228,8 +235,6 @@ pulse_session_shutdown(struct pulse_session *ps)
commands_exec_async(pulse.cmdbase, session_shutdown, ps); commands_exec_async(pulse.cmdbase, session_shutdown, ps);
} }
/* ------------------------ EXECUTED IN BOTH THREADS ------------------------ */
static void static void
pulse_session_shutdown_all(pa_stream_state_t state) pulse_session_shutdown_all(pa_stream_state_t state)
{ {
@ -514,14 +519,14 @@ context_state_cb(pa_context *c, void *userdata)
break; break;
case PA_CONTEXT_FAILED: case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED: DPRINTF(E_LOG, L_LAUDIO, "Pulseaudio failed with error: %s\n", pa_strerror(pa_context_errno(c)));
if (state == PA_CONTEXT_FAILED)
DPRINTF(E_LOG, L_LAUDIO, "Pulseaudio failed with error: %s\n", pa_strerror(pa_context_errno(c)));
else
DPRINTF(E_LOG, L_LAUDIO, "Pulseaudio terminated\n");
pulse_session_shutdown_all(PA_STREAM_FAILED); pulse_session_shutdown_all(PA_STREAM_FAILED);
pa_threaded_mainloop_signal(pulse.mainloop, 0);
break;
case PA_CONTEXT_TERMINATED:
DPRINTF(E_LOG, L_LAUDIO, "Pulseaudio terminated\n");
pulse_session_shutdown_all(PA_STREAM_UNCONNECTED);
pa_threaded_mainloop_signal(pulse.mainloop, 0); pa_threaded_mainloop_signal(pulse.mainloop, 0);
break; break;
@ -561,6 +566,7 @@ stream_open(struct pulse_session *ps, pa_stream_notify_cb_t cb)
{ {
pa_stream_flags_t flags; pa_stream_flags_t flags;
pa_sample_spec ss; pa_sample_spec ss;
pa_cvolume cvol;
int offset; int offset;
int ret; int ret;
@ -592,7 +598,9 @@ stream_open(struct pulse_session *ps, pa_stream_notify_cb_t cb)
ps->attr.minreq = (uint32_t)-1; ps->attr.minreq = (uint32_t)-1;
ps->attr.fragsize = (uint32_t)-1; ps->attr.fragsize = (uint32_t)-1;
ret = pa_stream_connect_playback(ps->stream, ps->devname, &ps->attr, flags, NULL, NULL); pa_cvolume_set(&cvol, 2, ps->volume);
ret = pa_stream_connect_playback(ps->stream, ps->devname, &ps->attr, flags, &cvol, NULL);
if (ret < 0) if (ret < 0)
goto unlock_and_fail; goto unlock_and_fail;
@ -701,7 +709,6 @@ pulse_device_volume_set(struct output_device *device, output_status_cb cb)
uint32_t idx; uint32_t idx;
pa_operation* o; pa_operation* o;
pa_cvolume cvol; pa_cvolume cvol;
pa_volume_t vol;
if (!sessions || !device->session || !device->session->session) if (!sessions || !device->session || !device->session->session)
return 0; return 0;
@ -709,10 +716,10 @@ pulse_device_volume_set(struct output_device *device, output_status_cb cb)
ps = device->session->session; ps = device->session->session;
idx = pa_stream_get_index(ps->stream); idx = pa_stream_get_index(ps->stream);
vol = PA_VOLUME_MUTED + (device->volume * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 100; ps->volume = pulse_from_device_volume(device->volume);
pa_cvolume_set(&cvol, 2, vol); pa_cvolume_set(&cvol, 2, ps->volume);
DPRINTF(E_DBG, L_LAUDIO, "Setting Pulseaudio volume for stream %" PRIu32 " to %d (%d)\n", idx, (int)vol, device->volume); DPRINTF(E_DBG, L_LAUDIO, "Setting Pulseaudio volume for stream %" PRIu32 " to %d (%d)\n", idx, (int)ps->volume, device->volume);
pa_threaded_mainloop_lock(pulse.mainloop); pa_threaded_mainloop_lock(pulse.mainloop);
@ -944,8 +951,6 @@ pulse_init(void)
static void static void
pulse_deinit(void) pulse_deinit(void)
{ {
pulse_session_shutdown_all(PA_STREAM_UNCONNECTED); // TODO Required?
pulse_free(); pulse_free();
} }