1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// container-au.c - a parser/builder for a container of Sun Audio File. 4c72fcc34Sopenharmony_ci// 5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6c72fcc34Sopenharmony_ci// 7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2. 8c72fcc34Sopenharmony_ci 9c72fcc34Sopenharmony_ci#include "container.h" 10c72fcc34Sopenharmony_ci#include "misc.h" 11c72fcc34Sopenharmony_ci 12c72fcc34Sopenharmony_ci// Not portable to all of UNIX platforms. 13c72fcc34Sopenharmony_ci#include <endian.h> 14c72fcc34Sopenharmony_ci 15c72fcc34Sopenharmony_ci// Reference: 16c72fcc34Sopenharmony_ci// * http://pubs.opengroup.org/external/auformat.html 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#define AU_MAGIC ".snd" 19c72fcc34Sopenharmony_ci#define UNKNOWN_SIZE UINT32_MAX 20c72fcc34Sopenharmony_ci 21c72fcc34Sopenharmony_cienum code_id { 22c72fcc34Sopenharmony_ci CODE_ID_CCIT_MU_LAW_BE = 0x01, 23c72fcc34Sopenharmony_ci CODE_ID_GENERIC_MBLA_S8 = 0x02, 24c72fcc34Sopenharmony_ci CODE_ID_GENERIC_MBLA_S16_BE = 0x03, 25c72fcc34Sopenharmony_ci CODE_ID_GENERIC_MBLA_S32_BE = 0x05, 26c72fcc34Sopenharmony_ci CODE_ID_IEEE754_FLOAT_S32_BE = 0x06, 27c72fcc34Sopenharmony_ci CODE_ID_IEEE754_DOUBLE_S64_BE = 0x07, 28c72fcc34Sopenharmony_ci CODE_ID_CCIT_ADPCM_G721_4BIT_BE = 0x17, 29c72fcc34Sopenharmony_ci CODE_ID_CCIT_ADPCM_G723_3BIT_BE = 0x19, 30c72fcc34Sopenharmony_ci CODE_ID_CCIT_A_LAW_BE = 0x1b, 31c72fcc34Sopenharmony_ci}; 32c72fcc34Sopenharmony_ci 33c72fcc34Sopenharmony_cistruct format_map { 34c72fcc34Sopenharmony_ci enum code_id code_id; 35c72fcc34Sopenharmony_ci snd_pcm_format_t format; 36c72fcc34Sopenharmony_ci}; 37c72fcc34Sopenharmony_ci 38c72fcc34Sopenharmony_cistatic const struct format_map format_maps[] = { 39c72fcc34Sopenharmony_ci {CODE_ID_GENERIC_MBLA_S8, SND_PCM_FORMAT_S8}, 40c72fcc34Sopenharmony_ci {CODE_ID_GENERIC_MBLA_S16_BE, SND_PCM_FORMAT_S16_BE}, 41c72fcc34Sopenharmony_ci {CODE_ID_GENERIC_MBLA_S32_BE, SND_PCM_FORMAT_S32_BE}, 42c72fcc34Sopenharmony_ci {CODE_ID_IEEE754_FLOAT_S32_BE, SND_PCM_FORMAT_FLOAT_BE}, 43c72fcc34Sopenharmony_ci {CODE_ID_IEEE754_DOUBLE_S64_BE, SND_PCM_FORMAT_FLOAT64_BE}, 44c72fcc34Sopenharmony_ci // CODE_ID_CCIT_ADPCM_G721_4BIT_BE is not supported by ALSA. 45c72fcc34Sopenharmony_ci // CODE_ID_CCIT_ADPCM_G723_3BIT_BE is not supported due to width of 46c72fcc34Sopenharmony_ci // its sample. 47c72fcc34Sopenharmony_ci {CODE_ID_CCIT_A_LAW_BE, SND_PCM_FORMAT_A_LAW}, 48c72fcc34Sopenharmony_ci {CODE_ID_CCIT_MU_LAW_BE, SND_PCM_FORMAT_MU_LAW}, 49c72fcc34Sopenharmony_ci}; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_cistruct container_header { 52c72fcc34Sopenharmony_ci uint8_t magic[4]; 53c72fcc34Sopenharmony_ci uint32_t hdr_size; 54c72fcc34Sopenharmony_ci uint32_t data_size; 55c72fcc34Sopenharmony_ci uint32_t code_id; 56c72fcc34Sopenharmony_ci uint32_t frames_per_second; 57c72fcc34Sopenharmony_ci uint32_t samples_per_frame; 58c72fcc34Sopenharmony_ci}; 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_cistruct container_annotation { 61c72fcc34Sopenharmony_ci uint32_t chunks[0]; 62c72fcc34Sopenharmony_ci}; 63c72fcc34Sopenharmony_ci 64c72fcc34Sopenharmony_cistruct parser_state { 65c72fcc34Sopenharmony_ci enum code_id code_id; 66c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 67c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 68c72fcc34Sopenharmony_ci}; 69c72fcc34Sopenharmony_ci 70c72fcc34Sopenharmony_cistatic int au_parser_pre_process(struct container_context *cntr, 71c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 72c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 73c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 74c72fcc34Sopenharmony_ci uint64_t *byte_count) 75c72fcc34Sopenharmony_ci{ 76c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 77c72fcc34Sopenharmony_ci struct container_header header; 78c72fcc34Sopenharmony_ci enum code_id code_id; 79c72fcc34Sopenharmony_ci unsigned int i; 80c72fcc34Sopenharmony_ci int err; 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_ci // Parse header. 4 bytes are enough to detect supported containers. 83c72fcc34Sopenharmony_ci memcpy(&header.magic, cntr->magic, sizeof(cntr->magic)); 84c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, 85c72fcc34Sopenharmony_ci (char *)&header + sizeof(cntr->magic), 86c72fcc34Sopenharmony_ci sizeof(header) - sizeof(cntr->magic)); 87c72fcc34Sopenharmony_ci if (err < 0) 88c72fcc34Sopenharmony_ci return err; 89c72fcc34Sopenharmony_ci if (cntr->eof) 90c72fcc34Sopenharmony_ci return 0; 91c72fcc34Sopenharmony_ci 92c72fcc34Sopenharmony_ci if (memcmp(header.magic, AU_MAGIC, sizeof(header.magic)) != 0) 93c72fcc34Sopenharmony_ci return -EINVAL; 94c72fcc34Sopenharmony_ci if (be32toh(header.hdr_size) != sizeof(struct container_header)) 95c72fcc34Sopenharmony_ci return -EINVAL; 96c72fcc34Sopenharmony_ci 97c72fcc34Sopenharmony_ci code_id = be32toh(header.code_id); 98c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 99c72fcc34Sopenharmony_ci if (format_maps[i].code_id == code_id) 100c72fcc34Sopenharmony_ci break; 101c72fcc34Sopenharmony_ci } 102c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 103c72fcc34Sopenharmony_ci return -EINVAL; 104c72fcc34Sopenharmony_ci *format = format_maps[i].format; 105c72fcc34Sopenharmony_ci *frames_per_second = be32toh(header.frames_per_second); 106c72fcc34Sopenharmony_ci *samples_per_frame = be32toh(header.samples_per_frame); 107c72fcc34Sopenharmony_ci 108c72fcc34Sopenharmony_ci state->code_id = code_id; 109c72fcc34Sopenharmony_ci state->samples_per_frame = *samples_per_frame; 110c72fcc34Sopenharmony_ci state->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8; 111c72fcc34Sopenharmony_ci 112c72fcc34Sopenharmony_ci *byte_count = be32toh(header.data_size); 113c72fcc34Sopenharmony_ci 114c72fcc34Sopenharmony_ci return 0; 115c72fcc34Sopenharmony_ci} 116c72fcc34Sopenharmony_ci 117c72fcc34Sopenharmony_cistruct builder_state { 118c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 119c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 120c72fcc34Sopenharmony_ci unsigned int frames_per_second; 121c72fcc34Sopenharmony_ci enum code_id code_id; 122c72fcc34Sopenharmony_ci}; 123c72fcc34Sopenharmony_ci 124c72fcc34Sopenharmony_cistatic void build_container_header(struct builder_state *state, 125c72fcc34Sopenharmony_ci struct container_header *header, 126c72fcc34Sopenharmony_ci unsigned int frames_per_second, 127c72fcc34Sopenharmony_ci uint64_t byte_count) 128c72fcc34Sopenharmony_ci{ 129c72fcc34Sopenharmony_ci memcpy(header->magic, AU_MAGIC, sizeof(header->magic)); 130c72fcc34Sopenharmony_ci header->hdr_size = htobe32(sizeof(struct container_header)); 131c72fcc34Sopenharmony_ci header->data_size = htobe32(byte_count); 132c72fcc34Sopenharmony_ci header->code_id = htobe32(state->code_id); 133c72fcc34Sopenharmony_ci header->frames_per_second = htobe32(frames_per_second); 134c72fcc34Sopenharmony_ci header->samples_per_frame = htobe32(state->samples_per_frame); 135c72fcc34Sopenharmony_ci} 136c72fcc34Sopenharmony_ci 137c72fcc34Sopenharmony_cistatic int write_container_header(struct container_context *cntr, 138c72fcc34Sopenharmony_ci uint64_t byte_count) 139c72fcc34Sopenharmony_ci{ 140c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 141c72fcc34Sopenharmony_ci struct container_header header; 142c72fcc34Sopenharmony_ci 143c72fcc34Sopenharmony_ci build_container_header(state, &header, state->frames_per_second, 144c72fcc34Sopenharmony_ci byte_count); 145c72fcc34Sopenharmony_ci 146c72fcc34Sopenharmony_ci return container_recursive_write(cntr, &header, sizeof(header)); 147c72fcc34Sopenharmony_ci} 148c72fcc34Sopenharmony_ci 149c72fcc34Sopenharmony_cistatic int au_builder_pre_process(struct container_context *cntr, 150c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 151c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 152c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 153c72fcc34Sopenharmony_ci uint64_t *byte_count) 154c72fcc34Sopenharmony_ci{ 155c72fcc34Sopenharmony_ci struct builder_state *status = cntr->private_data; 156c72fcc34Sopenharmony_ci unsigned int i; 157c72fcc34Sopenharmony_ci 158c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 159c72fcc34Sopenharmony_ci if (format_maps[i].format == *format) 160c72fcc34Sopenharmony_ci break; 161c72fcc34Sopenharmony_ci } 162c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 163c72fcc34Sopenharmony_ci return -EINVAL; 164c72fcc34Sopenharmony_ci 165c72fcc34Sopenharmony_ci status->code_id = format_maps[i].code_id; 166c72fcc34Sopenharmony_ci status->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8; 167c72fcc34Sopenharmony_ci status->frames_per_second = *frames_per_second; 168c72fcc34Sopenharmony_ci status->samples_per_frame = *samples_per_frame; 169c72fcc34Sopenharmony_ci 170c72fcc34Sopenharmony_ci return write_container_header(cntr, *byte_count); 171c72fcc34Sopenharmony_ci} 172c72fcc34Sopenharmony_ci 173c72fcc34Sopenharmony_cistatic int au_builder_post_process(struct container_context *cntr, 174c72fcc34Sopenharmony_ci uint64_t handled_byte_count) 175c72fcc34Sopenharmony_ci{ 176c72fcc34Sopenharmony_ci int err; 177c72fcc34Sopenharmony_ci 178c72fcc34Sopenharmony_ci err = container_seek_offset(cntr, 0); 179c72fcc34Sopenharmony_ci if (err < 0) 180c72fcc34Sopenharmony_ci return err; 181c72fcc34Sopenharmony_ci 182c72fcc34Sopenharmony_ci return write_container_header(cntr, handled_byte_count); 183c72fcc34Sopenharmony_ci} 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ciconst struct container_parser container_parser_au = { 186c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_AU, 187c72fcc34Sopenharmony_ci .magic = AU_MAGIC, 188c72fcc34Sopenharmony_ci .max_size = UINT32_MAX, 189c72fcc34Sopenharmony_ci .ops = { 190c72fcc34Sopenharmony_ci .pre_process = au_parser_pre_process, 191c72fcc34Sopenharmony_ci }, 192c72fcc34Sopenharmony_ci .private_size = sizeof(struct parser_state), 193c72fcc34Sopenharmony_ci}; 194c72fcc34Sopenharmony_ci 195c72fcc34Sopenharmony_ciconst struct container_builder container_builder_au = { 196c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_AU, 197c72fcc34Sopenharmony_ci .max_size = UINT32_MAX, 198c72fcc34Sopenharmony_ci .ops = { 199c72fcc34Sopenharmony_ci .pre_process = au_builder_pre_process, 200c72fcc34Sopenharmony_ci .post_process = au_builder_post_process, 201c72fcc34Sopenharmony_ci }, 202c72fcc34Sopenharmony_ci .private_size = sizeof(struct builder_state), 203c72fcc34Sopenharmony_ci}; 204