mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-24 12:30:38 -04:00
[alsa] Let the user configure an offset to sync audio if required
This commit is contained in:
parent
e23fed4ac4
commit
ad01d65047
4
INSTALL
4
INSTALL
@ -136,8 +136,8 @@ Libraries:
|
|||||||
from <http://zlib.net/>
|
from <http://zlib.net/>
|
||||||
- libunistring 0.9.3+
|
- libunistring 0.9.3+
|
||||||
from <http://www.gnu.org/software/libunistring/#downloading>
|
from <http://www.gnu.org/software/libunistring/#downloading>
|
||||||
- libasound (optional - ALSA support, recommended for Linux)
|
- libasound (optional - local audio)
|
||||||
normally already installed as part of your distro
|
often already installed as part of your distro
|
||||||
- libplist 0.16+ (optional - iTunes XML support)
|
- libplist 0.16+ (optional - iTunes XML support)
|
||||||
from <http://github.com/JonathanBeck/libplist/downloads>
|
from <http://github.com/JonathanBeck/libplist/downloads>
|
||||||
- libspotify (optional - Spotify support)
|
- libspotify (optional - Spotify support)
|
||||||
|
@ -153,7 +153,7 @@ audio {
|
|||||||
# Name - used in the speaker list in Remote
|
# Name - used in the speaker list in Remote
|
||||||
nickname = "Computer"
|
nickname = "Computer"
|
||||||
|
|
||||||
# Type of the output (alsa, oss4, dummy)
|
# Type of the output (alsa or dummy)
|
||||||
# type = "alsa"
|
# type = "alsa"
|
||||||
|
|
||||||
# Audio device name for local audio output
|
# Audio device name for local audio output
|
||||||
@ -162,6 +162,12 @@ audio {
|
|||||||
# Mixer channel to use for volume control - ALSA/Linux only
|
# Mixer channel to use for volume control - ALSA/Linux only
|
||||||
# If not set, PCM will be used if available, otherwise Master.
|
# If not set, PCM will be used if available, otherwise Master.
|
||||||
# mixer = ""
|
# mixer = ""
|
||||||
|
|
||||||
|
# If your local audio is out of sync with AirPlay, you can adjust this
|
||||||
|
# value. Positive values correspond to moving local audio ahead,
|
||||||
|
# negative correspond to delaying it. The unit is samples, where is
|
||||||
|
# 44100 = 1 second. The offset must be between -44100 and 44100.
|
||||||
|
# offset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# AirPlay/Airport Express device settings
|
# AirPlay/Airport Express device settings
|
||||||
|
@ -94,12 +94,9 @@ static cfg_opt_t sec_audio[] =
|
|||||||
{
|
{
|
||||||
CFG_STR("nickname", "Computer", CFGF_NONE),
|
CFG_STR("nickname", "Computer", CFGF_NONE),
|
||||||
CFG_STR("type", NULL, CFGF_NONE),
|
CFG_STR("type", NULL, CFGF_NONE),
|
||||||
#ifdef __linux__
|
|
||||||
CFG_STR("card", "default", CFGF_NONE),
|
CFG_STR("card", "default", CFGF_NONE),
|
||||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
||||||
CFG_STR("card", "/dev/dsp", CFGF_NONE),
|
|
||||||
#endif
|
|
||||||
CFG_STR("mixer", NULL, CFGF_NONE),
|
CFG_STR("mixer", NULL, CFGF_NONE),
|
||||||
|
CFG_INT("offset", 0, CFGF_NONE),
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ static snd_mixer_t *mixer_hdl;
|
|||||||
static snd_mixer_elem_t *vol_elem;
|
static snd_mixer_elem_t *vol_elem;
|
||||||
static long vol_min;
|
static long vol_min;
|
||||||
static long vol_max;
|
static long vol_max;
|
||||||
|
static int offset;
|
||||||
|
|
||||||
#define ALSA_F_STARTED (1 << 15)
|
#define ALSA_F_STARTED (1 << 15)
|
||||||
|
|
||||||
@ -552,13 +553,16 @@ playback_start(struct alsa_session *as, uint64_t pos, uint64_t start_pos)
|
|||||||
// Clear prebuffer in case start somehow got called twice without a stop in between
|
// Clear prebuffer in case start somehow got called twice without a stop in between
|
||||||
prebuf_free(as);
|
prebuf_free(as);
|
||||||
|
|
||||||
|
// Adjust the starting position with the configured value
|
||||||
|
start_pos -= offset;
|
||||||
|
|
||||||
// The difference between pos and start_pos should match the 2 second
|
// The difference between pos and start_pos should match the 2 second
|
||||||
// buffer that AirPlay uses. We will not use alsa's buffer for the initial
|
// buffer that AirPlay uses. We will not use alsa's buffer for the initial
|
||||||
// buffering, because my sound card's start_threshold is not to be counted on.
|
// buffering, because my sound card's start_threshold is not to be counted on.
|
||||||
// Instead we allocate our own buffer, and when it is time to play we write as
|
// Instead we allocate our own buffer, and when it is time to play we write as
|
||||||
// much as we can to alsa's buffer.
|
// much as we can to alsa's buffer.
|
||||||
as->prebuf_len = (start_pos - pos) / AIRTUNES_V2_PACKET_SAMPLES + 1;
|
as->prebuf_len = (start_pos - pos) / AIRTUNES_V2_PACKET_SAMPLES + 1;
|
||||||
if (as->prebuf_len > 2*126)
|
if (as->prebuf_len > (3 * 44100 - offset) / AIRTUNES_V2_PACKET_SAMPLES)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_LAUDIO, "Sanity check of prebuf_len (%" PRIu32 " packets) failed\n", as->prebuf_len);
|
DPRINTF(E_LOG, L_LAUDIO, "Sanity check of prebuf_len (%" PRIu32 " packets) failed\n", as->prebuf_len);
|
||||||
return;
|
return;
|
||||||
@ -669,7 +673,7 @@ sync_check(struct alsa_session *as, uint64_t rtptime, snd_pcm_sframes_t delay, i
|
|||||||
npackets = 0;
|
npackets = 0;
|
||||||
|
|
||||||
pb_pos = rtptime - delay - AIRTUNES_V2_PACKET_SAMPLES * npackets;
|
pb_pos = rtptime - delay - AIRTUNES_V2_PACKET_SAMPLES * npackets;
|
||||||
latency = cur_pos - pb_pos;
|
latency = cur_pos - (pb_pos - offset);
|
||||||
|
|
||||||
// If the latency is low or very different from our last measurement, we reset the sync_counter
|
// If the latency is low or very different from our last measurement, we reset the sync_counter
|
||||||
if (abs(latency) < ALSA_MAX_LATENCY || abs(as->last_latency - latency) > ALSA_MAX_LATENCY_VARIANCE)
|
if (abs(latency) < ALSA_MAX_LATENCY || abs(as->last_latency - latency) > ALSA_MAX_LATENCY_VARIANCE)
|
||||||
@ -692,7 +696,7 @@ sync_check(struct alsa_session *as, uint64_t rtptime, snd_pcm_sframes_t delay, i
|
|||||||
as->last_latency = latency;
|
as->last_latency = latency;
|
||||||
|
|
||||||
if (latency)
|
if (latency)
|
||||||
DPRINTF(E_DBG, L_LAUDIO, "Sync %d cur_pos %" PRIu64 ", pb_pos %" PRIu64 " (diff %d, delay %li), pos %" PRIu64 "\n", sync, cur_pos, pb_pos, latency, delay, as->pos);
|
DPRINTF(E_SPAM, L_LAUDIO, "Sync %d cur_pos %" PRIu64 ", pb_pos %" PRIu64 " (diff %d, delay %li), pos %" PRIu64 "\n", sync, cur_pos, pb_pos, latency, delay, as->pos);
|
||||||
|
|
||||||
return sync;
|
return sync;
|
||||||
}
|
}
|
||||||
@ -987,6 +991,12 @@ alsa_init(void)
|
|||||||
card_name = cfg_getstr(cfg_audio, "card");
|
card_name = cfg_getstr(cfg_audio, "card");
|
||||||
mixer_name = cfg_getstr(cfg_audio, "mixer");
|
mixer_name = cfg_getstr(cfg_audio, "mixer");
|
||||||
nickname = cfg_getstr(cfg_audio, "nickname");
|
nickname = cfg_getstr(cfg_audio, "nickname");
|
||||||
|
offset = cfg_getint(cfg_audio, "offset");
|
||||||
|
if (abs(offset) > 44100)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_LAUDIO, "The ALSA offset (%d) set in the configuration is out of bounds\n", offset);
|
||||||
|
offset = 44100 * (offset/abs(offset));
|
||||||
|
}
|
||||||
|
|
||||||
device = calloc(1, sizeof(struct output_device));
|
device = calloc(1, sizeof(struct output_device));
|
||||||
if (!device)
|
if (!device)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user