diff options
| author | XANTRONIX Development | 2022-02-01 13:49:22 -0500 | 
|---|---|---|
| committer | XANTRONIX Development | 2022-02-01 13:49:22 -0500 | 
| commit | c801d7da7935731dd71fde695eb8ee8419c71d03 (patch) | |
| tree | 9436f5bb4a9f1eed18db75bf0fe3b8609541ee67 /src | |
| parent | 6391c03277dbe0aae6bae4c24b936ce2becf69c1 (diff) | |
| download | xas-c801d7da7935731dd71fde695eb8ee8419c71d03.tar.gz xas-c801d7da7935731dd71fde695eb8ee8419c71d03.tar.bz2 xas-c801d7da7935731dd71fde695eb8ee8419c71d03.zip | |
Implement xas_riff_file_open()
Implement xas_riff_file_open() to open files for reading; implement a
RIFF header reader to parse and validate a header, and to extract PCM
sample metadata requisite to process a stream
Diffstat (limited to 'src')
| -rw-r--r-- | src/riff.c | 175 | 
1 files changed, 175 insertions, 0 deletions
| @@ -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; +} | 
 
    