diff options
-rw-r--r-- | include/tinyalsa/asoundlib.h | 9 | ||||
-rw-r--r-- | mixer.c | 2 | ||||
-rw-r--r-- | pcm.c | 6 | ||||
-rw-r--r-- | tinyplay.c | 73 |
4 files changed, 64 insertions, 26 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h index 704354e..e65403e 100644 --- a/include/tinyalsa/asoundlib.h +++ b/include/tinyalsa/asoundlib.h @@ -45,6 +45,15 @@ struct pcm; #define PCM_IN 0x10000000 #define PCM_MMAP 0x00000001 #define PCM_NOIRQ 0x00000002 +#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to + * pcm_write for a playback stream will not + * attempt to restart the stream in the case + * of an underflow, but will return -EPIPE + * instead. After the first -EPIPE error, the + * stream is considered to be stopped, and a + * second call to pcm_write will attempt to + * restart the stream. + */ /* PCM runtime states */ #define PCM_STATE_OPEN 0 @@ -34,6 +34,8 @@ #include <errno.h> #include <ctype.h> +#include <sys/ioctl.h> + #include <linux/ioctl.h> #define __force #define __bitwise @@ -378,8 +378,12 @@ int pcm_write(struct pcm *pcm, const void *data, unsigned int count) if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { pcm->running = 0; if (errno == EPIPE) { - /* we failed to make our window -- try to restart */ + /* we failed to make our window -- try to restart if we are + * allowed to do so. Otherwise, simply allow the EPIPE error to + * propagate up to the app level */ pcm->underruns++; + if (pcm->flags & PCM_NORESTART) + return -EPIPE; continue; } return oops(pcm, errno, "cannot write stream data"); @@ -36,22 +36,24 @@ #define ID_FMT 0x20746d66 #define ID_DATA 0x61746164 -#define FORMAT_PCM 1 - -struct wav_header { +struct riff_wave_header { uint32_t riff_id; uint32_t riff_sz; - uint32_t riff_fmt; - uint32_t fmt_id; - uint32_t fmt_sz; + uint32_t wave_id; +}; + +struct chunk_header { + uint32_t id; + uint32_t sz; +}; + +struct chunk_fmt { uint16_t audio_format; uint16_t num_channels; uint32_t sample_rate; uint32_t byte_rate; uint16_t block_align; uint16_t bits_per_sample; - uint32_t data_id; - uint32_t data_sz; }; void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, @@ -61,11 +63,15 @@ void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned in int main(int argc, char **argv) { FILE *file; - struct wav_header header; + struct riff_wave_header riff_wave_header; + struct chunk_header chunk_header; + struct chunk_fmt chunk_fmt; unsigned int device = 0; unsigned int card = 0; unsigned int period_size = 1024; unsigned int period_count = 4; + char *filename; + int more_chunks = 1; if (argc < 2) { fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-p period_size]" @@ -73,12 +79,41 @@ int main(int argc, char **argv) return 1; } - file = fopen(argv[1], "rb"); + filename = argv[1]; + file = fopen(filename, "rb"); if (!file) { - fprintf(stderr, "Unable to open file '%s'\n", argv[1]); + fprintf(stderr, "Unable to open file '%s'\n", filename); + return 1; + } + + fread(&riff_wave_header, sizeof(riff_wave_header), 1, file); + if ((riff_wave_header.riff_id != ID_RIFF) || + (riff_wave_header.wave_id != ID_WAVE)) { + fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename); + fclose(file); return 1; } + do { + fread(&chunk_header, sizeof(chunk_header), 1, file); + + switch (chunk_header.id) { + case ID_FMT: + fread(&chunk_fmt, sizeof(chunk_fmt), 1, file); + /* If the format header is larger, skip the rest */ + if (chunk_header.sz > sizeof(chunk_fmt)) + fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR); + break; + case ID_DATA: + /* Stop looking for chunks */ + more_chunks = 0; + break; + default: + /* Unknown chunk, skip bytes */ + fseek(file, chunk_header.sz, SEEK_CUR); + } + } while (more_chunks); + /* parse command line arguments */ argv += 2; while (*argv) { @@ -106,20 +141,8 @@ int main(int argc, char **argv) argv++; } - fread(&header, sizeof(struct wav_header), 1, file); - - if ((header.riff_id != ID_RIFF) || - (header.riff_fmt != ID_WAVE) || - (header.fmt_id != ID_FMT) || - (header.audio_format != FORMAT_PCM) || - (header.fmt_sz != 16)) { - fprintf(stderr, "Error: '%s' is not a PCM riff/wave file\n", argv[1]); - fclose(file); - return 1; - } - - play_sample(file, card, device, header.num_channels, header.sample_rate, - header.bits_per_sample, period_size, period_count); + play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate, + chunk_fmt.bits_per_sample, period_size, period_count); fclose(file); |