1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// container-riff-wave.c - a parser/builder for a container of RIFF/Wave 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// References: 16c72fcc34Sopenharmony_ci// - 'Resource Interchange File Format (RIFF)' at msdn.microsoft.com 17c72fcc34Sopenharmony_ci// - 'Multiple channel audio data and WAVE files' at msdn.microsoft.com 18c72fcc34Sopenharmony_ci// - RFC 2361 'WAVE and AVI Codec Registries' at ietf.org 19c72fcc34Sopenharmony_ci// - 'mmreg.h' in Wine project 20c72fcc34Sopenharmony_ci// - 'mmreg.h' in ReactOS project 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_ci#define RIFF_MAGIC "RIF" // A common part. 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#define RIFF_CHUNK_ID_LE "RIFF" 25c72fcc34Sopenharmony_ci#define RIFF_CHUNK_ID_BE "RIFX" 26c72fcc34Sopenharmony_ci#define RIFF_FORM_WAVE "WAVE" 27c72fcc34Sopenharmony_ci#define FMT_SUBCHUNK_ID "fmt " 28c72fcc34Sopenharmony_ci#define DATA_SUBCHUNK_ID "data" 29c72fcc34Sopenharmony_ci 30c72fcc34Sopenharmony_ci// See 'WAVE and AVI Codec Registries (Historic Registry)' in 'iana.org'. 31c72fcc34Sopenharmony_ci// https://www.iana.org/assignments/wave-avi-codec-registry/ 32c72fcc34Sopenharmony_cienum wave_format { 33c72fcc34Sopenharmony_ci WAVE_FORMAT_PCM = 0x0001, 34c72fcc34Sopenharmony_ci WAVE_FORMAT_ADPCM = 0x0002, 35c72fcc34Sopenharmony_ci WAVE_FORMAT_IEEE_FLOAT = 0x0003, 36c72fcc34Sopenharmony_ci WAVE_FORMAT_ALAW = 0x0006, 37c72fcc34Sopenharmony_ci WAVE_FORMAT_MULAW = 0x0007, 38c72fcc34Sopenharmony_ci WAVE_FORMAT_G723_ADPCM = 0x0014, 39c72fcc34Sopenharmony_ci // The others are not supported. 40c72fcc34Sopenharmony_ci}; 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_cistruct format_map { 43c72fcc34Sopenharmony_ci enum wave_format wformat; 44c72fcc34Sopenharmony_ci snd_pcm_format_t format; 45c72fcc34Sopenharmony_ci}; 46c72fcc34Sopenharmony_ci 47c72fcc34Sopenharmony_cistatic const struct format_map format_maps[] = { 48c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_U8}, 49c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S16_LE}, 50c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S16_BE}, 51c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S24_LE}, 52c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S24_BE}, 53c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S32_LE}, 54c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S32_BE}, 55c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S24_3LE}, 56c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S24_3BE}, 57c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S20_3LE}, 58c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S20_3BE}, 59c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S18_3LE}, 60c72fcc34Sopenharmony_ci {WAVE_FORMAT_PCM, SND_PCM_FORMAT_S18_3BE}, 61c72fcc34Sopenharmony_ci {WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT_LE}, 62c72fcc34Sopenharmony_ci {WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT_BE}, 63c72fcc34Sopenharmony_ci {WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT64_LE}, 64c72fcc34Sopenharmony_ci {WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT64_BE}, 65c72fcc34Sopenharmony_ci {WAVE_FORMAT_ALAW, SND_PCM_FORMAT_A_LAW}, 66c72fcc34Sopenharmony_ci {WAVE_FORMAT_MULAW, SND_PCM_FORMAT_MU_LAW}, 67c72fcc34Sopenharmony_ci // Below sample formats are not currently supported, due to width of 68c72fcc34Sopenharmony_ci // its sample. 69c72fcc34Sopenharmony_ci // - WAVE_FORMAT_ADPCM 70c72fcc34Sopenharmony_ci // - WAVE_FORMAT_G723_ADPCM 71c72fcc34Sopenharmony_ci // - WAVE_FORMAT_G723_ADPCM 72c72fcc34Sopenharmony_ci // - WAVE_FORMAT_G723_ADPCM 73c72fcc34Sopenharmony_ci // - WAVE_FORMAT_G723_ADPCM 74c72fcc34Sopenharmony_ci}; 75c72fcc34Sopenharmony_ci 76c72fcc34Sopenharmony_cistruct riff_chunk { 77c72fcc34Sopenharmony_ci uint8_t id[4]; 78c72fcc34Sopenharmony_ci uint32_t size; 79c72fcc34Sopenharmony_ci 80c72fcc34Sopenharmony_ci uint8_t data[0]; 81c72fcc34Sopenharmony_ci}; 82c72fcc34Sopenharmony_ci 83c72fcc34Sopenharmony_cistruct riff_chunk_data { 84c72fcc34Sopenharmony_ci uint8_t id[4]; 85c72fcc34Sopenharmony_ci 86c72fcc34Sopenharmony_ci uint8_t subchunks[0]; 87c72fcc34Sopenharmony_ci}; 88c72fcc34Sopenharmony_ci 89c72fcc34Sopenharmony_cistruct riff_subchunk { 90c72fcc34Sopenharmony_ci uint8_t id[4]; 91c72fcc34Sopenharmony_ci uint32_t size; 92c72fcc34Sopenharmony_ci 93c72fcc34Sopenharmony_ci uint8_t data[0]; 94c72fcc34Sopenharmony_ci}; 95c72fcc34Sopenharmony_ci 96c72fcc34Sopenharmony_cistruct wave_fmt_subchunk { 97c72fcc34Sopenharmony_ci uint8_t id[4]; 98c72fcc34Sopenharmony_ci uint32_t size; 99c72fcc34Sopenharmony_ci 100c72fcc34Sopenharmony_ci uint16_t format; 101c72fcc34Sopenharmony_ci uint16_t samples_per_frame; 102c72fcc34Sopenharmony_ci uint32_t frames_per_second; 103c72fcc34Sopenharmony_ci uint32_t average_bytes_per_second; 104c72fcc34Sopenharmony_ci uint16_t bytes_per_frame; 105c72fcc34Sopenharmony_ci uint16_t bits_per_sample; 106c72fcc34Sopenharmony_ci uint8_t extension[0]; 107c72fcc34Sopenharmony_ci}; 108c72fcc34Sopenharmony_ci 109c72fcc34Sopenharmony_cistruct wave_data_subchunk { 110c72fcc34Sopenharmony_ci uint8_t id[4]; 111c72fcc34Sopenharmony_ci uint32_t size; 112c72fcc34Sopenharmony_ci 113c72fcc34Sopenharmony_ci uint8_t frames[0]; 114c72fcc34Sopenharmony_ci}; 115c72fcc34Sopenharmony_ci 116c72fcc34Sopenharmony_cistruct parser_state { 117c72fcc34Sopenharmony_ci bool be; 118c72fcc34Sopenharmony_ci enum wave_format format; 119c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 120c72fcc34Sopenharmony_ci unsigned int frames_per_second; 121c72fcc34Sopenharmony_ci unsigned int average_bytes_per_second; 122c72fcc34Sopenharmony_ci unsigned int bytes_per_frame; 123c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 124c72fcc34Sopenharmony_ci unsigned int avail_bits_in_sample; 125c72fcc34Sopenharmony_ci unsigned int byte_count; 126c72fcc34Sopenharmony_ci}; 127c72fcc34Sopenharmony_ci 128c72fcc34Sopenharmony_cistatic int parse_riff_chunk_header(struct parser_state *state, 129c72fcc34Sopenharmony_ci struct riff_chunk *chunk, 130c72fcc34Sopenharmony_ci uint64_t *byte_count) 131c72fcc34Sopenharmony_ci{ 132c72fcc34Sopenharmony_ci if (!memcmp(chunk->id, RIFF_CHUNK_ID_BE, sizeof(chunk->id))) 133c72fcc34Sopenharmony_ci state->be = true; 134c72fcc34Sopenharmony_ci else if (!memcmp(chunk->id, RIFF_CHUNK_ID_LE, sizeof(chunk->id))) 135c72fcc34Sopenharmony_ci state->be = false; 136c72fcc34Sopenharmony_ci else 137c72fcc34Sopenharmony_ci return -EINVAL; 138c72fcc34Sopenharmony_ci 139c72fcc34Sopenharmony_ci if (state->be) 140c72fcc34Sopenharmony_ci *byte_count = be32toh(chunk->size); 141c72fcc34Sopenharmony_ci else 142c72fcc34Sopenharmony_ci *byte_count = le32toh(chunk->size); 143c72fcc34Sopenharmony_ci 144c72fcc34Sopenharmony_ci return 0; 145c72fcc34Sopenharmony_ci} 146c72fcc34Sopenharmony_ci 147c72fcc34Sopenharmony_cistatic int parse_riff_chunk(struct container_context *cntr, 148c72fcc34Sopenharmony_ci uint64_t *byte_count) 149c72fcc34Sopenharmony_ci{ 150c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 151c72fcc34Sopenharmony_ci union { 152c72fcc34Sopenharmony_ci struct riff_chunk chunk; 153c72fcc34Sopenharmony_ci struct riff_chunk_data chunk_data; 154c72fcc34Sopenharmony_ci } buf = {0}; 155c72fcc34Sopenharmony_ci int err; 156c72fcc34Sopenharmony_ci 157c72fcc34Sopenharmony_ci // Chunk header. 4 bytes were alread read to detect container type. 158c72fcc34Sopenharmony_ci memcpy(buf.chunk.id, cntr->magic, sizeof(cntr->magic)); 159c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, 160c72fcc34Sopenharmony_ci (char *)&buf.chunk + sizeof(cntr->magic), 161c72fcc34Sopenharmony_ci sizeof(buf.chunk) - sizeof(cntr->magic)); 162c72fcc34Sopenharmony_ci if (err < 0) 163c72fcc34Sopenharmony_ci return err; 164c72fcc34Sopenharmony_ci if (cntr->eof) 165c72fcc34Sopenharmony_ci return 0; 166c72fcc34Sopenharmony_ci 167c72fcc34Sopenharmony_ci err = parse_riff_chunk_header(state, &buf.chunk, byte_count); 168c72fcc34Sopenharmony_ci if (err < 0) 169c72fcc34Sopenharmony_ci return err; 170c72fcc34Sopenharmony_ci 171c72fcc34Sopenharmony_ci // Chunk data header. 172c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &buf, sizeof(buf.chunk_data)); 173c72fcc34Sopenharmony_ci if (err < 0) 174c72fcc34Sopenharmony_ci return err; 175c72fcc34Sopenharmony_ci if (cntr->eof) 176c72fcc34Sopenharmony_ci return 0; 177c72fcc34Sopenharmony_ci 178c72fcc34Sopenharmony_ci if (memcmp(buf.chunk_data.id, RIFF_FORM_WAVE, 179c72fcc34Sopenharmony_ci sizeof(buf.chunk_data.id))) 180c72fcc34Sopenharmony_ci return -EINVAL; 181c72fcc34Sopenharmony_ci 182c72fcc34Sopenharmony_ci return 0; 183c72fcc34Sopenharmony_ci} 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_cistatic int parse_wave_fmt_subchunk(struct parser_state *state, 186c72fcc34Sopenharmony_ci struct wave_fmt_subchunk *subchunk) 187c72fcc34Sopenharmony_ci{ 188c72fcc34Sopenharmony_ci if (state->be) { 189c72fcc34Sopenharmony_ci state->format = be16toh(subchunk->format); 190c72fcc34Sopenharmony_ci state->samples_per_frame = be16toh(subchunk->samples_per_frame); 191c72fcc34Sopenharmony_ci state->frames_per_second = be32toh(subchunk->frames_per_second); 192c72fcc34Sopenharmony_ci state->average_bytes_per_second = 193c72fcc34Sopenharmony_ci be32toh(subchunk->average_bytes_per_second); 194c72fcc34Sopenharmony_ci state->bytes_per_frame = be16toh(subchunk->bytes_per_frame); 195c72fcc34Sopenharmony_ci state->avail_bits_in_sample = 196c72fcc34Sopenharmony_ci be16toh(subchunk->bits_per_sample); 197c72fcc34Sopenharmony_ci } else { 198c72fcc34Sopenharmony_ci state->format = le16toh(subchunk->format); 199c72fcc34Sopenharmony_ci state->samples_per_frame = le16toh(subchunk->samples_per_frame); 200c72fcc34Sopenharmony_ci state->frames_per_second = le32toh(subchunk->frames_per_second); 201c72fcc34Sopenharmony_ci state->average_bytes_per_second = 202c72fcc34Sopenharmony_ci le32toh(subchunk->average_bytes_per_second); 203c72fcc34Sopenharmony_ci state->bytes_per_frame = le16toh(subchunk->bytes_per_frame); 204c72fcc34Sopenharmony_ci state->avail_bits_in_sample = 205c72fcc34Sopenharmony_ci le16toh(subchunk->bits_per_sample); 206c72fcc34Sopenharmony_ci } 207c72fcc34Sopenharmony_ci 208c72fcc34Sopenharmony_ci if (state->average_bytes_per_second != 209c72fcc34Sopenharmony_ci state->bytes_per_frame * state->frames_per_second) 210c72fcc34Sopenharmony_ci return -EINVAL; 211c72fcc34Sopenharmony_ci 212c72fcc34Sopenharmony_ci return 0; 213c72fcc34Sopenharmony_ci} 214c72fcc34Sopenharmony_ci 215c72fcc34Sopenharmony_cistatic int parse_wave_data_subchunk(struct parser_state *state, 216c72fcc34Sopenharmony_ci struct wave_data_subchunk *subchunk) 217c72fcc34Sopenharmony_ci{ 218c72fcc34Sopenharmony_ci if (state->be) 219c72fcc34Sopenharmony_ci state->byte_count = be32toh(subchunk->size); 220c72fcc34Sopenharmony_ci else 221c72fcc34Sopenharmony_ci state->byte_count = le32toh(subchunk->size); 222c72fcc34Sopenharmony_ci 223c72fcc34Sopenharmony_ci return 0; 224c72fcc34Sopenharmony_ci} 225c72fcc34Sopenharmony_ci 226c72fcc34Sopenharmony_cistatic int parse_wave_subchunk(struct container_context *cntr) 227c72fcc34Sopenharmony_ci{ 228c72fcc34Sopenharmony_ci union { 229c72fcc34Sopenharmony_ci struct riff_subchunk subchunk; 230c72fcc34Sopenharmony_ci struct wave_fmt_subchunk fmt_subchunk; 231c72fcc34Sopenharmony_ci struct wave_data_subchunk data_subchunk; 232c72fcc34Sopenharmony_ci } buf = {0}; 233c72fcc34Sopenharmony_ci enum { 234c72fcc34Sopenharmony_ci SUBCHUNK_TYPE_UNKNOWN = -1, 235c72fcc34Sopenharmony_ci SUBCHUNK_TYPE_FMT, 236c72fcc34Sopenharmony_ci SUBCHUNK_TYPE_DATA, 237c72fcc34Sopenharmony_ci } subchunk_type; 238c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 239c72fcc34Sopenharmony_ci unsigned int required_size; 240c72fcc34Sopenharmony_ci unsigned int subchunk_data_size; 241c72fcc34Sopenharmony_ci int err; 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_ci while (1) { 244c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &buf, 245c72fcc34Sopenharmony_ci sizeof(buf.subchunk)); 246c72fcc34Sopenharmony_ci if (err < 0) 247c72fcc34Sopenharmony_ci return err; 248c72fcc34Sopenharmony_ci if (cntr->eof) 249c72fcc34Sopenharmony_ci return 0; 250c72fcc34Sopenharmony_ci 251c72fcc34Sopenharmony_ci // Calculate the size of subchunk data. 252c72fcc34Sopenharmony_ci if (state->be) 253c72fcc34Sopenharmony_ci subchunk_data_size = be32toh(buf.subchunk.size); 254c72fcc34Sopenharmony_ci else 255c72fcc34Sopenharmony_ci subchunk_data_size = le32toh(buf.subchunk.size); 256c72fcc34Sopenharmony_ci 257c72fcc34Sopenharmony_ci // Detect type of subchunk. 258c72fcc34Sopenharmony_ci if (!memcmp(buf.subchunk.id, FMT_SUBCHUNK_ID, 259c72fcc34Sopenharmony_ci sizeof(buf.subchunk.id))) { 260c72fcc34Sopenharmony_ci subchunk_type = SUBCHUNK_TYPE_FMT; 261c72fcc34Sopenharmony_ci } else if (!memcmp(buf.subchunk.id, DATA_SUBCHUNK_ID, 262c72fcc34Sopenharmony_ci sizeof(buf.subchunk.id))) { 263c72fcc34Sopenharmony_ci subchunk_type = SUBCHUNK_TYPE_DATA; 264c72fcc34Sopenharmony_ci } else { 265c72fcc34Sopenharmony_ci subchunk_type = SUBCHUNK_TYPE_UNKNOWN; 266c72fcc34Sopenharmony_ci } 267c72fcc34Sopenharmony_ci 268c72fcc34Sopenharmony_ci if (subchunk_type != SUBCHUNK_TYPE_UNKNOWN) { 269c72fcc34Sopenharmony_ci // Parse data of this subchunk. 270c72fcc34Sopenharmony_ci if (subchunk_type == SUBCHUNK_TYPE_FMT) { 271c72fcc34Sopenharmony_ci required_size = 272c72fcc34Sopenharmony_ci sizeof(struct wave_fmt_subchunk) - 273c72fcc34Sopenharmony_ci sizeof(struct riff_chunk); 274c72fcc34Sopenharmony_ci } else { 275c72fcc34Sopenharmony_ci required_size = 276c72fcc34Sopenharmony_ci sizeof(struct wave_data_subchunk)- 277c72fcc34Sopenharmony_ci sizeof(struct riff_chunk); 278c72fcc34Sopenharmony_ci } 279c72fcc34Sopenharmony_ci 280c72fcc34Sopenharmony_ci if (subchunk_data_size < required_size) 281c72fcc34Sopenharmony_ci return -EINVAL; 282c72fcc34Sopenharmony_ci 283c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &buf.subchunk.data, 284c72fcc34Sopenharmony_ci required_size); 285c72fcc34Sopenharmony_ci if (err < 0) 286c72fcc34Sopenharmony_ci return err; 287c72fcc34Sopenharmony_ci if (cntr->eof) 288c72fcc34Sopenharmony_ci return 0; 289c72fcc34Sopenharmony_ci subchunk_data_size -= required_size; 290c72fcc34Sopenharmony_ci 291c72fcc34Sopenharmony_ci if (subchunk_type == SUBCHUNK_TYPE_FMT) { 292c72fcc34Sopenharmony_ci err = parse_wave_fmt_subchunk(state, 293c72fcc34Sopenharmony_ci &buf.fmt_subchunk); 294c72fcc34Sopenharmony_ci } else if (subchunk_type == SUBCHUNK_TYPE_DATA) { 295c72fcc34Sopenharmony_ci err = parse_wave_data_subchunk(state, 296c72fcc34Sopenharmony_ci &buf.data_subchunk); 297c72fcc34Sopenharmony_ci } 298c72fcc34Sopenharmony_ci if (err < 0) 299c72fcc34Sopenharmony_ci return err; 300c72fcc34Sopenharmony_ci 301c72fcc34Sopenharmony_ci // Found frame data. 302c72fcc34Sopenharmony_ci if (subchunk_type == SUBCHUNK_TYPE_DATA) 303c72fcc34Sopenharmony_ci break; 304c72fcc34Sopenharmony_ci } 305c72fcc34Sopenharmony_ci 306c72fcc34Sopenharmony_ci // Go to next subchunk. 307c72fcc34Sopenharmony_ci while (subchunk_data_size > 0) { 308c72fcc34Sopenharmony_ci unsigned int consume; 309c72fcc34Sopenharmony_ci 310c72fcc34Sopenharmony_ci if (subchunk_data_size > sizeof(buf)) 311c72fcc34Sopenharmony_ci consume = sizeof(buf); 312c72fcc34Sopenharmony_ci else 313c72fcc34Sopenharmony_ci consume = subchunk_data_size; 314c72fcc34Sopenharmony_ci 315c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &buf, consume); 316c72fcc34Sopenharmony_ci if (err < 0) 317c72fcc34Sopenharmony_ci return err; 318c72fcc34Sopenharmony_ci if (cntr->eof) 319c72fcc34Sopenharmony_ci return 0; 320c72fcc34Sopenharmony_ci subchunk_data_size -= consume; 321c72fcc34Sopenharmony_ci } 322c72fcc34Sopenharmony_ci } 323c72fcc34Sopenharmony_ci 324c72fcc34Sopenharmony_ci return 0; 325c72fcc34Sopenharmony_ci} 326c72fcc34Sopenharmony_ci 327c72fcc34Sopenharmony_cistatic int parse_riff_wave_format(struct container_context *cntr) 328c72fcc34Sopenharmony_ci{ 329c72fcc34Sopenharmony_ci uint64_t byte_count; 330c72fcc34Sopenharmony_ci int err; 331c72fcc34Sopenharmony_ci 332c72fcc34Sopenharmony_ci err = parse_riff_chunk(cntr, &byte_count); 333c72fcc34Sopenharmony_ci if (err < 0) 334c72fcc34Sopenharmony_ci return err; 335c72fcc34Sopenharmony_ci 336c72fcc34Sopenharmony_ci err = parse_wave_subchunk(cntr); 337c72fcc34Sopenharmony_ci if (err < 0) 338c72fcc34Sopenharmony_ci return err; 339c72fcc34Sopenharmony_ci 340c72fcc34Sopenharmony_ci return 0; 341c72fcc34Sopenharmony_ci} 342c72fcc34Sopenharmony_ci 343c72fcc34Sopenharmony_cistatic int wave_parser_pre_process(struct container_context *cntr, 344c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 345c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 346c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 347c72fcc34Sopenharmony_ci uint64_t *byte_count) 348c72fcc34Sopenharmony_ci{ 349c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 350c72fcc34Sopenharmony_ci int phys_width; 351c72fcc34Sopenharmony_ci const struct format_map *map; 352c72fcc34Sopenharmony_ci unsigned int i; 353c72fcc34Sopenharmony_ci int err; 354c72fcc34Sopenharmony_ci 355c72fcc34Sopenharmony_ci err = parse_riff_wave_format(cntr); 356c72fcc34Sopenharmony_ci if (err < 0) 357c72fcc34Sopenharmony_ci return err; 358c72fcc34Sopenharmony_ci 359c72fcc34Sopenharmony_ci phys_width = 8 * state->average_bytes_per_second / 360c72fcc34Sopenharmony_ci state->samples_per_frame / state->frames_per_second; 361c72fcc34Sopenharmony_ci 362c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 363c72fcc34Sopenharmony_ci map = &format_maps[i]; 364c72fcc34Sopenharmony_ci if (state->format != map->wformat) 365c72fcc34Sopenharmony_ci continue; 366c72fcc34Sopenharmony_ci if ((int)state->avail_bits_in_sample != 367c72fcc34Sopenharmony_ci snd_pcm_format_width(map->format)) 368c72fcc34Sopenharmony_ci continue; 369c72fcc34Sopenharmony_ci if (phys_width != snd_pcm_format_physical_width(map->format)) 370c72fcc34Sopenharmony_ci continue; 371c72fcc34Sopenharmony_ci 372c72fcc34Sopenharmony_ci if (state->be && snd_pcm_format_big_endian(map->format) != 1) 373c72fcc34Sopenharmony_ci continue; 374c72fcc34Sopenharmony_ci 375c72fcc34Sopenharmony_ci break; 376c72fcc34Sopenharmony_ci } 377c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 378c72fcc34Sopenharmony_ci return -EINVAL; 379c72fcc34Sopenharmony_ci 380c72fcc34Sopenharmony_ci // Set parameters. 381c72fcc34Sopenharmony_ci *format = format_maps[i].format; 382c72fcc34Sopenharmony_ci *samples_per_frame = state->samples_per_frame; 383c72fcc34Sopenharmony_ci *frames_per_second = state->frames_per_second; 384c72fcc34Sopenharmony_ci *byte_count = state->byte_count; 385c72fcc34Sopenharmony_ci 386c72fcc34Sopenharmony_ci return 0; 387c72fcc34Sopenharmony_ci} 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_cistruct builder_state { 390c72fcc34Sopenharmony_ci bool be; 391c72fcc34Sopenharmony_ci enum wave_format format; 392c72fcc34Sopenharmony_ci unsigned int avail_bits_in_sample; 393c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 394c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 395c72fcc34Sopenharmony_ci unsigned int frames_per_second; 396c72fcc34Sopenharmony_ci}; 397c72fcc34Sopenharmony_ci 398c72fcc34Sopenharmony_cistatic void build_riff_chunk_header(struct riff_chunk *chunk, 399c72fcc34Sopenharmony_ci uint64_t byte_count, bool be) 400c72fcc34Sopenharmony_ci{ 401c72fcc34Sopenharmony_ci uint64_t data_size = sizeof(struct riff_chunk_data) + 402c72fcc34Sopenharmony_ci sizeof(struct wave_fmt_subchunk) + 403c72fcc34Sopenharmony_ci sizeof(struct wave_data_subchunk) + byte_count; 404c72fcc34Sopenharmony_ci 405c72fcc34Sopenharmony_ci if (be) { 406c72fcc34Sopenharmony_ci memcpy(chunk->id, RIFF_CHUNK_ID_BE, sizeof(chunk->id)); 407c72fcc34Sopenharmony_ci chunk->size = htobe32(data_size); 408c72fcc34Sopenharmony_ci } else { 409c72fcc34Sopenharmony_ci memcpy(chunk->id, RIFF_CHUNK_ID_LE, sizeof(chunk->id)); 410c72fcc34Sopenharmony_ci chunk->size = htole32(data_size); 411c72fcc34Sopenharmony_ci } 412c72fcc34Sopenharmony_ci} 413c72fcc34Sopenharmony_ci 414c72fcc34Sopenharmony_cistatic void build_subchunk_header(struct riff_subchunk *subchunk, 415c72fcc34Sopenharmony_ci const char *const form, uint64_t size, 416c72fcc34Sopenharmony_ci bool be) 417c72fcc34Sopenharmony_ci{ 418c72fcc34Sopenharmony_ci memcpy(subchunk->id, form, sizeof(subchunk->id)); 419c72fcc34Sopenharmony_ci if (be) 420c72fcc34Sopenharmony_ci subchunk->size = htobe32(size); 421c72fcc34Sopenharmony_ci else 422c72fcc34Sopenharmony_ci subchunk->size = htole32(size); 423c72fcc34Sopenharmony_ci} 424c72fcc34Sopenharmony_ci 425c72fcc34Sopenharmony_cistatic void build_wave_format_subchunk(struct wave_fmt_subchunk *subchunk, 426c72fcc34Sopenharmony_ci struct builder_state *state) 427c72fcc34Sopenharmony_ci{ 428c72fcc34Sopenharmony_ci unsigned int bytes_per_frame = 429c72fcc34Sopenharmony_ci state->bytes_per_sample * state->samples_per_frame; 430c72fcc34Sopenharmony_ci unsigned int average_bytes_per_second = state->bytes_per_sample * 431c72fcc34Sopenharmony_ci state->samples_per_frame * state->frames_per_second; 432c72fcc34Sopenharmony_ci uint64_t size; 433c72fcc34Sopenharmony_ci 434c72fcc34Sopenharmony_ci // No extensions. 435c72fcc34Sopenharmony_ci size = sizeof(struct wave_fmt_subchunk) - sizeof(struct riff_subchunk); 436c72fcc34Sopenharmony_ci build_subchunk_header((struct riff_subchunk *)subchunk, FMT_SUBCHUNK_ID, 437c72fcc34Sopenharmony_ci size, state->be); 438c72fcc34Sopenharmony_ci 439c72fcc34Sopenharmony_ci if (state->be) { 440c72fcc34Sopenharmony_ci subchunk->format = htobe16(state->format); 441c72fcc34Sopenharmony_ci subchunk->samples_per_frame = htobe16(state->samples_per_frame); 442c72fcc34Sopenharmony_ci subchunk->frames_per_second = htobe32(state->frames_per_second); 443c72fcc34Sopenharmony_ci subchunk->average_bytes_per_second = 444c72fcc34Sopenharmony_ci htobe32(average_bytes_per_second); 445c72fcc34Sopenharmony_ci subchunk->bytes_per_frame = htobe16(bytes_per_frame); 446c72fcc34Sopenharmony_ci subchunk->bits_per_sample = 447c72fcc34Sopenharmony_ci htobe16(state->avail_bits_in_sample); 448c72fcc34Sopenharmony_ci } else { 449c72fcc34Sopenharmony_ci subchunk->format = htole16(state->format); 450c72fcc34Sopenharmony_ci subchunk->samples_per_frame = htole16(state->samples_per_frame); 451c72fcc34Sopenharmony_ci subchunk->frames_per_second = htole32(state->frames_per_second); 452c72fcc34Sopenharmony_ci subchunk->average_bytes_per_second = 453c72fcc34Sopenharmony_ci htole32(average_bytes_per_second); 454c72fcc34Sopenharmony_ci subchunk->bytes_per_frame = htole16(bytes_per_frame); 455c72fcc34Sopenharmony_ci subchunk->bits_per_sample = 456c72fcc34Sopenharmony_ci htole16(state->avail_bits_in_sample); 457c72fcc34Sopenharmony_ci } 458c72fcc34Sopenharmony_ci} 459c72fcc34Sopenharmony_ci 460c72fcc34Sopenharmony_cistatic void build_wave_data_subchunk(struct wave_data_subchunk *subchunk, 461c72fcc34Sopenharmony_ci uint64_t byte_count, bool be) 462c72fcc34Sopenharmony_ci{ 463c72fcc34Sopenharmony_ci build_subchunk_header((struct riff_subchunk *)subchunk, 464c72fcc34Sopenharmony_ci DATA_SUBCHUNK_ID, byte_count, be); 465c72fcc34Sopenharmony_ci} 466c72fcc34Sopenharmony_ci 467c72fcc34Sopenharmony_cistatic int write_riff_chunk_for_wave(struct container_context *cntr, 468c72fcc34Sopenharmony_ci uint64_t byte_count) 469c72fcc34Sopenharmony_ci{ 470c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 471c72fcc34Sopenharmony_ci union { 472c72fcc34Sopenharmony_ci struct riff_chunk chunk; 473c72fcc34Sopenharmony_ci struct riff_chunk_data chunk_data; 474c72fcc34Sopenharmony_ci struct wave_fmt_subchunk fmt_subchunk; 475c72fcc34Sopenharmony_ci struct wave_data_subchunk data_subchunk; 476c72fcc34Sopenharmony_ci } buf = {0}; 477c72fcc34Sopenharmony_ci uint64_t total_byte_count; 478c72fcc34Sopenharmony_ci int err; 479c72fcc34Sopenharmony_ci 480c72fcc34Sopenharmony_ci // Chunk header. 481c72fcc34Sopenharmony_ci total_byte_count = sizeof(struct riff_chunk_data) + 482c72fcc34Sopenharmony_ci sizeof(struct wave_fmt_subchunk) + 483c72fcc34Sopenharmony_ci sizeof(struct wave_data_subchunk); 484c72fcc34Sopenharmony_ci if (byte_count > cntr->max_size - total_byte_count) 485c72fcc34Sopenharmony_ci total_byte_count = cntr->max_size; 486c72fcc34Sopenharmony_ci else 487c72fcc34Sopenharmony_ci total_byte_count += byte_count; 488c72fcc34Sopenharmony_ci build_riff_chunk_header(&buf.chunk, total_byte_count, state->be); 489c72fcc34Sopenharmony_ci err = container_recursive_write(cntr, &buf, sizeof(buf.chunk)); 490c72fcc34Sopenharmony_ci if (err < 0) 491c72fcc34Sopenharmony_ci return err; 492c72fcc34Sopenharmony_ci 493c72fcc34Sopenharmony_ci // Chunk data header. 494c72fcc34Sopenharmony_ci memcpy(buf.chunk_data.id, RIFF_FORM_WAVE, sizeof(buf.chunk_data.id)); 495c72fcc34Sopenharmony_ci err = container_recursive_write(cntr, &buf, sizeof(buf.chunk_data)); 496c72fcc34Sopenharmony_ci if (err < 0) 497c72fcc34Sopenharmony_ci return err; 498c72fcc34Sopenharmony_ci 499c72fcc34Sopenharmony_ci // A subchunk in the chunk data for WAVE format. 500c72fcc34Sopenharmony_ci build_wave_format_subchunk(&buf.fmt_subchunk, state); 501c72fcc34Sopenharmony_ci err = container_recursive_write(cntr, &buf, sizeof(buf.fmt_subchunk)); 502c72fcc34Sopenharmony_ci if (err < 0) 503c72fcc34Sopenharmony_ci return err; 504c72fcc34Sopenharmony_ci 505c72fcc34Sopenharmony_ci // A subchunk in the chunk data for WAVE data. 506c72fcc34Sopenharmony_ci build_wave_data_subchunk(&buf.data_subchunk, byte_count, state->be); 507c72fcc34Sopenharmony_ci return container_recursive_write(cntr, &buf, sizeof(buf.data_subchunk)); 508c72fcc34Sopenharmony_ci} 509c72fcc34Sopenharmony_ci 510c72fcc34Sopenharmony_cistatic int wave_builder_pre_process(struct container_context *cntr, 511c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 512c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 513c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 514c72fcc34Sopenharmony_ci uint64_t *byte_count) 515c72fcc34Sopenharmony_ci{ 516c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 517c72fcc34Sopenharmony_ci unsigned int i; 518c72fcc34Sopenharmony_ci 519c72fcc34Sopenharmony_ci // Validate parameters. 520c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 521c72fcc34Sopenharmony_ci if (format_maps[i].format == *format) 522c72fcc34Sopenharmony_ci break; 523c72fcc34Sopenharmony_ci } 524c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 525c72fcc34Sopenharmony_ci return -EINVAL; 526c72fcc34Sopenharmony_ci 527c72fcc34Sopenharmony_ci state->format = format_maps[i].wformat; 528c72fcc34Sopenharmony_ci state->avail_bits_in_sample = snd_pcm_format_width(*format); 529c72fcc34Sopenharmony_ci state->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8; 530c72fcc34Sopenharmony_ci state->samples_per_frame = *samples_per_frame; 531c72fcc34Sopenharmony_ci state->frames_per_second = *frames_per_second; 532c72fcc34Sopenharmony_ci 533c72fcc34Sopenharmony_ci state->be = (snd_pcm_format_big_endian(*format) == 1); 534c72fcc34Sopenharmony_ci 535c72fcc34Sopenharmony_ci return write_riff_chunk_for_wave(cntr, *byte_count); 536c72fcc34Sopenharmony_ci} 537c72fcc34Sopenharmony_ci 538c72fcc34Sopenharmony_cistatic int wave_builder_post_process(struct container_context *cntr, 539c72fcc34Sopenharmony_ci uint64_t handled_byte_count) 540c72fcc34Sopenharmony_ci{ 541c72fcc34Sopenharmony_ci int err; 542c72fcc34Sopenharmony_ci 543c72fcc34Sopenharmony_ci err = container_seek_offset(cntr, 0); 544c72fcc34Sopenharmony_ci if (err < 0) 545c72fcc34Sopenharmony_ci return err; 546c72fcc34Sopenharmony_ci 547c72fcc34Sopenharmony_ci return write_riff_chunk_for_wave(cntr, handled_byte_count); 548c72fcc34Sopenharmony_ci} 549c72fcc34Sopenharmony_ci 550c72fcc34Sopenharmony_ciconst struct container_parser container_parser_riff_wave = { 551c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_RIFF_WAVE, 552c72fcc34Sopenharmony_ci .magic = RIFF_MAGIC, 553c72fcc34Sopenharmony_ci .max_size = UINT32_MAX - 554c72fcc34Sopenharmony_ci sizeof(struct riff_chunk_data) - 555c72fcc34Sopenharmony_ci sizeof(struct wave_fmt_subchunk) - 556c72fcc34Sopenharmony_ci sizeof(struct wave_data_subchunk), 557c72fcc34Sopenharmony_ci .ops = { 558c72fcc34Sopenharmony_ci .pre_process = wave_parser_pre_process, 559c72fcc34Sopenharmony_ci }, 560c72fcc34Sopenharmony_ci .private_size = sizeof(struct parser_state), 561c72fcc34Sopenharmony_ci}; 562c72fcc34Sopenharmony_ci 563c72fcc34Sopenharmony_ciconst struct container_builder container_builder_riff_wave = { 564c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_RIFF_WAVE, 565c72fcc34Sopenharmony_ci .max_size = UINT32_MAX - 566c72fcc34Sopenharmony_ci sizeof(struct riff_chunk_data) - 567c72fcc34Sopenharmony_ci sizeof(struct wave_fmt_subchunk) - 568c72fcc34Sopenharmony_ci sizeof(struct wave_data_subchunk), 569c72fcc34Sopenharmony_ci .ops = { 570c72fcc34Sopenharmony_ci .pre_process = wave_builder_pre_process, 571c72fcc34Sopenharmony_ci .post_process = wave_builder_post_process, 572c72fcc34Sopenharmony_ci }, 573c72fcc34Sopenharmony_ci .private_size = sizeof(struct builder_state), 574c72fcc34Sopenharmony_ci}; 575