[pulseaudio] Misc improvements
- Set volume on stream startup - Change cleanup on server exit - README update
This commit is contained in:
parent
8b842b18d5
commit
9bd2ef4f42
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue