aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2011-10-14 11:12:24 -0700
committerEric Laurent <elaurent@google.com>2011-10-14 11:35:43 -0700
commit73b9c679a656c7b0f5e265dae5a76664c7d03031 (patch)
treec4778fe02eff8c7f8512f7426fbd17648e4934e6
parente9942c8b1fab1cea4836b5af2dd59a1bf0ad411d (diff)
downloadtinyalsa-ics-mr0.tar.gz
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
-rw-r--r--include/tinyalsa/asoundlib.h5
-rw-r--r--pcm.c80
2 files changed, 63 insertions, 22 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index 3c86c84..741c466 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -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 d12e5da..dbf68e4 100644
--- 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;