]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Improved automatic start/stop
authorAbramo Bagnara <abramo@alsa-project.org>
Thu, 19 Apr 2001 21:18:23 +0000 (21:18 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Thu, 19 Apr 2001 21:18:23 +0000 (21:18 +0000)
include/local.h
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_local.h
src/pcm/pcm_null.c
src/pcm/pcm_params.c
src/pcm/pcm_share.c

index 6959f13d55019d73ec64898137a017fbf3167785..903c36a4a9f6cfda5e2e65605c1a668b6a4a9d95 100644 (file)
@@ -53,4 +53,49 @@ typedef enum _snd_set_mode {
 size_t page_align(size_t size);
 size_t page_size(void);
 
+#define HAVE_GNU_LD
+#define HAVE_ELF
+#define HAVE_ASM_PREVIOUS_DIRECTIVE
+
+/* Stolen from libc-symbols.h in GNU glibc */
+
+/* When a reference to SYMBOL is encountered, the linker will emit a
+   warning message MSG.  */
+#ifdef HAVE_GNU_LD
+# ifdef HAVE_ELF
+
+/* We want the .gnu.warning.SYMBOL section to be unallocated.  */
+#  ifdef HAVE_ASM_PREVIOUS_DIRECTIVE
+#   define __make_section_unallocated(section_string)  \
+  asm (".section " section_string "\n\t.previous");
+#  elif defined HAVE_ASM_POPSECTION_DIRECTIVE
+#   define __make_section_unallocated(section_string)  \
+  asm (".pushsection " section_string "\n\t.popsection");
+#  else
+#   define __make_section_unallocated(section_string)
+#  endif
+
+/* Tacking on "\n\t#" to the section name makes gcc put it's bogus
+   section attributes on what looks like a comment to the assembler.  */
+#  ifdef HAVE_SECTION_QUOTES
+#   define link_warning(symbol, msg) \
+  __make_section_unallocated (".gnu.warning." #symbol) \
+  static const char __evoke_link_warning_##symbol[]    \
+    __attribute__ ((section (".gnu.warning." #symbol "\"\n\t#\""))) = msg;
+#  else
+#   define link_warning(symbol, msg) \
+  __make_section_unallocated (".gnu.warning." #symbol) \
+  static const char __evoke_link_warning_##symbol[]    \
+    __attribute__ ((section (".gnu.warning." #symbol "\n\t#"))) = msg;
+#  endif
+# else
+#  define link_warning(symbol, msg)            \
+  asm (".stabs \"" msg "\",30,0,0,0\n\t"       \
+       ".stabs \"" __SYMBOL_PREFIX #symbol "\",1,0,0,0\n");
+# endif
+#else
+/* We will never be heard; they will all die horribly.  */
+# define link_warning(symbol, msg)
+#endif
+
 #endif
index a8e0dcb511777a15d2745fcbe7b71b99a46d9d37..52cd738f5e7ea9bed80e5ba4bafe8fd22a144fa1 100644 (file)
@@ -172,19 +172,19 @@ typedef enum _snd_pcm_state {
 /** PCM start mode */
 typedef enum _snd_pcm_start {
        /** Automatic start on data read/write */
-       SND_PCM_START_DATA = SNDRV_PCM_START_DATA,
+       SND_PCM_START_DATA,
        /** Explicit start */
-       SND_PCM_START_EXPLICIT = SNDRV_PCM_START_EXPLICIT,
-       SND_PCM_START_LAST = SNDRV_PCM_START_LAST,
+       SND_PCM_START_EXPLICIT,
+       SND_PCM_START_LAST,
 } snd_pcm_start_t;
 
 /** PCM xrun mode */
 typedef enum _snd_pcm_xrun {
        /** Xrun detection disabled */
-       SND_PCM_XRUN_NONE = SNDRV_PCM_XRUN_NONE,
+       SND_PCM_XRUN_NONE,
        /** Stop on xrun detection */
-       SND_PCM_XRUN_STOP = SNDRV_PCM_XRUN_STOP,
-       SND_PCM_XRUN_LAST = SNDRV_PCM_XRUN_LAST,
+       SND_PCM_XRUN_STOP,
+       SND_PCM_XRUN_LAST,
 } snd_pcm_xrun_t;
 
 /** PCM timestamp mode */
@@ -695,6 +695,12 @@ snd_pcm_uframes_t snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *par
 int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
 snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params);
 
+int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
+snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params);
+
+int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
+snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params);
+
 int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
 snd_pcm_uframes_t snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params);
 
index d032603bfa3e5a49babc41dce03e84bcd06c645e..f0590d14dff2c4047b0b8d20c0d3ea52b9e8d418 100644 (file)
@@ -225,13 +225,13 @@ int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
        err = pcm->ops->sw_params(pcm->op_arg, params);
        if (err < 0)
                return err;
-       pcm->start_mode = snd_pcm_sw_params_get_start_mode(params);
-       pcm->xrun_mode = snd_pcm_sw_params_get_xrun_mode(params);
        pcm->tstamp_mode = snd_pcm_sw_params_get_tstamp_mode(params);
        pcm->period_step = params->period_step;
        pcm->sleep_min = params->sleep_min;
        pcm->avail_min = params->avail_min;
        pcm->xfer_align = params->xfer_align;
+       pcm->start_threshold = params->start_threshold;
+       pcm->stop_threshold = params->stop_threshold;
        pcm->silence_threshold = params->silence_threshold;
        pcm->silence_size = params->silence_size;
        pcm->boundary = params->boundary;
@@ -713,7 +713,7 @@ const char *snd_pcm_subformat_description(snd_pcm_subformat_t subformat)
 }
 
 /**
- * \brief get name of PCM start mode setting
+ * \brief (DEPRECATED) get name of PCM start mode setting
  * \param mode PCM start mode
  * \return ascii name of PCM start mode setting
  */
@@ -723,8 +723,10 @@ const char *snd_pcm_start_mode_name(snd_pcm_start_t mode)
        return snd_pcm_start_mode_names[snd_enum_to_int(mode)];
 }
 
+link_warning(snd_pcm_start_mode_name, "Warning: start_mode is deprecated, consider to use start_threshold");
+
 /**
- * \brief get name of PCM xrun mode setting
+ * \brief (DEPRECATED) get name of PCM xrun mode setting
  * \param mode PCM xrun mode
  * \return ascii name of PCM xrun mode setting
  */
@@ -734,6 +736,8 @@ const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode)
        return snd_pcm_xrun_mode_names[snd_enum_to_int(mode)];
 }
 
+link_warning(snd_pcm_xrun_mode_name, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
+
 /**
  * \brief get name of PCM tstamp mode setting
  * \param mode PCM tstamp mode
@@ -793,16 +797,16 @@ int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out)
        assert(pcm);
        assert(out);
        assert(pcm->setup);
-       snd_output_printf(out, "start_mode   : %s\n", snd_pcm_start_mode_name(pcm->start_mode));
-       snd_output_printf(out, "xrun_mode    : %s\n", snd_pcm_xrun_mode_name(pcm->xrun_mode));
        snd_output_printf(out, "tstamp_mode  : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode));
-       snd_output_printf(out, "period_step  : %ld\n", (long)pcm->period_step);
-       snd_output_printf(out, "sleep_min    : %ld\n", (long)pcm->sleep_min);
-       snd_output_printf(out, "avail_min    : %ld\n", (long)pcm->avail_min);
-       snd_output_printf(out, "xfer_align   : %ld\n", (long)pcm->xfer_align);
-       snd_output_printf(out, "silence_threshold: %ld\n", (long)pcm->silence_threshold);
-       snd_output_printf(out, "silence_size : %ld\n", (long)pcm->silence_size);
-       snd_output_printf(out, "boundary     : %ld\n", (long)pcm->boundary);
+       snd_output_printf(out, "period_step  : %d\n", pcm->period_step);
+       snd_output_printf(out, "sleep_min    : %d\n", pcm->sleep_min);
+       snd_output_printf(out, "avail_min    : %ld\n", pcm->avail_min);
+       snd_output_printf(out, "xfer_align   : %ld\n", pcm->xfer_align);
+       snd_output_printf(out, "start_threshold  : %ld\n", pcm->start_threshold);
+       snd_output_printf(out, "stop_threshold   : %ld\n", pcm->stop_threshold);
+       snd_output_printf(out, "silence_threshold: %ld\n", pcm->silence_threshold);
+       snd_output_printf(out, "silence_size : %ld\n", pcm->silence_size);
+       snd_output_printf(out, "boundary     : %ld\n", pcm->boundary);
        return 0;
 }
 
@@ -3287,13 +3291,13 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 {
        assert(pcm && params);
        assert(pcm->setup);
-       params->start_mode = snd_enum_to_int(pcm->start_mode);
-       params->xrun_mode = snd_enum_to_int(pcm->xrun_mode);
        params->tstamp_mode = snd_enum_to_int(pcm->tstamp_mode);
        params->period_step = pcm->period_step;
        params->sleep_min = pcm->sleep_min;
        params->avail_min = pcm->avail_min;
        params->xfer_align = pcm->xfer_align;
+       params->start_threshold = pcm->start_threshold;
+       params->stop_threshold = pcm->stop_threshold;
        params->silence_threshold = pcm->silence_threshold;
        params->silence_size = pcm->silence_size;
        params->boundary = pcm->boundary;
@@ -3365,34 +3369,48 @@ void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t
 }
 
 /**
- * \brief Set start mode inside a software configuration container
+ * \brief (DEPRECATED) Set start mode inside a software configuration container
  * \param pcm PCM handle
  * \param params Software configuration container
  * \param val Start mode
  * \return 0 otherwise a negative error code
  */
-int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_start_t val)
+int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val)
 {
        assert(pcm && params);
-       assert(val <= SND_PCM_START_LAST);
-       params->start_mode = snd_enum_to_int(val);
+       switch (val) {
+       case SND_PCM_START_DATA:
+               params->start_threshold = 1;
+               break;
+       case SND_PCM_START_EXPLICIT:
+               params->start_threshold = pcm->boundary;
+               break;
+       default:
+               assert(0);
+               break;
+       }
        return 0;
 }
 
+link_warning(snd_pcm_sw_params_set_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold");
+
 /**
- * \brief Get start mode from a software configuration container
+ * \brief (DEPRECATED) Get start mode from a software configuration container
  * \param params Software configuration container
  * \return start mode
  */
 snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params)
 {
        assert(params);
-       return snd_int_to_enum(params->start_mode);
+       /* FIXME: Ugly */
+       return params->start_threshold > 1024 * 1024 ? SND_PCM_START_EXPLICIT : SND_PCM_START_DATA;
 }
 
+link_warning(snd_pcm_sw_params_get_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold");
+
 
 /**
- * \brief Set xrun mode inside a software configuration container
+ * \brief (DEPRECATED) Set xrun mode inside a software configuration container
  * \param pcm PCM handle
  * \param params Software configuration container
  * \param val Xrun mode
@@ -3401,22 +3419,35 @@ snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *para
 int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val)
 {
        assert(pcm && params);
-       assert(val <= SND_PCM_XRUN_LAST);
-       params->xrun_mode = snd_enum_to_int(val);
+       switch (val) {
+       case SND_PCM_XRUN_STOP:
+               params->stop_threshold = pcm->buffer_size;
+               break;
+       case SND_PCM_XRUN_NONE:
+               params->stop_threshold = pcm->boundary;
+               break;
+       default:
+               assert(0);
+               break;
+       }
        return 0;
 }
 
+link_warning(snd_pcm_sw_params_set_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
+
 /**
- * \brief Get xrun mode from a software configuration container
+ * \brief (DEPRECATED) Get xrun mode from a software configuration container
  * \param params Software configuration container
  * \return xrun mode
  */
 snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params)
 {
        assert(params);
-       return snd_int_to_enum(params->xrun_mode);
+       /* FIXME: Ugly */
+       return params->stop_threshold > 1024 * 1024 ? SND_PCM_XRUN_NONE : SND_PCM_XRUN_STOP;
 }
 
+link_warning(snd_pcm_sw_params_get_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
 
 /**
  * \brief Set timestamp mode inside a software configuration container
@@ -3539,6 +3570,68 @@ snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *pa
 }
 
 
+/**
+ * \brief Set start threshold inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Start threshold in frames 
+ * \return 0 otherwise a negative error code
+ *
+ * PCM is automatically started when playback frames available to PCM 
+ * are >= threshold or when requested capture frames are >= threshold
+ */
+int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
+{
+       assert(pcm && params);
+       params->start_threshold = val;
+       return 0;
+}
+
+/**
+ * \brief Get start threshold from a software configuration container
+ * \param params Software configuration container
+ * \return Start threshold in frames
+ *
+ * PCM is automatically started when playback frames available to PCM 
+ * are >= threshold or when requested capture frames are >= threshold
+ */
+snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params)
+{
+       assert(params);
+       return params->start_threshold;
+}
+
+/**
+ * \brief Set stop threshold inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Stop threshold in frames
+ * \return 0 otherwise a negative error code
+ *
+ * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available
+ * frames is >= threshold
+ */
+int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
+{
+       assert(pcm && params);
+       params->stop_threshold = val;
+       return 0;
+}
+
+/**
+ * \brief Get stop threshold from a software configuration container
+ * \param params Software configuration container
+ * \return Stop threshold in frames
+ *
+ * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available
+ * frames is >= threshold
+ */
+snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params)
+{
+       assert(params);
+       return params->stop_threshold;
+}
+
 /**
  * \brief Set silence threshold inside a software configuration container
  * \param pcm PCM handle
@@ -4015,7 +4108,7 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
 
        switch (snd_enum_to_int(state)) {
        case SND_PCM_STATE_PREPARED:
-               if (pcm->start_mode == SND_PCM_START_DATA) {
+               if (size >= pcm->start_threshold) {
                        err = snd_pcm_start(pcm);
                        if (err < 0)
                                goto _end;
@@ -4156,11 +4249,14 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
                        goto _end;
                }
 #endif
-               if (state == SND_PCM_STATE_PREPARED &&
-                   pcm->start_mode == SND_PCM_START_DATA) {
-                       err = snd_pcm_start(pcm);
-                       if (err < 0)
-                               goto _end;
+               if (state == SND_PCM_STATE_PREPARED) {
+                       snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail;
+                       hw_avail += frames;
+                       if (hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) {
+                               err = snd_pcm_start(pcm);
+                               if (err < 0)
+                                       goto _end;
+                       }
                }
        }
  _end:
index 0adf5ca6414f1d0e4f5580d27b3dd78f60a2a11b..1c1e51a90893f9df5b7724172d77fd9cc59d9307 100644 (file)
@@ -151,12 +151,12 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 {
        snd_pcm_hw_t *hw = pcm->private_data;
        int fd = hw->fd;
-       if ((snd_pcm_start_t) params->start_mode == pcm->start_mode &&
-           (snd_pcm_xrun_t) params->xrun_mode == pcm->xrun_mode &&
-           (snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
+       if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
            params->period_step == pcm->period_step &&
            params->sleep_min == pcm->sleep_min &&
            params->xfer_align == pcm->xfer_align &&
+           params->start_threshold == pcm->start_threshold &&
+           params->stop_threshold == pcm->stop_threshold &&
            params->silence_threshold == pcm->silence_threshold &&
            params->silence_size == pcm->silence_size) {
                hw->mmap_control->avail_min = params->avail_min;
index 0d68bc2b3394bec671e5f8cfeb8bdbd0d7468e7e..7c36f2c993e4fc45779ff27d6e405ea1907db8fb 100644 (file)
@@ -132,12 +132,12 @@ struct _snd_pcm {
        snd_pcm_uframes_t period_size;
        unsigned int period_time;       /* period duration */
        unsigned int tick_time;
-       snd_pcm_start_t start_mode;     /* start mode */
-       snd_pcm_xrun_t xrun_mode;       /* xrun detection mode */
        snd_pcm_tstamp_t tstamp_mode;   /* timestamp mode */
        unsigned int period_step;
        unsigned int sleep_min;
        snd_pcm_uframes_t avail_min;    /* min avail frames for wakeup */
+       snd_pcm_uframes_t start_threshold;      
+       snd_pcm_uframes_t stop_threshold;       
        snd_pcm_uframes_t silence_threshold;    /* Silence filling happens when
                                           noise is nearest than this */
        snd_pcm_uframes_t silence_size; /* Silence filling size */
index bd3f6a16e4858e5d72287e3eb70bf0efed15197a..387ad4cd60df656c20750ac489458d75286cc0fb 100644 (file)
@@ -117,7 +117,9 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
        assert(null->state == SND_PCM_STATE_PREPARED);
        null->state = SND_PCM_STATE_RUNNING;
        if (pcm->stream == SND_PCM_STREAM_CAPTURE)
-               snd_pcm_mmap_appl_forward(pcm, pcm->buffer_size);
+               *pcm->hw_ptr = *pcm->appl_ptr + pcm->buffer_size;
+       else
+               *pcm->hw_ptr = *pcm->appl_ptr;
        return 0;
 }
 
@@ -153,10 +155,11 @@ static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f
 {
        snd_pcm_null_t *null = pcm->private_data;
        switch (snd_enum_to_int(null->state)) {
-       case SND_PCM_STATE_PREPARED:
        case SND_PCM_STATE_RUNNING:
-               snd_pcm_mmap_appl_backward(pcm, frames);
                snd_pcm_mmap_hw_backward(pcm, frames);
+               /* Fall through */
+       case SND_PCM_STATE_PREPARED:
+               snd_pcm_mmap_appl_backward(pcm, frames);
                return frames;
        default:
                return -EBADFD;
@@ -167,56 +170,45 @@ static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size
 {
        snd_pcm_null_t *null = pcm->private_data;
        switch (snd_enum_to_int(null->state)) {
-       case SND_PCM_STATE_PREPARED:
        case SND_PCM_STATE_RUNNING:
-               snd_pcm_mmap_appl_forward(pcm, size);
                snd_pcm_mmap_hw_forward(pcm, size);
+               /* Fall through */
+       case SND_PCM_STATE_PREPARED:
+               snd_pcm_mmap_appl_forward(pcm, size);
                return size;
        default:
                return -EBADFD;
        }
 }
 
+static snd_pcm_uframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
+                                                const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
+                                                snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+                                                snd_pcm_uframes_t size)
+{
+       snd_pcm_mmap_appl_forward(pcm, size);
+       snd_pcm_mmap_hw_forward(pcm, size);
+       return size;
+}
+
 static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
 {
-       snd_pcm_null_t *null = pcm->private_data;
-       if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->start_mode != SND_PCM_START_EXPLICIT) {
-               null->state = SND_PCM_STATE_RUNNING;
-       }
-       return snd_pcm_null_fwd(pcm, size);
+       return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
 }
 
 static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
 {
-       snd_pcm_null_t *null = pcm->private_data;
-       if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->start_mode != SND_PCM_START_EXPLICIT) {
-               null->state = SND_PCM_STATE_RUNNING;
-       }
-       return snd_pcm_null_fwd(pcm, size);
+       return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
 }
 
 static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
 {
-       snd_pcm_null_t *null = pcm->private_data;
-       if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->start_mode != SND_PCM_START_EXPLICIT) {
-               null->state = SND_PCM_STATE_RUNNING;
-               snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
-       }
-       return snd_pcm_null_fwd(pcm, size);
+       return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
 }
 
 static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
 {
-       snd_pcm_null_t *null = pcm->private_data;
-       if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->start_mode != SND_PCM_START_EXPLICIT) {
-               null->state = SND_PCM_STATE_RUNNING;
-               snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
-       }
-       return snd_pcm_null_fwd(pcm, size);
+       return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
 }
 
 static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
