aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tinyalsa/asoundlib.h9
-rw-r--r--mixer.c2
-rw-r--r--pcm.c6
-rw-r--r--tinyplay.c73
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
diff --git a/mixer.c b/mixer.c
index 4a39a43..9514528 100644
--- a/mixer.c
+++ b/mixer.c
@@ -34,6 +34,8 @@
#include <errno.h>
#include <ctype.h>
+#include <sys/ioctl.h>
+
#include <linux/ioctl.h>
#define __force
#define __bitwise
diff --git a/pcm.c b/pcm.c
index d253433..2dca157 100644
--- a/pcm.c
+++ b/pcm.c
@@ -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");
diff --git a/tinyplay.c b/tinyplay.c
index 4d257e7..3f76cc6 100644
--- a/tinyplay.c
+++ b/tinyplay.c
@@ -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);