]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-external-tinyalsa.git/commitdiff
Add dynamic change of avail_min for mmap mode
authorEric Laurent <elaurent@google.com>
Fri, 14 Oct 2011 18:12:24 +0000 (11:12 -0700)
committerEric Laurent <elaurent@google.com>
Fri, 14 Oct 2011 18:35:43 +0000 (11:35 -0700)
Added support for setting avail_min when opening a stream as well
as dynamically changing its value whitout stopping playback when the
stream is opened in mmap and no irq mode.

Allow writing less than avail_min frames to pcm_mmap_write() without
systematically waiting for avail_min frames to be available.

Also fixed wait timeout for no irq mode in pcm_mmap_write().

Change-Id: Ief8e05dde8d538185174da9ef14e27a0a470057c

include/tinyalsa/asoundlib.h
pcm.c

index 3c86c844733dc9b61471a9e9cab0a061959c80a3..741c46641cd31967a6019c0d666b40db9c6eef32 100644 (file)
@@ -84,6 +84,7 @@ struct pcm_config {
     unsigned int start_threshold;
     unsigned int stop_threshold;
     unsigned int silence_threshold;
+    int avail_min;
 };
 
 /* Mixer control types */
@@ -150,6 +151,10 @@ int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
 int pcm_start(struct pcm *pcm);
 int pcm_stop(struct pcm *pcm);
 
+/* Change avail_min after the stream has been opened with no need to stop the stream.
+ * Only accepted if opened with PCM_MMAP and PCM_NOIRQ flags
+ */
+int pcm_set_avail_min(struct pcm *pcm, int avail_min);
 
 /*
  * MIXER API
diff --git a/pcm.c b/pcm.c
index d12e5daa2147b15b2d23836036a6256040dca6a1..dbf68e4768ea2623fdeb84585e59dbf76759b7f1 100644 (file)
--- a/pcm.c
+++ b/pcm.c
@@ -156,6 +156,7 @@ struct pcm {
     struct snd_pcm_sync_ptr *sync_ptr;
     void *mmap_buffer;
     unsigned int noirq_frames_per_msec;
+    int wait_for_avail_min;
 };
 
 unsigned int pcm_get_buffer_size(struct pcm *pcm)
@@ -249,7 +250,10 @@ static int pcm_hw_mmap_status(struct pcm *pcm) {
         pcm->mmap_status = NULL;
         goto mmap_error;
     }
-    pcm->mmap_control->avail_min = 1;
+    if (pcm->flags & PCM_MMAP)
+        pcm->mmap_control->avail_min = pcm->config.avail_min;
+    else
+        pcm->mmap_control->avail_min = 1;
 
     return 0;
 
@@ -260,7 +264,11 @@ mmap_error:
         return -ENOMEM;
     pcm->mmap_status = &pcm->sync_ptr->s.status;
     pcm->mmap_control = &pcm->sync_ptr->c.control;
-    pcm->mmap_control->avail_min = 1;
+    if (pcm->flags & PCM_MMAP)
+        pcm->mmap_control->avail_min = pcm->config.avail_min;
+    else
+        pcm->mmap_control->avail_min = 1;
+
     pcm_sync_ptr(pcm, 0);
 
     return 0;
@@ -344,7 +352,9 @@ int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
         frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
 
     if (frames < 0)
-        return -1;
+        frames += pcm->boundary;
+    else if (frames > (int)pcm->boundary)
+        frames -= pcm->boundary;
 
     *avail = (unsigned int)frames;
 
@@ -529,7 +539,6 @@ struct pcm *pcm_open(unsigned int card, unsigned int device,
     memset(&sparams, 0, sizeof(sparams));
     sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
     sparams.period_step = 1;
-    sparams.avail_min = 1;
 
     if (!config->start_threshold)
         pcm->config.start_threshold = sparams.start_threshold =
@@ -544,6 +553,14 @@ struct pcm *pcm_open(unsigned int card, unsigned int device,
     else
         sparams.stop_threshold = config->stop_threshold;
 
+    if (!pcm->config.avail_min) {
+        if (pcm->flags & PCM_MMAP)
+            pcm->config.avail_min = sparams.avail_min = pcm->config.period_size;
+        else
+            pcm->config.avail_min = sparams.avail_min = 1;
+    } else
+        sparams.avail_min = config->avail_min;
+
     sparams.xfer_align = config->period_size / 2; /* needed for old kernels */
     sparams.silence_size = 0;
     sparams.silence_threshold = config->silence_threshold;
@@ -697,6 +714,15 @@ int pcm_state(struct pcm *pcm)
     return pcm->mmap_status->state;
 }
 
+int pcm_set_avail_min(struct pcm *pcm, int avail_min)
+{
+    if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ))
+        return -ENOSYS;
+
+    pcm->config.avail_min = avail_min;
+    return 0;
+}
+
 int pcm_wait(struct pcm *pcm, int timeout)
 {
     struct pollfd pfd;
@@ -768,28 +794,38 @@ int pcm_mmap_write(struct pcm *pcm, void *buffer, unsigned int bytes)
                     avail);
                 return -errno;
             }
+            pcm->wait_for_avail_min = 0;
         }
 
         /* sleep until we have space to write new frames */
-        if (pcm->running &&
-            (unsigned int)avail < pcm->mmap_control->avail_min) {
-            int time = -1;
-
-            if (pcm->flags & PCM_NOIRQ)
-                time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min)
-                        / pcm->noirq_frames_per_msec;
-
-            err = pcm_wait(pcm, time);
-            if (err < 0) {
-                pcm->running = 0;
-                fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
-                    (unsigned int)pcm->mmap_status->hw_ptr,
-                    (unsigned int)pcm->mmap_control->appl_ptr,
-                    avail);
-                pcm->mmap_control->appl_ptr = 0;
-                return err;
+        if (pcm->running) {
+            /* enable waiting for avail_min threshold when less frames than we have to write
+             * are available. */
+            if (!pcm->wait_for_avail_min && (count > (unsigned int)avail))
+                pcm->wait_for_avail_min = 1;
+
+            if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) {
+                int time = -1;
+
+                /* disable waiting for avail_min threshold to allow small amounts of data to be
+                 * written without waiting as long as there is enough room in buffer. */
+                pcm->wait_for_avail_min = 0;
+
+                if (pcm->flags & PCM_NOIRQ)
+                    time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec;
+
+                err = pcm_wait(pcm, time);
+                if (err < 0) {
+                    pcm->running = 0;
+                    oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
+                        (unsigned int)pcm->mmap_status->hw_ptr,
+                        (unsigned int)pcm->mmap_control->appl_ptr,
+                        avail);
+                    pcm->mmap_control->appl_ptr = 0;
+                    return err;
+                }
+                continue;
             }
-            continue;
         }
 
         frames = count;