index e9685111ed700201c279a98cf2efa0d9d17a7dd7..ac7099c929398a71bcf39bb338e9783d1a71a664 100644 (file)
@@ -2022,13 +2022,13 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params
 {
        assert(pcm && params);
        assert(pcm->setup);
-       params->start_mode = snd_enum_to_int(SND_PCM_START_DATA);
-       params->xrun_mode = snd_enum_to_int(SND_PCM_XRUN_STOP);
        params->tstamp_mode = snd_enum_to_int(SND_PCM_TSTAMP_NONE);
        params->period_step = 1;
        params->sleep_min = 0;
        params->avail_min = pcm->period_size;
        params->xfer_align = pcm->period_size;
+       params->start_threshold = 1;
+       params->stop_threshold = pcm->buffer_size;
        params->silence_threshold = 0;
        params->silence_size = 0;
        params->boundary = pcm->buffer_size;
index 873d18103eb3545d682291a65c2d2aea4eb1f502..69e78b716f36becac8aa46e8b4a7c6286bbc087d 100644 (file)
@@ -182,7 +182,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *sla
    - draining silencing
    - return distance in frames to next event
 */
-static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
+static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm)
 {
        snd_pcm_share_t *share = pcm->private_data;
        snd_pcm_share_slave_t *slave = share->slave;
@@ -204,12 +204,12 @@ static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
        default:
                return INT_MAX;
        }
