diff options
Diffstat (limited to 'src/modules/alsa/alsa-sink.c')
| -rw-r--r-- | src/modules/alsa/alsa-sink.c | 65 | 
1 files changed, 37 insertions, 28 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index dbd95b63..7bf16c3c 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -6,7 +6,7 @@    PulseAudio is free software; you can redistribute it and/or modify    it under the terms of the GNU Lesser General Public License as published -  by the Free Software Foundation; either version 2 of the License, +  by the Free Software Foundation; either version 2.1 of the License,    or (at your option) any later version.    PulseAudio is distributed in the hope that it will be useful, but @@ -61,10 +61,11 @@  /* #define DEBUG_TIMING */  #define DEFAULT_DEVICE "default" -#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC)            /* 2s */ -#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC)       /* 20ms */ -#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC)               /* 10ms */ -#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC)               /* 4ms */ +#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC)            /* 2s   -- Overall buffer size */ +#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC)       /* 20ms -- Fill up when only this much is left in the buffer */ +#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC)          /* 10ms -- On underrun, increase watermark by this */ +#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC)               /* 10ms -- Sleep at least 10ms on each iteration */ +#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC)               /* 4ms  -- Wakeup at least this long before the buffer runs empty*/  struct userdata {      pa_core *core; @@ -86,7 +87,16 @@ struct userdata {      pa_bool_t mixer_seperate_channels:1;      pa_cvolume hardware_volume; -    size_t frame_size, fragment_size, hwbuf_size, tsched_watermark, hwbuf_unused, min_sleep, min_wakeup; +    size_t +        frame_size, +        fragment_size, +        hwbuf_size, +        tsched_watermark, +        hwbuf_unused, +        min_sleep, +        min_wakeup, +        watermark_step; +      unsigned nfragments;      pa_memchunk memchunk; @@ -138,7 +148,7 @@ static void reserve_update(struct userdata *u) {      const char *description;      pa_assert(u); -    if (!u->sink) +    if (!u->sink || !u->reserve)          return;      if ((description = pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION))) @@ -154,6 +164,9 @@ static int reserve_init(struct userdata *u, const char *dname) {      if (u->reserve)          return 0; +    if (pa_in_system_mode()) +        return 0; +      /* We are resuming, try to lock the device */      if (!(rname = pa_alsa_get_reserve_name(dname)))          return 0; @@ -205,10 +218,11 @@ static void adjust_after_underrun(struct userdata *u) {      pa_usec_t old_min_latency, new_min_latency;      pa_assert(u); +    pa_assert(u->use_tsched);      /* First, just try to increase the watermark */      old_watermark = u->tsched_watermark; -    u->tsched_watermark *= 2; +    u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_step);      fix_tsched_watermark(u);      if (old_watermark != u->tsched_watermark) { @@ -219,7 +233,8 @@ static void adjust_after_underrun(struct userdata *u) {      /* Hmm, we cannot increase the watermark any further, hence let's raise the latency */      old_min_latency = u->sink->thread_info.min_latency; -    new_min_latency = PA_MIN(old_min_latency * 2, u->sink->thread_info.max_latency); +    new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_STEP_USEC); +    new_min_latency = PA_MIN(new_min_latency, u->sink->thread_info.max_latency);      if (old_min_latency != new_min_latency) {          pa_log_notice("Increasing minimal latency to %0.2f ms", @@ -1175,17 +1190,11 @@ static int process_rewind(struct userdata *u) {      /* Figure out how much we shall rewind and reset the counter */      rewind_nbytes = u->sink->thread_info.rewind_nbytes; -    u->sink->thread_info.rewind_nbytes = 0; -    if (rewind_nbytes <= 0) -        goto finish; - -    pa_assert(rewind_nbytes > 0);      pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes); -    snd_pcm_hwsync(u->pcm_handle); -    if ((unused = snd_pcm_avail_update(u->pcm_handle)) < 0) { -        pa_log("snd_pcm_avail_update() failed: %s", snd_strerror((int) unused)); +    if (PA_UNLIKELY((unused = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) { +        pa_log("snd_pcm_avail() failed: %s", snd_strerror((int) unused));          return -1;      } @@ -1227,12 +1236,8 @@ static int process_rewind(struct userdata *u) {      } else          pa_log_debug("Mhmm, actually there is nothing to rewind."); -finish: -      pa_sink_process_rewind(u->sink, 0); -      return 0; -  }  static void thread_func(void *userdata) { @@ -1261,7 +1266,7 @@ static void thread_func(void *userdata) {              int work_done;              pa_usec_t sleep_usec = 0; -            if (u->sink->thread_info.rewind_requested) +            if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))                  if (process_rewind(u) < 0)                          goto fail; @@ -1484,7 +1489,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca      struct userdata *u = NULL;      const char *dev_id = NULL; -    pa_sample_spec ss; +    pa_sample_spec ss, requested_ss;      pa_channel_map map;      uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark;      snd_pcm_uframes_t period_frames, tsched_frames; @@ -1503,6 +1508,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca          goto fail;      } +    requested_ss = ss;      frame_size = pa_frame_size(&ss);      nfrags = m->core->default_n_fragments; @@ -1654,6 +1660,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca          pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, profile->description);      } +    pa_alsa_init_description(data.proplist); +      u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);      pa_sink_new_data_done(&data); @@ -1674,19 +1682,20 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca      u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);      u->nfragments = nfrags;      u->hwbuf_size = u->fragment_size * nfrags; -    u->tsched_watermark = tsched_watermark; +    u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->sink->sample_spec);      pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);      if (use_tsched) {          fix_min_sleep_wakeup(u);          fix_tsched_watermark(u); -    } -    u->sink->thread_info.max_rewind = use_tsched ? u->hwbuf_size : 0; -    u->sink->thread_info.max_request = u->hwbuf_size; +        u->watermark_step = pa_usec_to_bytes(TSCHED_WATERMARK_STEP_USEC, &u->sink->sample_spec); +    } +    pa_sink_set_max_rewind(u->sink, use_tsched ? u->hwbuf_size : 0); +    pa_sink_set_max_request(u->sink, u->hwbuf_size);      pa_sink_set_latency_range(u->sink, -                              !use_tsched ? pa_bytes_to_usec(u->hwbuf_size, &ss) : (pa_usec_t) -1, +                              use_tsched ? (pa_usec_t) -1 : pa_bytes_to_usec(u->hwbuf_size, &ss),                                pa_bytes_to_usec(u->hwbuf_size, &ss));      pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",  | 
