diff options
Diffstat (limited to 'src/modules')
29 files changed, 546 insertions, 267 deletions
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 61c92cd0..f3ce681f 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -479,7 +479,6 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann      snd_mixer_elem_t *me;      snd_mixer_selem_channel_id_t c;      pa_channel_position_mask_t mask = 0; -    pa_volume_t max_channel_volume = PA_VOLUME_MUTED;      unsigned k;      pa_assert(m); @@ -546,9 +545,6 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann              f = from_alsa_volume(value, e->min_volume, e->max_volume);          } -        if (f > max_channel_volume) -            max_channel_volume = f; -          for (k = 0; k < cm->channels; k++)              if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k]))                  if (v->values[k] < f) @@ -559,7 +555,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann      for (k = 0; k < cm->channels; k++)          if (!(mask & PA_CHANNEL_POSITION_MASK(cm->map[k]))) -            v->values[k] = max_channel_volume; +            v->values[k] = PA_VOLUME_NORM;      return 0;  } @@ -681,7 +677,6 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann      snd_mixer_elem_t *me;      snd_mixer_selem_channel_id_t c;      pa_channel_position_mask_t mask = 0; -    pa_volume_t max_channel_volume = PA_VOLUME_MUTED;      unsigned k;      pa_assert(m); @@ -771,9 +766,6 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann              f = from_alsa_volume(value, e->min_volume, e->max_volume);          } -        if (f > max_channel_volume) -            max_channel_volume = f; -          for (k = 0; k < cm->channels; k++)              if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k]))                  if (rv.values[k] < f) @@ -784,7 +776,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann      for (k = 0; k < cm->channels; k++)          if (!(mask & PA_CHANNEL_POSITION_MASK(cm->map[k]))) -            rv.values[k] = max_channel_volume; +            rv.values[k] = PA_VOLUME_NORM;      *v = rv;      return 0; @@ -1716,11 +1708,11 @@ static int option_verify(pa_alsa_option *o) {          { "input-radio",               N_("Radio") },          { "input-video",               N_("Video") },          { "input-agc-on",              N_("Automatic Gain Control") }, -        { "input-agc-off",             "" }, +        { "input-agc-off",             N_("No Automatic Gain Control") },          { "input-boost-on",            N_("Boost") }, -        { "input-boost-off",           "" }, +        { "input-boost-off",           N_("No Boost") },          { "output-amplifier-on",       N_("Amplifier") }, -        { "output-amplifier-off",      "" } +        { "output-amplifier-off",      N_("No Amplifier") }      };      pa_assert(o); @@ -2889,7 +2881,7 @@ static void profile_set_add_auto_pair(      else          name = pa_sprintf_malloc("input:%s", n->name); -    if ((p = pa_hashmap_get(ps->profiles, name))) { +    if (pa_hashmap_get(ps->profiles, name)) {          pa_xfree(name);          return;      } @@ -3145,7 +3137,13 @@ fail:      return NULL;  } -void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss) { +void pa_alsa_profile_set_probe( +        pa_alsa_profile_set *ps, +        const char *dev_id, +        const pa_sample_spec *ss, +        unsigned default_n_fragments, +        unsigned default_fragment_size_msec) { +      void *state;      pa_alsa_profile *p, *last = NULL;      pa_alsa_mapping *m; @@ -3160,6 +3158,7 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons      PA_HASHMAP_FOREACH(p, ps->profiles, state) {          pa_sample_spec try_ss;          pa_channel_map try_map; +        snd_pcm_uframes_t try_period_size, try_buffer_size;          uint32_t idx;          /* Is this already marked that it is supported? (i.e. from the config file) */ @@ -3213,13 +3212,18 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons                  try_ss = *ss;                  try_ss.channels = try_map.channels; +                try_period_size = +                    pa_usec_to_bytes(default_fragment_size_msec * PA_USEC_PER_MSEC, &try_ss) / +                    pa_frame_size(&try_ss); +                try_buffer_size = default_n_fragments * try_period_size; +                  if (!(m ->output_pcm = pa_alsa_open_by_template(                                m->device_strings,                                dev_id,                                NULL,                                &try_ss, &try_map,                                SND_PCM_STREAM_PLAYBACK, -                              NULL, NULL, 0, NULL, NULL, +                              &try_period_size, &try_buffer_size, 0, NULL, NULL,                                TRUE))) {                      p->supported = FALSE;                      break; @@ -3237,13 +3241,18 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons                  try_ss = *ss;                  try_ss.channels = try_map.channels; +                try_period_size = +                    pa_usec_to_bytes(default_fragment_size_msec*PA_USEC_PER_MSEC, &try_ss) / +                    pa_frame_size(&try_ss); +                try_buffer_size = default_n_fragments * try_period_size; +                  if (!(m ->input_pcm = pa_alsa_open_by_template(                                m->device_strings,                                dev_id,                                NULL,                                &try_ss, &try_map,                                SND_PCM_STREAM_CAPTURE, -                              NULL, NULL, 0, NULL, NULL, +                              &try_period_size, &try_buffer_size, 0, NULL, NULL,                                TRUE))) {                      p->supported = FALSE;                      break; diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 76788183..a0d4fcbe 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -269,7 +269,7 @@ void pa_alsa_mapping_dump(pa_alsa_mapping *m);  void pa_alsa_profile_dump(pa_alsa_profile *p);  pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus); -void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss); +void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);  void pa_alsa_profile_set_free(pa_alsa_profile_set *s);  void pa_alsa_profile_set_dump(pa_alsa_profile_set *s); diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 07d53880..22e88b4a 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -69,9 +69,12 @@  #define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC)       /* 10ms  -- On underrun, increase watermark by this */  #define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC)        /* 5ms   -- When everything's great, decrease watermark by this */  #define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC)    /* 20s   -- How long after a drop out recheck if things are good now */ -#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC)   /* 3ms   -- If the buffer level ever below this theshold, increase the watermark */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (0*PA_USEC_PER_MSEC)   /* 0ms   -- If the buffer level ever below this theshold, increase the watermark */  #define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms -- If the buffer level didn't drop below this theshold in the verification time, decrease the watermark */ +/* Note that TSCHED_WATERMARK_INC_THRESHOLD_USEC == 0 means tht we + * will increase the watermark only if we hit a real underrun. */ +  #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*/ @@ -113,7 +116,6 @@ struct userdata {      pa_usec_t watermark_dec_not_before; -    unsigned nfragments;      pa_memchunk memchunk;      char *device_name;  /* name of the PCM device */ @@ -410,6 +412,7 @@ static int try_recover(struct userdata *u, const char *call, int err) {  static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) {      size_t left_to_play; +    pa_bool_t underrun = FALSE;      /* We use <= instead of < for this check here because an underrun       * only happens after the last sample was processed, not already when @@ -422,6 +425,7 @@ static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t o          /* We got a dropout. What a mess! */          left_to_play = 0; +        underrun = TRUE;  #ifdef DEBUG_TIMING          PA_DEBUG_TRAP; @@ -443,7 +447,7 @@ static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t o          pa_bool_t reset_not_before = TRUE;          if (!u->first && !u->after_rewind) { -            if (left_to_play < u->watermark_inc_threshold) +            if (underrun || left_to_play < u->watermark_inc_threshold)                  increase_watermark(u);              else if (left_to_play > u->watermark_dec_threshold) {                  reset_not_before = FALSE; @@ -651,6 +655,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle          snd_pcm_sframes_t n;          size_t n_bytes;          int r; +        pa_bool_t after_avail = TRUE;          if (PA_UNLIKELY((n = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) { @@ -705,7 +710,6 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle          for (;;) {              snd_pcm_sframes_t frames;              void *p; -            pa_bool_t after_avail = TRUE;  /*         pa_log_debug("%lu frames to write", (unsigned long) frames); */ @@ -938,8 +942,7 @@ static int unsuspend(struct userdata *u) {      pa_sample_spec ss;      int err;      pa_bool_t b, d; -    unsigned nfrags; -    snd_pcm_uframes_t period_size; +    snd_pcm_uframes_t period_size, buffer_size;      pa_assert(u);      pa_assert(!u->pcm_handle); @@ -947,7 +950,7 @@ static int unsuspend(struct userdata *u) {      pa_log_info("Trying resume...");      if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK, -                            /*SND_PCM_NONBLOCK|*/ +                            SND_PCM_NONBLOCK|                              SND_PCM_NO_AUTO_RESAMPLE|                              SND_PCM_NO_AUTO_CHANNELS|                              SND_PCM_NO_AUTO_FORMAT)) < 0) { @@ -956,12 +959,12 @@ static int unsuspend(struct userdata *u) {      }      ss = u->sink->sample_spec; -    nfrags = u->nfragments;      period_size = u->fragment_size / u->frame_size; +    buffer_size = u->hwbuf_size / u->frame_size;      b = u->use_mmap;      d = u->use_tsched; -    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) { +    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) {          pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));          goto fail;      } @@ -976,10 +979,11 @@ static int unsuspend(struct userdata *u) {          goto fail;      } -    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { -        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)", -                    (unsigned long) u->nfragments, (unsigned long) u->fragment_size, -                    (unsigned long) nfrags, period_size * u->frame_size); +    if (period_size*u->frame_size != u->fragment_size || +        buffer_size*u->frame_size != u->hwbuf_size) { +        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", +                    (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, +                    (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size));          goto fail;      } @@ -1007,7 +1011,7 @@ fail:          u->pcm_handle = NULL;      } -    return -1; +    return -PA_ERR_IO;  }  /* Called from IO context */ @@ -1031,28 +1035,33 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse              switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { -                case PA_SINK_SUSPENDED: +                case PA_SINK_SUSPENDED: { +                    int r; +                      pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); -                    if (suspend(u) < 0) -                        return -1; +                    if ((r = suspend(u)) < 0) +                        return r;                      break; +                }                  case PA_SINK_IDLE: -                case PA_SINK_RUNNING: +                case PA_SINK_RUNNING: { +                    int r;                      if (u->sink->thread_info.state == PA_SINK_INIT) {                          if (build_pollfd(u) < 0) -                            return -1; +                            return -PA_ERR_IO;                      }                      if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { -                        if (unsuspend(u) < 0) -                            return -1; +                        if ((r = unsuspend(u)) < 0) +                            return r;                      }                      break; +                }                  case PA_SINK_UNLINKED:                  case PA_SINK_INIT: @@ -1080,7 +1089,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t new_state) {          reserve_done(u);      else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state))          if (reserve_init(u, u->device_name) < 0) -            return -1; +            return -PA_ERR_BUSY;      return 0;  } @@ -1633,8 +1642,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca      const char *dev_id = NULL;      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; +    uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark; +    snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;      size_t frame_size;      pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;      pa_sink_new_data data; @@ -1668,8 +1677,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca          goto fail;      } -    hwbuf_size = frag_size * nfrags; +    buffer_size = nfrags * frag_size; +      period_frames = frag_size/frame_size; +    buffer_frames = buffer_size/frame_size;      tsched_frames = tsched_size/frame_size;      if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { @@ -1736,7 +1747,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_PLAYBACK, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, mapping)))              goto fail; @@ -1751,7 +1762,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_PLAYBACK, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, profile_set, &mapping)))              goto fail; @@ -1763,7 +1774,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_PLAYBACK, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, FALSE)))              goto fail;      } @@ -1789,11 +1800,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca          u->use_tsched = use_tsched = FALSE;      } -    if (use_tsched && !pa_alsa_pcm_is_hw(u->pcm_handle)) { -        pa_log_info("Device is not a hardware device, disabling timer-based scheduling."); -        u->use_tsched = use_tsched = FALSE; -    } -      if (u->use_mmap)          pa_log_info("Successfully enabled mmap() mode."); @@ -1815,7 +1821,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca      pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);      pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); -    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); +    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size));      pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));      pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); @@ -1856,13 +1862,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca      pa_sink_set_rtpoll(u->sink, u->rtpoll);      u->frame_size = frame_size; -    u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); -    u->nfragments = nfrags; -    u->hwbuf_size = u->fragment_size * nfrags; +    u->fragment_size = frag_size = (size_t) (period_frames * frame_size); +    u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size);      pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels); -    pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", -                nfrags, (long unsigned) u->fragment_size, +    pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)", +                (double) u->hwbuf_size / (double) u->fragment_size, +                (long unsigned) u->fragment_size, +                (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC, +                (long unsigned) u->hwbuf_size,                  (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);      pa_sink_set_max_request(u->sink, u->hwbuf_size); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 165b2e3b..fa3ac0aa 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -66,7 +66,7 @@  #define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC)       /* 10ms  */  #define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC)        /* 5ms */  #define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC)    /* 20s */ -#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC)   /* 3ms */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (0*PA_USEC_PER_MSEC)   /* 0ms */  #define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms */  #define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC)           /* 10ms */ @@ -111,8 +111,6 @@ struct userdata {      pa_usec_t watermark_dec_not_before; -    unsigned nfragments; -      char *device_name;      char *control_device; @@ -406,6 +404,7 @@ static int try_recover(struct userdata *u, const char *call, int err) {  static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) {      size_t left_to_record;      size_t rec_space = u->hwbuf_size - u->hwbuf_unused; +    pa_bool_t overrun = FALSE;      /* We use <= instead of < for this check here because an overrun       * only happens after the last sample was processed, not already when @@ -418,6 +417,7 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t          /* We got a dropout. What a mess! */          left_to_record = 0; +        overrun = TRUE;  #ifdef DEBUG_TIMING          PA_DEBUG_TRAP; @@ -434,7 +434,7 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t      if (u->use_tsched) {          pa_bool_t reset_not_before = TRUE; -        if (left_to_record < u->watermark_inc_threshold) +        if (overrun || left_to_record < u->watermark_inc_threshold)              increase_watermark(u);          else if (left_to_record > u->watermark_dec_threshold) {              reset_not_before = FALSE; @@ -889,8 +889,7 @@ static int unsuspend(struct userdata *u) {      pa_sample_spec ss;      int err;      pa_bool_t b, d; -    unsigned nfrags; -    snd_pcm_uframes_t period_size; +    snd_pcm_uframes_t period_size, buffer_size;      pa_assert(u);      pa_assert(!u->pcm_handle); @@ -898,7 +897,7 @@ static int unsuspend(struct userdata *u) {      pa_log_info("Trying resume...");      if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, -                            /*SND_PCM_NONBLOCK|*/ +                            SND_PCM_NONBLOCK|                              SND_PCM_NO_AUTO_RESAMPLE|                              SND_PCM_NO_AUTO_CHANNELS|                              SND_PCM_NO_AUTO_FORMAT)) < 0) { @@ -907,12 +906,12 @@ static int unsuspend(struct userdata *u) {      }      ss = u->source->sample_spec; -    nfrags = u->nfragments;      period_size = u->fragment_size / u->frame_size; +    buffer_size = u->hwbuf_size / u->frame_size;      b = u->use_mmap;      d = u->use_tsched; -    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) { +    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) {          pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));          goto fail;      } @@ -927,10 +926,11 @@ static int unsuspend(struct userdata *u) {          goto fail;      } -    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { -        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)", -                    (unsigned long) u->nfragments, (unsigned long) u->fragment_size, -                    (unsigned long) nfrags, period_size * u->frame_size); +    if (period_size*u->frame_size != u->fragment_size || +        buffer_size*u->frame_size != u->hwbuf_size) { +        pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", +                    (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, +                    (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size));          goto fail;      } @@ -959,7 +959,7 @@ fail:          u->pcm_handle = NULL;      } -    return -1; +    return -PA_ERR_IO;  }  static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { @@ -982,30 +982,34 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off              switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { -                case PA_SOURCE_SUSPENDED: +                case PA_SOURCE_SUSPENDED: { +                    int r;                      pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state)); -                    if (suspend(u) < 0) -                        return -1; +                    if ((r = suspend(u)) < 0) +                        return r;                      break; +                }                  case PA_SOURCE_IDLE: -                case PA_SOURCE_RUNNING: +                case PA_SOURCE_RUNNING: { +                    int r;                      if (u->source->thread_info.state == PA_SOURCE_INIT) {                          if (build_pollfd(u) < 0) -                            return -1; +                            return -PA_ERR_IO;                          snd_pcm_start(u->pcm_handle);                      }                      if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { -                        if (unsuspend(u) < 0) -                            return -1; +                        if ((r = unsuspend(u)) < 0) +                            return r;                      }                      break; +                }                  case PA_SOURCE_UNLINKED:                  case PA_SOURCE_INIT: @@ -1033,7 +1037,7 @@ static int source_set_state_cb(pa_source *s, pa_source_state_t new_state) {          reserve_done(u);      else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state))          if (reserve_init(u, u->device_name) < 0) -            return -1; +            return -PA_ERR_BUSY;      return 0;  } @@ -1481,8 +1485,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p      const char *dev_id = NULL;      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; +    uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark; +    snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;      size_t frame_size;      pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;      pa_source_new_data data; @@ -1516,8 +1520,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p          goto fail;      } -    hwbuf_size = frag_size * nfrags; +    buffer_size = nfrags * frag_size; +      period_frames = frag_size/frame_size; +    buffer_frames = buffer_size/frame_size;      tsched_frames = tsched_size/frame_size;      if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { @@ -1583,7 +1589,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_CAPTURE, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, mapping)))              goto fail; @@ -1597,7 +1603,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_CAPTURE, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, profile_set, &mapping)))              goto fail; @@ -1608,7 +1614,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p                        &u->device_name,                        &ss, &map,                        SND_PCM_STREAM_CAPTURE, -                      &nfrags, &period_frames, tsched_frames, +                      &period_frames, &buffer_frames, tsched_frames,                        &b, &d, FALSE)))              goto fail;      } @@ -1634,11 +1640,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p          u->use_tsched = use_tsched = FALSE;      } -    if (use_tsched && !pa_alsa_pcm_is_hw(u->pcm_handle)) { -        pa_log_info("Device is not a hardware device, disabling timer-based scheduling."); -        u->use_tsched = use_tsched = FALSE; -    } -      if (u->use_mmap)          pa_log_info("Successfully enabled mmap() mode."); @@ -1660,7 +1661,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p      pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);      pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); -    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); +    pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size));      pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));      pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); @@ -1701,13 +1702,15 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p      pa_source_set_rtpoll(u->source, u->rtpoll);      u->frame_size = frame_size; -    u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); -    u->nfragments = nfrags; -    u->hwbuf_size = u->fragment_size * nfrags; +    u->fragment_size = frag_size = (size_t) (period_frames * frame_size); +    u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size);      pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels); -    pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", -                nfrags, (long unsigned) u->fragment_size, +    pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)", +                (double) u->hwbuf_size / (double) u->fragment_size, +                (long unsigned) u->fragment_size, +                (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC, +                (long unsigned) u->hwbuf_size,                  (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);      if (u->use_tsched) { diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index a47a8958..43a8e829 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -93,6 +93,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s      int ret;      pa_assert(pcm_handle); +    pa_assert(hwparams);      pa_assert(f);      if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) @@ -148,33 +149,71 @@ try_auto:      return -1;  } +static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) { +    snd_pcm_uframes_t s; +    int d, ret; + +    pa_assert(pcm_handle); +    pa_assert(hwparams); + +    s = size; +    d = 0; +    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) { +        s = size; +        d = -1; +        if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) { +            s = size; +            d = 1; +            if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) { +                pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret)); +                return ret; +            } +        } +    } + +    return 0; +} + +static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) { +    int ret; + +    pa_assert(pcm_handle); +    pa_assert(hwparams); + +    if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) { +        pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); +        return ret; +    } + +    return 0; +} +  /* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ + * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */  int pa_alsa_set_hw_params(          snd_pcm_t *pcm_handle,          pa_sample_spec *ss, -        uint32_t *periods,          snd_pcm_uframes_t *period_size, +        snd_pcm_uframes_t *buffer_size,          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,          pa_bool_t *use_tsched,          pa_bool_t require_exact_channel_number) {      int ret = -1; +    snd_pcm_hw_params_t *hwparams, *hwparams_copy; +    int dir;      snd_pcm_uframes_t _period_size = period_size ? *period_size : 0; -    unsigned int _periods = periods ? *periods : 0; -    unsigned int r = ss->rate; -    unsigned int c = ss->channels; -    pa_sample_format_t f = ss->format; -    snd_pcm_hw_params_t *hwparams; +    snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;      pa_bool_t _use_mmap = use_mmap && *use_mmap;      pa_bool_t _use_tsched = use_tsched && *use_tsched; -    int dir; +    pa_sample_spec _ss = *ss;      pa_assert(pcm_handle);      pa_assert(ss);      snd_pcm_hw_params_alloca(&hwparams); +    snd_pcm_hw_params_alloca(&hwparams_copy);      if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {          pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret)); @@ -208,114 +247,143 @@ int pa_alsa_set_hw_params(      if (!_use_mmap)          _use_tsched = FALSE; -    if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) +    if (!pa_alsa_pcm_is_hw(pcm_handle)) +        _use_tsched = FALSE; + +    if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)          goto finish; -    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) { +    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {          pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));          goto finish;      }      if (require_exact_channel_number) { -        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) { -            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", c, pa_alsa_strerror(ret)); +        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) { +            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));              goto finish;          }      } else { +        unsigned int c = _ss.channels; +          if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) { -            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", c, pa_alsa_strerror(ret)); +            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));              goto finish;          } -    } -    if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0) { -        pa_log_debug("snd_pcm_hw_params_set_periods_integer() failed: %s", pa_alsa_strerror(ret)); -        goto finish; +        _ss.channels = c;      } -    if (_period_size > 0 && tsched_size > 0 && _periods > 0) { -        snd_pcm_uframes_t buffer_size; -        unsigned int p; +    if (_use_tsched && tsched_size > 0) { +        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate); +        _period_size = _buffer_size; +    } else { +        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate); +        _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate); +    } -        /* Adjust the buffer sizes, if we didn't get the rate we were asking for */ -        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate); -        tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate); +    if (_buffer_size > 0 || _period_size > 0) { +        snd_pcm_uframes_t max_frames = 0; -        if (_use_tsched) { -            buffer_size = 0; +        if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0) +            pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret)); +        else +            pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) (max_frames * PA_MSEC_PER_SEC / _ss.rate)); -            if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0) -                pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret)); -            else -                pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r); +        /* Some ALSA drivers really don't like if we set the buffer +         * size first and the number of periods second. (which would +         * make a lot more sense to me) So, try a few combinations +         * before we give up. */ + +        if (_buffer_size > 0 && _period_size > 0) { +            snd_pcm_hw_params_copy(hwparams_copy, hwparams); + +            /* First try: set buffer size first, followed by period size */ +            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && +                set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && +                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { +                pa_log_debug("Set buffer size first, period size second."); +                goto success; +            } -            _period_size = tsched_size; -            _periods = 1; +            /* Second try: set period size first, followed by buffer size */ +            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && +                set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && +                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { +                pa_log_debug("Set period size first, buffer size second."); +                goto success; +            }          } -        /* Some ALSA drivers really don't like if we set the buffer -         * size first and the number of periods second. (which would -         * make a lot more sense to me) So, follow this rule and -         * adjust the periods first and the buffer size second */ - -        /* First we pass 0 as direction to get exactly what we -         * asked for. That this is necessary is presumably a bug -         * in ALSA. All in all this is mostly a hint to ALSA, so -         * we don't care if this fails. */ - -        p = _periods; -        dir = 0; -        if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { -            p = _periods; -            dir = 1; -            if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { -                p = _periods; -                dir = -1; -                if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir)) < 0) -                    pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret)); +        if (_buffer_size > 0) { +            snd_pcm_hw_params_copy(hwparams_copy, hwparams); + +            /* Third try: set only buffer size */ +            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && +                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { +                pa_log_debug("Set only buffer size second."); +                goto success;              }          } -        /* Now set the buffer size */ -        buffer_size = _periods * _period_size; -        if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) -            pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); +        if (_period_size > 0) { +            snd_pcm_hw_params_copy(hwparams_copy, hwparams); + +            /* Fourth try: set only period size */ +            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && +                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { +                pa_log_debug("Set only period size second."); +                goto success; +            } +        }      } -    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) +    pa_log_debug("Set neither period nor buffer size."); + +    /* Last chance, set nothing */ +    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { +        pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));          goto finish; +    } + +success: -    if (ss->rate != r) -        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); +    if (ss->rate != _ss.rate) +        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate); -    if (ss->channels != c) -        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); +    if (ss->channels != _ss.channels) +        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels); -    if (ss->format != f) -        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); +    if (ss->format != _ss.format) +        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(_ss.format));      if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {          pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));          goto finish;      } +    if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) { +        pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret)); +        goto finish; +    } +      if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 || -        (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0) { -        pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret)); +        (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) { +        pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));          goto finish;      }      /* If the sample rate deviates too much, we need to resample */ -    if (r < ss->rate*.95 || r > ss->rate*1.05) -        ss->rate = r; -    ss->channels = (uint8_t) c; -    ss->format = f; +    if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05) +        ss->rate = _ss.rate; +    ss->channels = _ss.channels; +    ss->format = _ss.format; -    pa_assert(_periods > 0);      pa_assert(_period_size > 0); +    pa_assert(_buffer_size > 0); -    if (periods) -        *periods = _periods; +    if (buffer_size) +        *buffer_size = _buffer_size;      if (period_size)          *period_size = _period_size; @@ -393,8 +461,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(          pa_sample_spec *ss,          pa_channel_map* map,          int mode, -        uint32_t *nfrags,          snd_pcm_uframes_t *period_size, +        snd_pcm_uframes_t *buffer_size,          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,          pa_bool_t *use_tsched, @@ -410,8 +478,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(      pa_assert(dev);      pa_assert(ss);      pa_assert(map); -    pa_assert(nfrags); -    pa_assert(period_size);      pa_assert(ps);      /* First we try to find a device string with a superset of the @@ -433,8 +499,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(                  ss,                  map,                  mode, -                nfrags,                  period_size, +                buffer_size,                  tsched_size,                  use_mmap,                  use_tsched, @@ -460,8 +526,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(                  ss,                  map,                  mode, -                nfrags,                  period_size, +                buffer_size,                  tsched_size,                  use_mmap,                  use_tsched, @@ -478,7 +544,18 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(      /* OK, we didn't find any good device, so let's try the raw hw: stuff */      d = pa_sprintf_malloc("hw:%s", dev_id);      pa_log_debug("Trying %s as last resort...", d); -    pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE); +    pcm_handle = pa_alsa_open_by_device_string( +            d, +            dev, +            ss, +            map, +            mode, +            period_size, +            buffer_size, +            tsched_size, +            use_mmap, +            use_tsched, +            FALSE);      pa_xfree(d);      if (pcm_handle && mapping) @@ -493,8 +570,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(          pa_sample_spec *ss,          pa_channel_map* map,          int mode, -        uint32_t *nfrags,          snd_pcm_uframes_t *period_size, +        snd_pcm_uframes_t *buffer_size,          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,          pa_bool_t *use_tsched, @@ -508,8 +585,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(      pa_assert(dev);      pa_assert(ss);      pa_assert(map); -    pa_assert(nfrags); -    pa_assert(period_size);      pa_assert(m);      try_ss.channels = m->channel_map.channels; @@ -524,8 +599,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(              &try_ss,              &try_map,              mode, -            nfrags,              period_size, +            buffer_size,              tsched_size,              use_mmap,              use_tsched, @@ -547,8 +622,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(          pa_sample_spec *ss,          pa_channel_map* map,          int mode, -        uint32_t *nfrags,          snd_pcm_uframes_t *period_size, +        snd_pcm_uframes_t *buffer_size,          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,          pa_bool_t *use_tsched, @@ -579,7 +654,15 @@ snd_pcm_t *pa_alsa_open_by_device_string(          pa_log_debug("Managed to open %s", d); -        if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) { +        if ((err = pa_alsa_set_hw_params( +                     pcm_handle, +                     ss, +                     period_size, +                     buffer_size, +                     tsched_size, +                     use_mmap, +                     use_tsched, +                     require_exact_channel_number)) < 0) {              if (!reformat) {                  reformat = TRUE; @@ -632,8 +715,8 @@ snd_pcm_t *pa_alsa_open_by_template(          pa_sample_spec *ss,          pa_channel_map* map,          int mode, -        uint32_t *nfrags,          snd_pcm_uframes_t *period_size, +        snd_pcm_uframes_t *buffer_size,          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,          pa_bool_t *use_tsched, @@ -653,8 +736,8 @@ snd_pcm_t *pa_alsa_open_by_template(                  ss,                  map,                  mode, -                nfrags,                  period_size, +                buffer_size,                  tsched_size,                  use_mmap,                  use_tsched, @@ -900,7 +983,7 @@ void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) {      snd_ctl_card_info_alloca(&info);      if ((err = snd_ctl_open(&ctl, name, 0)) < 0) { -        pa_log_warn("Error opening low-level control device '%s'", name); +        pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err));          return;      } diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 830a922e..265cd28c 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -42,8 +42,8 @@  int pa_alsa_set_hw_params(          snd_pcm_t *pcm_handle,          pa_sample_spec *ss,                /* modified at return */ -        uint32_t *periods,                 /* modified at return */          snd_pcm_uframes_t *period_size,    /* modified at return */ +        snd_pcm_uframes_t *buffer_size,    /* modified at return */          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,               /* modified at return */          pa_bool_t *use_tsched,             /* modified at return */ @@ -60,8 +60,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(          pa_sample_spec *ss,               /* modified at return */          pa_channel_map* map,              /* modified at return */          int mode, -        uint32_t *nfrags,                 /* modified at return */          snd_pcm_uframes_t *period_size,   /* modified at return */ +        snd_pcm_uframes_t *buffer_size,   /* modified at return */          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,              /* modified at return */          pa_bool_t *use_tsched,            /* modified at return */ @@ -75,8 +75,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(          pa_sample_spec *ss,               /* modified at return */          pa_channel_map* map,              /* modified at return */          int mode, -        uint32_t *nfrags,                 /* modified at return */          snd_pcm_uframes_t *period_size,   /* modified at return */ +        snd_pcm_uframes_t *buffer_size,   /* modified at return */          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,              /* modified at return */          pa_bool_t *use_tsched,            /* modified at return */ @@ -89,8 +89,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(          pa_sample_spec *ss,               /* modified at return */          pa_channel_map* map,              /* modified at return */          int mode, -        uint32_t *nfrags,                 /* modified at return */          snd_pcm_uframes_t *period_size,   /* modified at return */ +        snd_pcm_uframes_t *buffer_size,   /* modified at return */          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,              /* modified at return */          pa_bool_t *use_tsched,            /* modified at return */ @@ -104,8 +104,8 @@ snd_pcm_t *pa_alsa_open_by_template(          pa_sample_spec *ss,               /* modified at return */          pa_channel_map* map,              /* modified at return */          int mode, -        uint32_t *nfrags,                 /* modified at return */          snd_pcm_uframes_t *period_size,   /* modified at return */ +        snd_pcm_uframes_t *buffer_size,   /* modified at return */          snd_pcm_uframes_t tsched_size,          pa_bool_t *use_mmap,              /* modified at return */          pa_bool_t *use_tsched,            /* modified at return */ diff --git a/src/modules/alsa/mixer/paths/analog-input.conf.common b/src/modules/alsa/mixer/paths/analog-input.conf.common index 6728a6ae..87af38b3 100644 --- a/src/modules/alsa/mixer/paths/analog-input.conf.common +++ b/src/modules/alsa/mixer/paths/analog-input.conf.common @@ -78,6 +78,10 @@ priority = 19  name = input-microphone  priority = 19 +[Option Input Source:Internal Mic] +name = input-microphone +priority = 19 +  [Option Input Source:Line]  name = input-linein  priority = 18 @@ -90,6 +94,10 @@ priority = 18  name = input-linein  priority = 18 +[Option Input Source:Docking-Station] +name = input-docking +priority = 17 +  ;;; ' Capture Source'  [Element Capture Source] diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf index 691cb3f2..61d2e297 100644 --- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf @@ -56,7 +56,7 @@ volume = off  switch = off  volume = off -[Element Sourround] +[Element Surround]  switch = off  volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf index 3457d4a2..911361d7 100644 --- a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf @@ -62,7 +62,7 @@ volume = off  switch = off  volume = off -[Element Sourround] +[Element Surround]  switch = off  volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output-mono.conf b/src/modules/alsa/mixer/paths/analog-output-mono.conf index dc270cfe..2fbc60b7 100644 --- a/src/modules/alsa/mixer/paths/analog-output-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-mono.conf @@ -59,7 +59,7 @@ volume = off  switch = off  volume = off -[Element Sourround] +[Element Surround]  switch = off  volume = off diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 55f6a6e2..6bea33d7 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -329,7 +329,7 @@ int pa__init(pa_module *m) {      if (!u->profile_set)          goto fail; -    pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec); +    pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec, m->core->default_n_fragments, m->core->default_fragment_size_msec);      pa_card_new_data_init(&data);      data.driver = __FILE__; diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index b8a88042..4592fca1 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -221,9 +221,7 @@ static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t r      pa_assert(u);      pa_assert(u->service_fd >= 0);      pa_assert(msg); - -    if (room <= 0) -        room = BT_SUGGESTED_BUFFER_SIZE; +    pa_assert(room >= sizeof(*msg));      pa_log_debug("Trying to receive message from audio service..."); @@ -236,6 +234,11 @@ static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t r          return -1;      } +    if (msg->length > room) { +        pa_log_error("Not enough room."); +        return -1; +    } +      /* Secondly, read the payload */      if (msg->length > sizeof(*msg)) { diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index 85523b39..5f31d688 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -342,7 +342,7 @@ int pa__init(pa_module*m) {      if ((u->fd = pa_start_child_for_read(  #if defined(__linux__) && !defined(__OPTIMIZE__) -                              pa_run_from_build_tree() ? PA_BUILDDIR "/.libs/gconf-helper" : +                              pa_run_from_build_tree() ? PA_BUILDDIR "/gconf-helper" :  #endif                   PA_GCONF_HELPER, NULL, &u->pid)) < 0)          goto fail; diff --git a/src/modules/hal-util.c b/src/modules/hal-util.c index e2a2d8d7..2d59f51d 100644 --- a/src/modules/hal-util.c +++ b/src/modules/hal-util.c @@ -65,7 +65,7 @@ int pa_hal_get_info(pa_core *core, pa_proplist *p, int card) {          goto finish;      } -    if (!(udis = libhal_find_device_by_capability(hal, "sound", &n, &error)) < 0) { +    if (!(udis = libhal_find_device_by_capability(hal, "sound", &n, &error))) {          pa_log_error("Couldn't find devices: %s: %s", error.name, error.message);          goto finish;      } diff --git a/src/modules/module-always-sink.c b/src/modules/module-always-sink.c index aee1c650..3d7de9c6 100644 --- a/src/modules/module-always-sink.c +++ b/src/modules/module-always-sink.c @@ -24,6 +24,7 @@  #endif  #include <pulse/xmalloc.h> +#include <pulse/i18n.h>  #include <pulsecore/core.h>  #include <pulsecore/sink-input.h> @@ -35,7 +36,7 @@  #include "module-always-sink-symdef.h"  PA_MODULE_AUTHOR("Colin Guthrie"); -PA_MODULE_DESCRIPTION("Always keeps at least one sink loaded even if it's a null one"); +PA_MODULE_DESCRIPTION(_("Always keeps at least one sink loaded even if it's a null one"));  PA_MODULE_VERSION(PACKAGE_VERSION);  PA_MODULE_LOAD_ONCE(TRUE);  PA_MODULE_USAGE( @@ -78,7 +79,8 @@ static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata*      u->ignore = TRUE; -    t = pa_sprintf_malloc("sink_name=%s", u->sink_name); +    t = pa_sprintf_malloc("sink_name=%s sink_properties='device.description=\"%s\"'", u->sink_name, +                          _("Dummy Output"));      m = pa_module_load(c, "module-null-sink", t);      u->null_module = m ? m->index : PA_INVALID_INDEX;      pa_xfree(t); diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index fd9452b4..6bd0f4fc 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -25,6 +25,8 @@  #include <stdio.h>  #include <unistd.h> +#include <fcntl.h> +#include <errno.h>  #include <pulsecore/module.h>  #include <pulsecore/iochannel.h> @@ -33,6 +35,8 @@  #include <pulsecore/log.h>  #include <pulsecore/modargs.h>  #include <pulsecore/macro.h> +#include <pulsecore/core-util.h> +#include <pulsecore/core-error.h>  #include "module-cli-symdef.h" @@ -69,6 +73,7 @@ int pa__init(pa_module*m) {      pa_iochannel *io;      pa_modargs *ma;      pa_bool_t exit_on_eof = FALSE; +    int fd;      pa_assert(m); @@ -88,15 +93,28 @@ int pa__init(pa_module*m) {      }      if (pa_stdio_acquire() < 0) { -        pa_log("STDIN/STDUSE already in use."); +        pa_log("STDIN/STDOUT already in use.");          goto fail;      } -    io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO); -    pa_iochannel_set_noclose(io, 1); +    /* We try to open the controlling tty anew here. This has the +     * benefit of giving us a new fd that doesn't share the O_NDELAY +     * flag with fds 0, 1, or 2. Since pa_iochannel_xxx needs O_NDELAY +     * on its fd using those fds directly could set O_NDELAY which +     * fprintf() doesn't really like, resulting in truncated output +     * of log messages, particularly because if stdout and stderr are +     * dup'ed they share the same O_NDELAY, too. */ + +    if ((fd = open("/dev/tty", O_RDWR|O_CLOEXEC|O_NONBLOCK)) >= 0) { +        io = pa_iochannel_new(m->core->mainloop, fd, fd); +        pa_log_debug("Managed to open /dev/tty."); +    } else { +        io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO); +        pa_iochannel_set_noclose(io, TRUE); +        pa_log_debug("Failed to open /dev/tty, using stdin/stdout fds instead."); +    }      m->userdata = pa_cli_new(m->core, io, m); -      pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m);      pa_modargs_free(ma); @@ -114,7 +132,7 @@ fail:  void pa__done(pa_module*m) {      pa_assert(m); -    if (m->core->running_as_daemon == 0) { +    if (m->userdata) {          pa_cli_free(m->userdata);          pa_stdio_release();      } diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 6034d0ee..18519131 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -435,9 +435,7 @@ static int hal_device_add_all(struct userdata *u) {          int i;          for (i = 0; i < n; i++) { -            struct device *d; - -            if ((d = hal_device_add(u, udis[i]))) { +            if (hal_device_add(u, udis[i])) {                  count++;                  pa_log_debug("Loaded device %s", udis[i]);              } else diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 933fb182..994c778f 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -82,6 +82,8 @@ struct userdata {      LADSPA_Data control_out;      pa_memblockq *memblockq; + +    pa_bool_t auto_desc;  };  static const char* const valid_modargs[] = { @@ -423,6 +425,19 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {          pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);      } else          pa_sink_set_asyncmsgq(u->sink, NULL); + +    if (u->auto_desc && dest) { +        const char *z; +        pa_proplist *pl; + +        pl = pa_proplist_new(); +        z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); +        pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", +                         pa_proplist_gets(u->sink->proplist, "device.ladspa.name"), z ? z : dest->name); + +        pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl); +        pa_proplist_free(pl); +    }  }  /* Called from main context */ @@ -451,7 +466,6 @@ int pa__init(pa_module*m) {      pa_channel_map map;      pa_modargs *ma;      char *t; -    const char *z;      pa_sink *master;      pa_sink_input_new_data sink_input_data;      pa_sink_new_data sink_data; @@ -765,8 +779,6 @@ int pa__init(pa_module*m) {          sink_data.name = pa_sprintf_malloc("%s.ladspa", master->name);      pa_sink_new_data_set_sample_spec(&sink_data, &ss);      pa_sink_new_data_set_channel_map(&sink_data, &map); -    z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); -    pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name);      pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);      pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");      pa_proplist_sets(sink_data.proplist, "device.ladspa.module", plugin); @@ -782,6 +794,13 @@ int pa__init(pa_module*m) {          goto fail;      } +    if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { +        const char *z; + +        z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); +        pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name); +    } +      u->sink = pa_sink_new(m->core, &sink_data,                            PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME|                            (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 36c50b05..74a2ebb1 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -35,6 +35,7 @@  #include <pulse/rtclock.h>  #include <pulse/timeval.h>  #include <pulse/xmalloc.h> +#include <pulse/i18n.h>  #include <pulsecore/macro.h>  #include <pulsecore/sink.h> @@ -51,7 +52,7 @@  #include "module-null-sink-symdef.h"  PA_MODULE_AUTHOR("Lennart Poettering"); -PA_MODULE_DESCRIPTION("Clocked NULL sink"); +PA_MODULE_DESCRIPTION(_("Clocked NULL sink"));  PA_MODULE_VERSION(PACKAGE_VERSION);  PA_MODULE_LOAD_ONCE(FALSE);  PA_MODULE_USAGE( @@ -287,7 +288,7 @@ int pa__init(pa_module*m) {      pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));      pa_sink_new_data_set_sample_spec(&data, &ss);      pa_sink_new_data_set_channel_map(&data, &map); -    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output")); +    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", _("Null Output")));      pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");      if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c index e191ec33..7221b14f 100644 --- a/src/modules/module-position-event-sounds.c +++ b/src/modules/module-position-event-sounds.c @@ -57,35 +57,69 @@ struct userdata {      pa_hook_slot *sink_input_fixate_hook_slot;  }; +static int parse_pos(const char *pos, double *f) { + +    if (pa_atod(pos, f) < 0) { +        pa_log_warn("Failed to parse hpos/vpos property '%s'.", pos); +        return -1; +    } + +    if (*f < 0.0 || *f > 1.0) { +        pa_log_debug("Property hpos/vpos out of range %0.2f", *f); + +        *f = PA_CLAMP(*f, 0.0, 1.0); +    } + +    return 0; +} +  static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) { -    const char *hpos; +    const char *hpos, *vpos, *role;      double f;      char t[PA_CVOLUME_SNPRINT_MAX];      pa_cvolume v;      pa_assert(data); -    if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) +    if (!(role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE)))          return PA_HOOK_OK; -    if (pa_atod(hpos, &f) < 0) { -        pa_log_warn("Failed to parse "PA_PROP_EVENT_MOUSE_HPOS" property '%s'.", hpos); +    if (!pa_streq(role, "event"))          return PA_HOOK_OK; -    } -    if (f < 0.0 || f > 1.0) { -        pa_log_warn("Property "PA_PROP_EVENT_MOUSE_HPOS" out of range %0.2f", f); +    if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) +        hpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_HPOS); + +    if (!(vpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_VPOS))) +        vpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_VPOS); + +    if (!hpos && !vpos)          return PA_HOOK_OK; + +    pa_cvolume_reset(&v, data->sink->sample_spec.channels); + +    if (hpos) { +        if (parse_pos(hpos, &f) < 0) +            return PA_HOOK_OK; + +        if (pa_channel_map_can_balance(&data->sink->channel_map)) { +            pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); +            pa_cvolume_set_balance(&v, &data->sink->channel_map, f*2.0-1.0); +        }      } -    pa_log_debug("Positioning event sound '%s' at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); +    if (vpos) { +        if (parse_pos(vpos, &f) < 0) +            return PA_HOOK_OK; -    pa_cvolume_reset(&v, data->sample_spec.channels); -    pa_cvolume_set_balance(&v, &data->channel_map, f*2.0-1.0); +        if (pa_channel_map_can_fade(&data->sink->channel_map)) { +            pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); +            pa_cvolume_set_fade(&v, &data->sink->channel_map, f*2.0-1.0); +        } +    }      pa_log_debug("Final volume factor %s.", pa_cvolume_snprint(t, sizeof(t), &v)); - -    pa_sink_input_new_data_apply_volume_factor(data, &v); +    pa_sink_input_new_data_apply_volume_factor_sink(data, &v);      return PA_HOOK_OK;  } diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 6cfd0d15..43748bd0 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -58,6 +58,8 @@ struct userdata {      pa_sink *sink;      pa_sink_input *sink_input; + +    pa_bool_t auto_desc;  };  static const char* const valid_modargs[] = { @@ -307,6 +309,18 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {          pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);      } else          pa_sink_set_asyncmsgq(u->sink, NULL); + +    if (u->auto_desc && dest) { +        const char *k; +        pa_proplist *pl; + +        pl = pa_proplist_new(); +        k = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); +        pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : dest->name); + +        pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl); +        pa_proplist_free(pl); +    }  }  int pa__init(pa_module*m) { @@ -314,7 +328,6 @@ int pa__init(pa_module*m) {      pa_sample_spec ss;      pa_channel_map sink_map, stream_map;      pa_modargs *ma; -    const char *k;      pa_sink *master;      pa_sink_input_new_data sink_input_data;      pa_sink_new_data sink_data; @@ -370,8 +383,6 @@ int pa__init(pa_module*m) {          sink_data.name = pa_sprintf_malloc("%s.remapped", master->name);      pa_sink_new_data_set_sample_spec(&sink_data, &ss);      pa_sink_new_data_set_channel_map(&sink_data, &sink_map); -    k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); -    pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name);      pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);      pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); @@ -381,6 +392,13 @@ int pa__init(pa_module*m) {          goto fail;      } +    if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { +        const char *k; + +        k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); +        pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name); +    } +      u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY));      pa_sink_new_data_done(&sink_data); diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 5a6c8a3d..1e2dc4df 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1476,7 +1476,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,          if (!so->source)              continue; -        /* It might happen that a stream and a sink are set up at the +        /* It might happen that a stream and a source are set up at the             same time, in which case we want to make sure we don't             interfere with that */          if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so))) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ccb81d0..c97de3a1 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -332,7 +332,7 @@ static void command_moved(pa_pdispatch *pd,  uint32_t command,  uint32_t tag, pa  static void command_stream_buffer_attr_changed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {      struct userdata *u = userdata; -    uint32_t channel, maxlength, tlength, fragsize, prebuf, minreq; +    uint32_t channel, maxlength, tlength = 0, fragsize, prebuf, minreq;      pa_usec_t usec;      pa_assert(pd); @@ -1069,6 +1069,33 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command,  uint32_t tag, pa_t          }      } +    if (u->version >= 16) { +        uint32_t n_ports; +        const char *s; + +        if (pa_tagstruct_getu32(t, &n_ports)) { +            pa_log("Parse failure"); +            goto fail; +        } + +        for (uint32_t j = 0; j < n_ports; j++) { +            uint32_t priority; + +            if (pa_tagstruct_gets(t, &s) < 0 || /* name */ +                pa_tagstruct_gets(t, &s) < 0 || /* description */ +                pa_tagstruct_getu32(t, &priority) < 0) { + +                pa_log("Parse failure"); +                goto fail; +            } +        } + +        if (pa_tagstruct_gets(t, &s) < 0) { /* active port */ +            pa_log("Parse failure"); +            goto fail; +        } +    } +      if (!pa_tagstruct_eof(t)) {          pa_log("Packet too long");          goto fail; @@ -1097,7 +1124,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command,  uint32_t tag      uint32_t idx, owner_module, client, sink;      pa_usec_t buffer_usec, sink_usec;      const char *name, *driver, *resample_method; -    pa_bool_t mute; +    pa_bool_t mute = FALSE;      pa_sample_spec sample_spec;      pa_channel_map channel_map;      pa_cvolume volume; @@ -1245,6 +1272,33 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command,  uint32_t tag, pa          }      } +    if (u->version >= 16) { +        uint32_t n_ports; +        const char *s; + +        if (pa_tagstruct_getu32(t, &n_ports)) { +            pa_log("Parse failure"); +            goto fail; +        } + +        for (uint32_t j = 0; j < n_ports; j++) { +            uint32_t priority; + +            if (pa_tagstruct_gets(t, &s) < 0 || /* name */ +                pa_tagstruct_gets(t, &s) < 0 || /* description */ +                pa_tagstruct_getu32(t, &priority) < 0) { + +                pa_log("Parse failure"); +                goto fail; +            } +        } + +        if (pa_tagstruct_gets(t, &s) < 0) { /* active port */ +            pa_log("Parse failure"); +            goto fail; +        } +    } +      if (!pa_tagstruct_eof(t)) {          pa_log("Packet too long");          goto fail; @@ -1345,12 +1399,11 @@ static void command_subscribe_event(pa_pdispatch *pd,  uint32_t command,  uint32  /* Called from main context */  static void start_subscribe(struct userdata *u) {      pa_tagstruct *t; -    uint32_t tag;      pa_assert(u);      t = pa_tagstruct_new(NULL, 0);      pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); -    pa_tagstruct_putu32(t, tag = u->ctag++); +    pa_tagstruct_putu32(t, u->ctag++);      pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SERVER|  #ifdef TUNNEL_SINK                          PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SINK @@ -1526,7 +1579,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t      reply = pa_tagstruct_new(NULL, 0);      pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); -    pa_tagstruct_putu32(reply, tag = u->ctag++); +    pa_tagstruct_putu32(reply, u->ctag++);      if (u->version >= 13) {          pa_proplist *pl; @@ -1753,7 +1806,6 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata  static void sink_set_volume(pa_sink *sink) {      struct userdata *u;      pa_tagstruct *t; -    uint32_t tag;      pa_assert(sink);      u = sink->userdata; @@ -1761,7 +1813,7 @@ static void sink_set_volume(pa_sink *sink) {      t = pa_tagstruct_new(NULL, 0);      pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); -    pa_tagstruct_putu32(t, tag = u->ctag++); +    pa_tagstruct_putu32(t, u->ctag++);      pa_tagstruct_putu32(t, u->device_index);      pa_tagstruct_put_cvolume(t, &sink->real_volume);      pa_pstream_send_tagstruct(u->pstream, t); @@ -1771,7 +1823,6 @@ static void sink_set_volume(pa_sink *sink) {  static void sink_set_mute(pa_sink *sink) {      struct userdata *u;      pa_tagstruct *t; -    uint32_t tag;      pa_assert(sink);      u = sink->userdata; @@ -1782,7 +1833,7 @@ static void sink_set_mute(pa_sink *sink) {      t = pa_tagstruct_new(NULL, 0);      pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE); -    pa_tagstruct_putu32(t, tag = u->ctag++); +    pa_tagstruct_putu32(t, u->ctag++);      pa_tagstruct_putu32(t, u->device_index);      pa_tagstruct_put_boolean(t, !!sink->muted);      pa_pstream_send_tagstruct(u->pstream, t); diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index b41b9c0f..1b1e9c1a 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -29,10 +29,13 @@  #include <sys/inotify.h>  #include <libudev.h> +#include <pulse/timeval.h> +  #include <pulsecore/modargs.h>  #include <pulsecore/core-error.h>  #include <pulsecore/core-util.h>  #include <pulsecore/namereg.h> +#include <pulsecore/ratelimit.h>  #include "module-udev-detect-symdef.h" @@ -50,6 +53,7 @@ struct device {      char *card_name;      char *args;      uint32_t module; +    pa_ratelimit ratelimit;  };  struct userdata { @@ -110,6 +114,9 @@ static pa_bool_t is_card_busy(const char *id) {      pa_assert(id); +    /* This simply uses /proc/asound/card.../pcm.../sub.../status to +     * check whether there is still a process using this audio device. */ +      card_path = pa_sprintf_malloc("/proc/asound/card%s", id);      if (!(card_dir = opendir(card_path))) { @@ -234,14 +241,41 @@ static void verify_access(struct userdata *u, struct device *d) {              pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy));              if (!busy) { -                pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); -                m = pa_module_load(u->core, "module-alsa-card", d->args); -                if (m) { -                    d->module = m->index; -                    pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); +                /* So, why do we rate limit here? It's certainly ugly, +                 * but there seems to be no other way. Problem is +                 * this: if we are unable to configure/probe an audio +                 * device after opening it we will close it again and +                 * the module initialization will fail. This will then +                 * cause an inotify event on the device node which +                 * will be forwarded to us. We then try to reopen the +                 * audio device again, practically entering a busy +                 * loop. +                 * +                 * A clean fix would be if we would be able to ignore +                 * our own inotify close events. However, inotify +                 * lacks such functionality. Also, during probing of +                 * the device we cannot really distuingish between +                 * other processes causing EBUSY or ourselves, which +                 * means we have no way to figure out if the probing +                 * during opening was canceled by a "try again" +                 * failure or a "fatal" failure. */ + +                if (pa_ratelimit_test(&d->ratelimit)) { +                    pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); +                    m = pa_module_load(u->core, "module-alsa-card", d->args); + +                    if (m) { +                        d->module = m->index; +                        pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); +                    } else +                        pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);                  } else -                    pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); +                    pa_log_warn("Tried to configure %s (%s) more often than %u times in %llus", +                                d->path, +                                d->card_name, +                                d->ratelimit.burst, +                                (long long unsigned) (d->ratelimit.interval / PA_USEC_PER_SEC));              }          } @@ -277,6 +311,7 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {      d = pa_xnew0(struct device, 1);      d->path = pa_xstrdup(path);      d->module = PA_INVALID_INDEX; +    PA_INIT_RATELIMIT(d->ratelimit, 10*PA_USEC_PER_SEC, 5);      if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))          if (!(t = udev_device_get_property_value(dev, "ID_ID"))) diff --git a/src/modules/raop/base64.c b/src/modules/raop/base64.c index e1cbed02..5b061034 100644 --- a/src/modules/raop/base64.c +++ b/src/modules/raop/base64.c @@ -57,7 +57,6 @@ int pa_base64_encode(const void *data, int size, char **str)      p = s = pa_xnew(char, size * 4 / 3 + 4);      q = (const unsigned char *) data; -    i = 0;      for (i = 0; i < size;) {          c = q[i++];          c *= 256; diff --git a/src/modules/raop/module-raop-discover.c b/src/modules/raop/module-raop-discover.c index eaeb77fc..adba8e4f 100644 --- a/src/modules/raop/module-raop-discover.c +++ b/src/modules/raop/module-raop-discover.c @@ -265,7 +265,7 @@ static void browser_cb(          struct tunnel *t2;          if ((t2 = pa_hashmap_get(u->tunnels, t))) { -            pa_module_unload_by_index(u->core, t2->module_index, TRUE); +            pa_module_unload_request_by_index(u->core, t2->module_index, TRUE);              pa_hashmap_remove(u->tunnels, t2);              tunnel_free(t2);          } @@ -386,7 +386,7 @@ void pa__done(pa_module*m) {          struct tunnel *t;          while ((t = pa_hashmap_steal_first(u->tunnels))) { -            pa_module_unload_by_index(u->core, t->module_index, TRUE); +            pa_module_unload_request_by_index(u->core, t->module_index, TRUE);              tunnel_free(t);          } diff --git a/src/modules/reserve-wrap.c b/src/modules/reserve-wrap.c index 6086fc99..4be19c73 100644 --- a/src/modules/reserve-wrap.c +++ b/src/modules/reserve-wrap.c @@ -137,7 +137,7 @@ pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name)  #ifdef HAVE_DBUS      if (!(r->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { -        pa_log_warn("Unable to contact D-Bus session bus: %s: %s", error.name, error.message); +        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);          /* We don't treat this as error here because we want allow PA           * to run even when no session bus is available. */ @@ -154,10 +154,10 @@ pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name)                   NULL)) < 0) {          if (k == -EBUSY) { -            pa_log_error("Device '%s' already locked.", device_name); +            pa_log_debug("Device '%s' already locked.", device_name);              goto fail;          } else { -            pa_log_warn("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k)); +            pa_log_debug("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));              return r;          }      } @@ -280,7 +280,7 @@ pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const cha  #ifdef HAVE_DBUS      if (!(w->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { -        pa_log_warn("Unable to contact D-Bus session bus: %s: %s", error.name, error.message); +        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);          /* We don't treat this as error here because we want allow PA           * to run even when no session bus is available. */ @@ -294,7 +294,7 @@ pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const cha                   change_cb,                   NULL)) < 0) { -        pa_log_warn("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k)); +        pa_log_debug("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k));          goto fail;      } diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c index ba657f74..59618064 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -60,7 +60,6 @@ struct pa_rtsp_client {      uint16_t port;      pa_socket_client *sc; -    pa_iochannel *io;      pa_ioline *ioline;      pa_rtsp_cb_t callback; @@ -111,10 +110,8 @@ void pa_rtsp_client_free(pa_rtsp_client* c) {      if (c->sc)          pa_socket_client_unref(c->sc); -    if (c->ioline) -        pa_ioline_close(c->ioline); -    else if (c->io) -        pa_iochannel_free(c->io); + +    pa_rtsp_disconnect(c);      pa_xfree(c->hostname);      pa_xfree(c->url); @@ -187,7 +184,6 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {      if (!s) {          /* Keep the ioline/iochannel open as they will be freed automatically */          c->ioline = NULL; -        c->io = NULL;          c->callback(c, STATE_DISCONNECTED, NULL, c->userdata);          return;      } @@ -303,8 +299,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata          pa_log("Connection failed: %s", pa_cstrerror(errno));          return;      } -    pa_assert(!c->io); -    c->io = io; +    pa_assert(!c->ioline);      c->ioline = pa_ioline_new(io);      pa_ioline_set_callback(c->ioline, line_callback, c); @@ -360,9 +355,6 @@ void pa_rtsp_disconnect(pa_rtsp_client *c) {      if (c->ioline)          pa_ioline_close(c->ioline); -    else if (c->io) -        pa_iochannel_free(c->io); -    c->io = NULL;      c->ioline = NULL;  } @@ -408,13 +400,11 @@ static int rtsp_exec(pa_rtsp_client* c, const char* cmd,                          pa_headerlist* headers) {      pa_strbuf* buf;      char* hdrs; -    ssize_t l;      pa_assert(c);      pa_assert(c->url); - -    if (!cmd) -        return -1; +    pa_assert(cmd); +    pa_assert(c->ioline);      pa_log_debug("Sending command: %s", cmd); @@ -453,7 +443,7 @@ static int rtsp_exec(pa_rtsp_client* c, const char* cmd,      hdrs = pa_strbuf_tostring_free(buf);      /*pa_log_debug("Submitting request:");      pa_log_debug(hdrs);*/ -    l = pa_iochannel_write(c->io, hdrs, strlen(hdrs)); +    pa_ioline_puts(c->ioline, hdrs);      pa_xfree(hdrs);      return 0; diff --git a/src/modules/x11/module-x11-publish.c b/src/modules/x11/module-x11-publish.c index 2c7fdc12..7ee1b6da 100644 --- a/src/modules/x11/module-x11-publish.c +++ b/src/modules/x11/module-x11-publish.c @@ -90,7 +90,7 @@ static void publish_servers(struct userdata *u, pa_strlist *l) {          l = pa_strlist_reverse(l);          s = pa_strlist_tostring(l); -        l = pa_strlist_reverse(l); +        pa_strlist_reverse(l);          pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s);          pa_xfree(s);  | 