-       if (slave_xrun && pcm->xrun_mode != SND_PCM_XRUN_NONE) {
+       share->hw_ptr = slave->hw_ptr;
+       avail = snd_pcm_mmap_avail(pcm);
+       if (avail >= pcm->stop_threshold) {
                _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
                goto update_poll;
        }
-       share->hw_ptr = slave->hw_ptr;
-       avail = snd_pcm_mmap_avail(pcm);
        hw_avail = buffer_size - avail;
        slave_avail = snd_pcm_share_slave_avail(slave);
        if (avail < slave_avail) {
@@ -247,18 +247,18 @@ static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
                }
                break;
        case SND_PCM_STATE_RUNNING:
-               if (pcm->xrun_mode != SND_PCM_XRUN_NONE) {
-                       if (hw_avail <= 0) {
-                               _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
-                               break;
-                       }
-                       if ((snd_pcm_uframes_t)hw_avail < missing)
-                               missing = hw_avail;
+               if (avail >= pcm->stop_threshold) {
+                       _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
+                       break;
+               } else {
+                       snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail;
+                       if (missing > xrun_missing)
+                               missing = xrun_missing;
                }
                ready_missing = pcm->avail_min - avail;
                if (ready_missing > 0) {
                        ready = 0;
-                       if ((snd_pcm_uframes_t)ready_missing < missing)
+                       if (missing > (snd_pcm_uframes_t)ready_missing)
                                missing = ready_missing;
                }
                running = 1;
@@ -322,12 +322,11 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *sla
        snd_pcm_uframes_t missing = INT_MAX;
        struct list_head *i;
        snd_pcm_sframes_t avail = snd_pcm_avail_update(slave->pcm);
-       int slave_xrun = (avail == -EPIPE);
        slave->hw_ptr = *slave->pcm->hw_ptr;
        list_for_each(i, &slave->clients) {
                snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
                snd_pcm_t *pcm = share->pcm;
-               snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm, slave_xrun);
+               snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm);
                if (m < missing)
                        missing = m;
        }
@@ -396,7 +395,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
        snd_pcm_uframes_t missing;
        snd_pcm_sframes_t avail = snd_pcm_avail_update(spcm);
        slave->hw_ptr = *slave->pcm->hw_ptr;
-       missing = _snd_pcm_share_missing(pcm, avail == -EPIPE);
+       missing = _snd_pcm_share_missing(pcm);
        if (!slave->polling) {
                pthread_cond_signal(&slave->poll_cond);
                return;