From 744c8798c06510a79c10128a2839d00e7a0ba738 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Mon, 15 Jan 2001 11:06:55 +0000 Subject: [PATCH] New PCM model with fragment concept removal and two interrupt sources Renamed size_t/ssize_t to snd_pcm_sframes_t/snd_pcm_uframes_t --- aplay/aplay.c | 197 +++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 97 deletions(-) diff --git a/aplay/aplay.c b/aplay/aplay.c index d3887e6..3428150 100644 --- a/aplay/aplay.c +++ b/aplay/aplay.c @@ -69,22 +69,21 @@ static struct { static int timelimit = 0; static int quiet_mode = 0; static int file_type = FORMAT_DEFAULT; -static int xrun_mode = SND_PCM_XRUN_FRAGMENT; -static int ready_mode = SND_PCM_READY_FRAGMENT; +static unsigned int sleep_min = 0; static int open_mode = 0; static int stream = SND_PCM_STREAM_PLAYBACK; static int mmap_flag = 0; static int interleaved = 1; static int nonblock = 0; static char *audiobuf = NULL; -static int buffer_size = -1; -static int frag_length = 125000; -static int buffer_length = 500000; -static int avail_min = 50000; +static int chunk_size = -1; +static int period_time = -1; +static int buffer_time = -1; +static int avail_min = -1; static int verbose = 0; static int buffer_pos = 0; static size_t bits_per_sample, bits_per_frame; -static size_t buffer_bytes; +static size_t chunk_bytes; static int digtype = SND_CONTROL_TYPE_NONE; static snd_digital_audio_t diga; @@ -146,11 +145,11 @@ Usage: %s [OPTION]... [FILE]... -f, --format=FORMAT sample format (case insensitive) -r, --rate=# sample rate -d, --duration=# interrupt after # seconds --e, --frame-mode use frame mode instead of default fragment mode +-s, --sleep-min=# min ticks to sleep -M, --mmap mmap stream -N, --nonblock nonblocking mode --F, --fragment-length=# fragment length is # microseconds --B, --buffer-length=# buffer length is # microseconds +-F, --period-time=# distance between interrupts is # microseconds +-B, --buffer-time=# buffer duration is # microseconds -A, --avail-min=# min available space for wakeup is # microseconds -X, --xfer-min=# min xfer size is # microseconds -v, --verbose show PCM structure and setup @@ -257,7 +256,7 @@ static void version(void) int main(int argc, char *argv[]) { int option_index; - char *short_options = "lLD:qt:c:f:r:d:eMNF:A:X:B:vIPC"; + char *short_options = "lLD:qt:c:f:r:d:s:MNF:A:X:B:vIPC"; static struct option long_options[] = { {"help", 0, 0, OPT_HELP}, {"version", 0, 0, OPT_VERSION}, @@ -270,13 +269,13 @@ int main(int argc, char *argv[]) {"format", 1, 0, 'f'}, {"rate", 1, 0, 'r'}, {"duration", 1, 0 ,'d'}, - {"asap-mode", 0, 0, 'e'}, + {"sleep-min", 0, 0, 's'}, {"mmap", 0, 0, 'M'}, {"nonblock", 0, 0, 'N'}, - {"fragment-length", 1, 0, 'F'}, + {"period_time", 1, 0, 'F'}, {"avail-min", 1, 0, 'A'}, {"xfer-min", 1, 0, 'X'}, - {"buffer-length", 1, 0, 'B'}, + {"buffer-time", 1, 0, 'B'}, {"verbose", 0, 0, 'v'}, {"iec958c", 0, 0, 'C'}, {"iec958p", 0, 0, 'P'}, @@ -300,7 +299,7 @@ int main(int argc, char *argv[]) return 1; } - buffer_size = -1; + chunk_size = -1; rhwparams.format = SND_PCM_FORMAT_U8; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; @@ -375,19 +374,18 @@ int main(int argc, char *argv[]) case 'd': timelimit = atoi(optarg); break; - case 'e': - xrun_mode = SND_PCM_XRUN_ASAP; - ready_mode = SND_PCM_READY_ASAP; + case 's': + sleep_min = atoi(optarg); break; case 'N': nonblock = 1; open_mode |= SND_PCM_NONBLOCK; break; case 'F': - frag_length = atoi(optarg); + period_time = atoi(optarg); break; case 'B': - buffer_length = atoi(optarg); + buffer_time = atoi(optarg); break; case 'A': avail_min = atoi(optarg); @@ -476,7 +474,7 @@ int main(int argc, char *argv[]) } } - buffer_size = 1024; + chunk_size = 1024; hwparams = rhwparams; audiobuf = (char *)malloc(1024); @@ -711,9 +709,10 @@ static void set_params(void) { snd_pcm_hw_params_t params; snd_pcm_sw_params_t swparams; - size_t bufsize; + size_t buffer_size; int err; size_t n; + size_t xfer_align; err = snd_pcm_hw_params_any(handle, ¶ms); if (err < 0) { error("Broken configuration for this PCM: no configurations available"); @@ -730,69 +729,73 @@ static void set_params(void) } else if (interleaved) err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_ACCESS, - SND_PCM_ACCESS_RW_INTERLEAVED); + SND_PCM_ACCESS_RW_INTERLEAVED, 0); else err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_ACCESS, - SND_PCM_ACCESS_RW_NONINTERLEAVED); + SND_PCM_ACCESS_RW_NONINTERLEAVED, 0); if (err < 0) { error("Access type not available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_FORMAT, - hwparams.format); + hwparams.format, 0); if (err < 0) { error("Sample format non available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_CHANNELS, - hwparams.channels); + hwparams.channels, 0); if (err < 0) { error("Channels count non available"); exit(EXIT_FAILURE); } +#if 0 err = snd_pcm_hw_param_min(handle, ¶ms, - SND_PCM_HW_PARAM_FRAGMENTS, 2); - assert(err >= 0); - err = snd_pcm_hw_param_near(handle, ¶ms, - SND_PCM_HW_PARAM_RATE, hwparams.rate); - assert(err >= 0); - err = snd_pcm_hw_param_near(handle, ¶ms, - SND_PCM_HW_PARAM_FRAGMENT_LENGTH, - frag_length); + SND_PCM_HW_PARAM_PERIODS, 2); assert(err >= 0); +#endif err = snd_pcm_hw_param_near(handle, ¶ms, - SND_PCM_HW_PARAM_BUFFER_LENGTH, - buffer_length); + SND_PCM_HW_PARAM_RATE, hwparams.rate, 0); assert(err >= 0); + if (buffer_time < 0) + buffer_time = 500000; + buffer_time = snd_pcm_hw_param_near(handle, ¶ms, + SND_PCM_HW_PARAM_BUFFER_TIME, + buffer_time, 0); + assert(buffer_time >= 0); + if (period_time < 0) + period_time = buffer_time / 4; + period_time = snd_pcm_hw_param_near(handle, ¶ms, + SND_PCM_HW_PARAM_PERIOD_TIME, + period_time, 0); + assert(period_time >= 0); err = snd_pcm_hw_params(handle, ¶ms); if (err < 0) { fprintf(stderr, "Unable to install hw params:\n"); snd_pcm_hw_params_dump(¶ms, stderr); exit(EXIT_FAILURE); } - buffer_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_FRAGMENT_SIZE); - bufsize = buffer_size * snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_FRAGMENTS); - + chunk_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_PERIOD_SIZE, 0); + buffer_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_BUFFER_SIZE, 0); snd_pcm_sw_params_current(handle, &swparams); + xfer_align = snd_pcm_sw_param_value(&swparams, SND_PCM_SW_PARAM_XFER_ALIGN); + if (sleep_min) + xfer_align = 1; err = snd_pcm_sw_param_set(handle, &swparams, - SND_PCM_SW_PARAM_READY_MODE, ready_mode); + SND_PCM_SW_PARAM_SLEEP_MIN, sleep_min); assert(err >= 0); - err = snd_pcm_sw_param_set(handle, &swparams, - SND_PCM_SW_PARAM_XRUN_MODE, xrun_mode); - assert(err >= 0); - n = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_RATE) * avail_min / 1000000; - if (n > bufsize - buffer_size) - n = bufsize - buffer_size; + if (avail_min < 0) + n = chunk_size; + else + n = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_RATE, 0) * (double) avail_min / 1000000; err = snd_pcm_sw_param_near(handle, &swparams, SND_PCM_SW_PARAM_AVAIL_MIN, n); - if (xrun_mode == SND_PCM_XRUN_ASAP) { - err = snd_pcm_sw_param_near(handle, &swparams, - SND_PCM_SW_PARAM_XFER_ALIGN, 1); - assert(err >= 0); - } + err = snd_pcm_sw_param_near(handle, &swparams, + SND_PCM_SW_PARAM_XFER_ALIGN, xfer_align); + assert(err >= 0); if (snd_pcm_sw_params(handle, &swparams) < 0) { error("unable to install sw params:"); snd_pcm_sw_params_dump(&swparams, stderr); @@ -808,13 +811,13 @@ static void set_params(void) bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_frame = bits_per_sample * hwparams.channels; - buffer_bytes = buffer_size * bits_per_frame / 8; - audiobuf = realloc(audiobuf, buffer_bytes); + chunk_bytes = chunk_size * bits_per_frame / 8; + audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { error("not enough memory"); exit(EXIT_FAILURE); } - // fprintf(stderr, "real buffer_size = %i, frags = %i, total = %i\n", buffer_size, setup.buf.block.frags, setup.buf.block.frags * buffer_size); + // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); } /* playback write error hander */ @@ -857,10 +860,10 @@ static ssize_t pcm_write(u_char *data, size_t count) ssize_t r; ssize_t result = 0; - if (xrun_mode == SND_PCM_XRUN_FRAGMENT && - count < buffer_size) { - snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (buffer_size - count) * hwparams.channels); - count = buffer_size; + if (sleep_min == 0 && + count < chunk_size) { + snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (chunk_size - count) * hwparams.channels); + count = chunk_size; } while (count > 0) { r = writei_func(handle, data, count); @@ -886,14 +889,14 @@ static ssize_t pcm_writev(u_char **data, unsigned int channels, size_t count) ssize_t r; size_t result = 0; - if (xrun_mode == SND_PCM_XRUN_FRAGMENT && - count != buffer_size) { + if (sleep_min == 0 && + count != chunk_size) { unsigned int channel; size_t offset = count; - size_t remaining = buffer_size - count; + size_t remaining = chunk_size - count; for (channel = 0; channel < channels; channel++) snd_pcm_format_set_silence(hwparams.format, data[channel] + offset * bits_per_sample / 8, remaining); - count = buffer_size; + count = chunk_size; } while (count > 0) { unsigned int channel; @@ -928,9 +931,9 @@ static ssize_t pcm_read(u_char *data, size_t rcount) size_t result = 0; size_t count = rcount; - if (xrun_mode == SND_PCM_XRUN_FRAGMENT && - count != buffer_size) { - count = buffer_size; + if (sleep_min == 0 && + count != chunk_size) { + count = chunk_size; } while (count > 0) { @@ -958,9 +961,9 @@ static ssize_t pcm_readv(u_char **data, unsigned int channels, size_t rcount) size_t result = 0; size_t count = rcount; - if (xrun_mode == SND_PCM_XRUN_FRAGMENT && - count != buffer_size) { - count = buffer_size; + if (sleep_min == 0 && + count != chunk_size) { + count = chunk_size; } while (count > 0) { @@ -997,14 +1000,14 @@ static ssize_t voc_pcm_write(u_char *data, size_t count) while (count > 0) { size = count; - if (size > buffer_bytes - buffer_pos) - size = buffer_bytes - buffer_pos; + if (size > chunk_bytes - buffer_pos) + size = chunk_bytes - buffer_pos; memcpy(audiobuf + buffer_pos, data, size); data += size; count -= size; buffer_pos += size; - if (buffer_pos == buffer_bytes) { - if ((r = pcm_write(audiobuf, buffer_size)) != buffer_size) + if (buffer_pos == chunk_bytes) { + if ((r = pcm_write(audiobuf, chunk_size)) != chunk_size) return r; buffer_pos = 0; } @@ -1017,16 +1020,16 @@ static void voc_write_silence(unsigned x) unsigned l; char *buf; - buf = (char *) malloc(buffer_bytes); + buf = (char *) malloc(chunk_bytes); if (buf == NULL) { error("can't allocate buffer for silence"); return; /* not fatal error */ } - snd_pcm_format_set_silence(hwparams.format, buf, buffer_size * hwparams.channels); + snd_pcm_format_set_silence(hwparams.format, buf, chunk_size * hwparams.channels); while (x > 0) { l = x; - if (l > buffer_size) - l = buffer_size; + if (l > chunk_size) + l = chunk_size; if (voc_pcm_write(buf, l) != l) { error("write error"); exit(EXIT_FAILURE); @@ -1039,10 +1042,10 @@ static void voc_pcm_flush(void) { if (buffer_pos > 0) { size_t b; - if (xrun_mode == SND_PCM_XRUN_FRAGMENT) { - if (snd_pcm_format_set_silence(hwparams.format, audiobuf + buffer_pos, buffer_bytes - buffer_pos * 8 / bits_per_sample) < 0) + if (sleep_min == 0) { + if (snd_pcm_format_set_silence(hwparams.format, audiobuf + buffer_pos, chunk_bytes - buffer_pos * 8 / bits_per_sample) < 0) fprintf(stderr, "voc_pcm_flush - silence error"); - b = buffer_size; + b = chunk_size; } else { b = buffer_pos * 8 / bits_per_frame; } @@ -1078,12 +1081,12 @@ static void voc_play(int fd, int ofs, char *name) fprintf(stderr, "Playing Creative Labs Channel file '%s'...\n", name); } /* first we waste the rest of header, ugly but we don't need seek */ - while (ofs > buffer_bytes) { - if (safe_read(fd, buf, buffer_bytes) != buffer_bytes) { + while (ofs > chunk_bytes) { + if (safe_read(fd, buf, chunk_bytes) != chunk_bytes) { error("read error"); exit(EXIT_FAILURE); } - ofs -= buffer_bytes; + ofs -= chunk_bytes; } if (ofs) { if (safe_read(fd, buf, ofs) != ofs) { @@ -1104,7 +1107,7 @@ static void voc_play(int fd, int ofs, char *name) if (in_buffer) memcpy(buf, data, in_buffer); data = buf; - if ((l = safe_read(fd, buf + in_buffer, buffer_bytes - in_buffer)) > 0) + if ((l = safe_read(fd, buf + in_buffer, chunk_bytes - in_buffer)) > 0) in_buffer += l; else if (!in_buffer) { /* the file is truncated, so simulate 'Terminator' @@ -1482,11 +1485,11 @@ void playback_go(int fd, size_t loaded, size_t count, int rtype, char *name) header(rtype, name); set_params(); - while (loaded > buffer_bytes && written < count) { - if (pcm_write(audiobuf + written, buffer_size) <= 0) + while (loaded > chunk_bytes && written < count) { + if (pcm_write(audiobuf + written, chunk_size) <= 0) return; - written += buffer_bytes; - loaded -= buffer_bytes; + written += chunk_bytes; + loaded -= chunk_bytes; } if (written > 0 && loaded > 0) memmove(audiobuf, audiobuf + written, loaded); @@ -1495,8 +1498,8 @@ void playback_go(int fd, size_t loaded, size_t count, int rtype, char *name) while (written < count) { do { c = count - written; - if (c > buffer_bytes) - c = buffer_bytes; + if (c > chunk_bytes) + c = chunk_bytes; c -= l; if (c == 0) @@ -1509,7 +1512,7 @@ void playback_go(int fd, size_t loaded, size_t count, int rtype, char *name) if (r == 0) break; l += r; - } while (xrun_mode != SND_PCM_XRUN_ASAP && l < buffer_bytes); + } while (sleep_min == 0 && l < chunk_bytes); l = l * 8 / bits_per_frame; r = pcm_write(audiobuf, l); if (r != l) @@ -1533,8 +1536,8 @@ void capture_go(int fd, size_t count, int rtype, char *name) while (count > 0) { c = count; - if (c > buffer_bytes) - c = buffer_bytes; + if (c > chunk_bytes) + c = chunk_bytes; c = c * 8 / bits_per_frame; if ((r = pcm_read(audiobuf, c)) != c) break; @@ -1635,7 +1638,7 @@ void playbackv_go(int* fds, unsigned int channels, size_t loaded, size_t count, header(rtype, names[0]); set_params(); - vsize = buffer_bytes / channels; + vsize = chunk_bytes / channels; // Not yet implemented assert(loaded == 0); @@ -1663,7 +1666,7 @@ void playbackv_go(int* fds, unsigned int channels, size_t loaded, size_t count, if (r == 0) break; c += r; - } while (xrun_mode != SND_PCM_XRUN_ASAP && c < expected); + } while (sleep_min == 0 && c < expected); c = c * 8 / bits_per_sample; r = pcm_writev(bufs, channels, c); if (r != c) @@ -1685,7 +1688,7 @@ void capturev_go(int* fds, unsigned int channels, size_t count, int rtype, char header(rtype, names[0]); set_params(); - vsize = buffer_bytes / channels; + vsize = chunk_bytes / channels; for (channel = 0; channel < channels; ++channel) bufs[channel] = audiobuf + vsize * channel; @@ -1693,8 +1696,8 @@ void capturev_go(int* fds, unsigned int channels, size_t count, int rtype, char while (count > 0) { size_t rv; c = count; - if (c > buffer_bytes) - c = buffer_bytes; + if (c > chunk_bytes) + c = chunk_bytes; c = c * 8 / bits_per_frame; if ((r = pcm_readv(bufs, channels, c)) != c) break; -- 2.47.1