summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/xas/riff.h3
-rw-r--r--src/riff.c175
2 files changed, 178 insertions, 0 deletions
diff --git a/include/xas/riff.h b/include/xas/riff.h
index 6e097c3..823a9ae 100644
--- a/include/xas/riff.h
+++ b/include/xas/riff.h
@@ -55,4 +55,7 @@ xas_audio_stream *xas_riff_file_new(const char *path,
size_t channels,
int flags);
+xas_audio_stream *xas_riff_file_open(const char *path,
+ int flags);
+
#endif /* _XAS_RIFF_H */
diff --git a/src/riff.c b/src/riff.c
index 640f550..233d2cb 100644
--- a/src/riff.c
+++ b/src/riff.c
@@ -1,6 +1,8 @@
#include <stdlib.h>
+#include <string.h>
#include <fcntl.h>
#include <unistd.h>
+#include <errno.h>
#include <xas/audio.h>
#include <xas/riff.h>
@@ -104,6 +106,139 @@ error_malloc_riff:
return NULL;
}
+static int wave_header_parse(xas_riff *riff,
+ xas_riff_wave_header *header) {
+ if (memcmp(header->riff.header.id,
+ XAS_RIFF_HEADER_MAIN_ID,
+ strlen(XAS_RIFF_HEADER_MAIN_ID)) != 0) {
+ goto error_invalid_header_main_id;
+ }
+
+ if (header->riff.header.size < sizeof(xas_riff_main_chunk)
+ + sizeof(xas_riff_wave_chunk)) {
+ goto error_invalid_header_wave_chunk_size;
+ }
+
+ if (memcmp(header->riff.type,
+ XAS_RIFF_HEADER_WAVE_ID,
+ strlen(XAS_RIFF_HEADER_WAVE_ID)) != 0) {
+ goto error_invalid_wave_chunk_id;
+ }
+
+ if (memcmp(header->wave.header.id,
+ XAS_RIFF_HEADER_WAVE_FMT_ID,
+ strlen(XAS_RIFF_HEADER_WAVE_FMT_ID)) != 0) {
+ goto error_invalid_wave_format_id;
+ }
+
+ if (header->wave.header.size != sizeof(xas_riff_wave_chunk)
+ - sizeof(xas_riff_chunk)) {
+ goto error_invalid_wave_format_size;
+ }
+
+ if (header->wave.type != XAS_RIFF_WAVE_DEFAULT_TYPE) {
+ goto error_invalid_wave_format_type;
+ }
+
+ switch (header->wave.channels) {
+ case XAS_AUDIO_STREAM_MONO:
+ case XAS_AUDIO_STREAM_STEREO:
+ break;
+
+ default:
+ goto error_invalid_wave_channels;
+ }
+
+ if (header->wave.byte_rate != header->wave.channels
+ * header->wave.sample_size
+ * header->wave.sample_rate) {
+ goto error_invalid_wave_byte_rate;
+ }
+
+ if (header->wave.sample_size_bits != header->wave.sample_size << 3) {
+ goto error_invalid_wave_sample_size_bits;
+ }
+
+ if (memcmp(header->data.id,
+ XAS_RIFF_HEADER_WAVE_DATA_ID,
+ strlen(XAS_RIFF_HEADER_WAVE_DATA_ID)) != 0) {
+ goto error_invalid_wave_data_format_id;
+ }
+
+ riff->sample_size = header->wave.sample_size;
+ riff->sample_rate = header->wave.sample_rate;
+ riff->channels = header->wave.channels;
+
+ return 0;
+
+error_invalid_wave_data_format_id:
+error_invalid_wave_sample_size_bits:
+error_invalid_wave_byte_rate:
+error_invalid_wave_channels:
+error_invalid_wave_format_type:
+error_invalid_wave_format_size:
+error_invalid_wave_format_id:
+error_invalid_wave_chunk_id:
+error_invalid_header_wave_chunk_size:
+error_invalid_header_main_id:
+ return -1;
+}
+
+static xas_riff *file_open(const char *path,
+ int flags) {
+ xas_riff *riff;
+ xas_riff_wave_header header;
+
+ ssize_t readlen;
+
+ if ((riff = malloc(sizeof(*riff))) == NULL) {
+ goto error_malloc_riff;
+ }
+
+ flags &= ~(O_CREAT | O_TRUNC);
+
+ if ((riff->fd = open(path, flags)) < 0) {
+ goto error_open;
+ }
+
+ riff->size = 0;
+ riff->sample_size = 0;
+ riff->sample_rate = 0;
+ riff->channels = 0;
+
+ if (lseek(riff->fd, 0, SEEK_SET) < 0) {
+ goto error_lseek;
+ }
+
+ if ((readlen = read(riff->fd, &header, sizeof(header))) < 0) {
+ goto error_read;
+ }
+
+ if (readlen != sizeof(header)) {
+ errno= EINVAL;
+
+ goto error_wave_header_short;
+ }
+
+ if (wave_header_parse(riff, &header) < 0) {
+ goto error_wave_header_parse;
+ }
+
+ return riff;
+
+error_wave_header_parse:
+error_wave_header_short:
+error_read:
+error_lseek:
+ close(riff->fd);
+
+error_open:
+ free(riff);
+
+error_malloc_riff:
+ return NULL;
+}
+
static void file_close(xas_riff *riff, xas_audio_stream *stream) {
if (lseek(riff->fd, 0, SEEK_SET) < 0) {
goto error_io;
@@ -208,3 +343,43 @@ error_audio_stream_new_sink:
error_file_new:
return NULL;
}
+
+xas_audio_stream *xas_riff_file_open(const char *path,
+ int flags) {
+ xas_audio_stream *stream;
+ xas_riff *riff;
+
+ if ((riff = file_open(path, flags)) == NULL) {
+ goto error_file_open;
+ }
+
+ if (flags & (O_RDWR | O_WRONLY)) {
+ if ((stream = xas_audio_stream_new_sink((xas_audio_drain)audio_drain,
+ (xas_audio_cleanup)file_close,
+ riff,
+ riff->sample_size,
+ riff->sample_rate,
+ riff->channels,
+ 4096)) == NULL) {
+ goto error_audio_stream_new_sink;
+ }
+ } else {
+ if ((stream = xas_audio_stream_new_source((xas_audio_fill)audio_fill,
+ (xas_audio_cleanup)file_close,
+ riff,
+ riff->sample_size,
+ riff->sample_rate,
+ riff->channels,
+ 4096)) == NULL) {
+ goto error_audio_stream_new_sink;
+ }
+ }
+
+ return stream;
+
+error_audio_stream_new_sink:
+ file_close(riff, NULL);
+
+error_file_open:
+ return NULL;
+}