1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// container-voc.c - a parser/builder for a container of Creative Voice 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// - http://sox.sourceforge.net/ 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#define VOC_MAGIC "Creative Voice File\x1a" 19c72fcc34Sopenharmony_ci#define VOC_VERSION_1_10 0x010a 20c72fcc34Sopenharmony_ci#define VOC_VERSION_1_20 0x0114 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_cienum block_type { 23c72fcc34Sopenharmony_ci BLOCK_TYPE_TERMINATOR = 0x00, 24c72fcc34Sopenharmony_ci BLOCK_TYPE_V110_DATA = 0x01, 25c72fcc34Sopenharmony_ci BLOCK_TYPE_CONTINUOUS_DATA = 0x02, 26c72fcc34Sopenharmony_ci BLOCK_TYPE_SILENCE = 0x03, 27c72fcc34Sopenharmony_ci BLOCK_TYPE_MARKER = 0x04, 28c72fcc34Sopenharmony_ci BLOCK_TYPE_STRING = 0x05, 29c72fcc34Sopenharmony_ci BLOCK_TYPE_REPEAT_START = 0x06, 30c72fcc34Sopenharmony_ci BLOCK_TYPE_REPEAT_END = 0x07, 31c72fcc34Sopenharmony_ci BLOCK_TYPE_EXTENDED_V110_FORMAT = 0x08, 32c72fcc34Sopenharmony_ci BLOCK_TYPE_V120_DATA = 0x09, 33c72fcc34Sopenharmony_ci}; 34c72fcc34Sopenharmony_ci 35c72fcc34Sopenharmony_cienum code_id { 36c72fcc34Sopenharmony_ci // Version 1.10. 37c72fcc34Sopenharmony_ci CODE_ID_GENERIC_MBLA_U8 = 0x00, 38c72fcc34Sopenharmony_ci CODE_ID_CREATIVE_ADPCM_8BIT_TO_4BIT_LE = 0x01, 39c72fcc34Sopenharmony_ci CODE_ID_CREATIVE_ADPCM_8BIT_TO_3BIT_LE = 0x02, 40c72fcc34Sopenharmony_ci CODE_ID_CREATIVE_ADPCM_8BIT_TO_2BIT_LE = 0x03, 41c72fcc34Sopenharmony_ci // Version 1.20. 42c72fcc34Sopenharmony_ci CODE_ID_GENERIC_MBLA_S16_LE = 0x04, 43c72fcc34Sopenharmony_ci CODE_ID_CCIT_A_LAW_LE = 0x06, 44c72fcc34Sopenharmony_ci CODE_ID_CCIT_MU_LAW_LE = 0x07, 45c72fcc34Sopenharmony_ci CODE_ID_CREATIVE_ADPCM_16BIT_TO_4BIT_LE = 0x2000, 46c72fcc34Sopenharmony_ci}; 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_cistruct format_map { 49c72fcc34Sopenharmony_ci unsigned int minimal_version; 50c72fcc34Sopenharmony_ci enum code_id code_id; 51c72fcc34Sopenharmony_ci snd_pcm_format_t format; 52c72fcc34Sopenharmony_ci}; 53c72fcc34Sopenharmony_ci 54c72fcc34Sopenharmony_cistatic const struct format_map format_maps[] = { 55c72fcc34Sopenharmony_ci {VOC_VERSION_1_10, CODE_ID_GENERIC_MBLA_U8, SND_PCM_FORMAT_U8}, 56c72fcc34Sopenharmony_ci {VOC_VERSION_1_20, CODE_ID_GENERIC_MBLA_S16_LE, SND_PCM_FORMAT_S16_LE}, 57c72fcc34Sopenharmony_ci {VOC_VERSION_1_20, CODE_ID_CCIT_A_LAW_LE, SND_PCM_FORMAT_A_LAW}, 58c72fcc34Sopenharmony_ci {VOC_VERSION_1_20, CODE_ID_CCIT_MU_LAW_LE, SND_PCM_FORMAT_MU_LAW}, 59c72fcc34Sopenharmony_ci // The other formats are not supported by ALSA. 60c72fcc34Sopenharmony_ci}; 61c72fcc34Sopenharmony_ci 62c72fcc34Sopenharmony_cistruct container_header { 63c72fcc34Sopenharmony_ci uint8_t magic[20]; 64c72fcc34Sopenharmony_ci uint16_t hdr_size; 65c72fcc34Sopenharmony_ci uint16_t version; 66c72fcc34Sopenharmony_ci uint16_t version_compr; 67c72fcc34Sopenharmony_ci}; 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci// A format for data blocks except for terminator type. 70c72fcc34Sopenharmony_cistruct block_header { 71c72fcc34Sopenharmony_ci uint8_t type; 72c72fcc34Sopenharmony_ci uint8_t size[3]; 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_ci uint8_t data[0]; 75c72fcc34Sopenharmony_ci}; 76c72fcc34Sopenharmony_ci 77c72fcc34Sopenharmony_ci// Data block for terminator type has an exceptional format. 78c72fcc34Sopenharmony_cistruct block_terminator { 79c72fcc34Sopenharmony_ci uint8_t type; 80c72fcc34Sopenharmony_ci}; 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_cistruct time_const { 83c72fcc34Sopenharmony_ci unsigned int frames_per_second; 84c72fcc34Sopenharmony_ci uint16_t code; 85c72fcc34Sopenharmony_ci}; 86c72fcc34Sopenharmony_ci 87c72fcc34Sopenharmony_cistatic const struct time_const v110_time_consts[] = { 88c72fcc34Sopenharmony_ci {5512, 74}, 89c72fcc34Sopenharmony_ci {8000, 130}, 90c72fcc34Sopenharmony_ci {11025, 165}, 91c72fcc34Sopenharmony_ci {16000, 193}, 92c72fcc34Sopenharmony_ci {22050, 210}, 93c72fcc34Sopenharmony_ci {32000, 224}, 94c72fcc34Sopenharmony_ci {44100, 233}, 95c72fcc34Sopenharmony_ci {48000, 235}, 96c72fcc34Sopenharmony_ci {64000, 240}, 97c72fcc34Sopenharmony_ci // Time constant for the upper sampling rate is not identical. 98c72fcc34Sopenharmony_ci}; 99c72fcc34Sopenharmony_ci 100c72fcc34Sopenharmony_cistatic const struct time_const ex_v110_time_consts[] = { 101c72fcc34Sopenharmony_ci {5512, 19092}, 102c72fcc34Sopenharmony_ci {8000, 33536}, 103c72fcc34Sopenharmony_ci {11025, 42317}, 104c72fcc34Sopenharmony_ci {16000, 49536}, 105c72fcc34Sopenharmony_ci {22050, 53927}, 106c72fcc34Sopenharmony_ci {32000, 57536}, 107c72fcc34Sopenharmony_ci {44100, 59732}, 108c72fcc34Sopenharmony_ci {48000, 60203}, 109c72fcc34Sopenharmony_ci {64000, 61536}, 110c72fcc34Sopenharmony_ci {88200, 62634}, 111c72fcc34Sopenharmony_ci {96000, 62870}, 112c72fcc34Sopenharmony_ci {176400, 64085}, 113c72fcc34Sopenharmony_ci {192000, 64203}, 114c72fcc34Sopenharmony_ci // This support up to 192.0 kHz. The rest is for cases with 2ch. 115c72fcc34Sopenharmony_ci {352800, 64811}, 116c72fcc34Sopenharmony_ci {384000, 64870}, 117c72fcc34Sopenharmony_ci}; 118c72fcc34Sopenharmony_ci 119c72fcc34Sopenharmony_ci// v1.10 format: 120c72fcc34Sopenharmony_ci// - monaural. 121c72fcc34Sopenharmony_ci// - frames_per_second = 1,000,000 / (256 - time_const) 122c72fcc34Sopenharmony_cistruct block_v110_data { 123c72fcc34Sopenharmony_ci uint8_t type; 124c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to (2 + the size of frames). 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci uint8_t time_const; 127c72fcc34Sopenharmony_ci uint8_t code_id; 128c72fcc34Sopenharmony_ci uint8_t frames[0]; // Aligned to little-endian. 129c72fcc34Sopenharmony_ci}; 130c72fcc34Sopenharmony_ci 131c72fcc34Sopenharmony_cistruct block_continuous_data { 132c72fcc34Sopenharmony_ci uint8_t type; 133c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to the size of frames. 134c72fcc34Sopenharmony_ci 135c72fcc34Sopenharmony_ci uint8_t frames[0]; // Aligned to little-endian. 136c72fcc34Sopenharmony_ci}; 137c72fcc34Sopenharmony_ci 138c72fcc34Sopenharmony_ci// v1.10 format: 139c72fcc34Sopenharmony_ci// - monaural. 140c72fcc34Sopenharmony_ci// - frames_per_second = 1,000,000 / (256 - time_const). 141c72fcc34Sopenharmony_cistruct block_silence { 142c72fcc34Sopenharmony_ci uint8_t type; 143c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to 3. 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_ci uint16_t frame_count; 146c72fcc34Sopenharmony_ci uint8_t time_const; 147c72fcc34Sopenharmony_ci}; 148c72fcc34Sopenharmony_ci 149c72fcc34Sopenharmony_cistruct block_marker { 150c72fcc34Sopenharmony_ci uint8_t type; 151c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to 2. 152c72fcc34Sopenharmony_ci 153c72fcc34Sopenharmony_ci uint16_t mark; 154c72fcc34Sopenharmony_ci}; 155c72fcc34Sopenharmony_ci 156c72fcc34Sopenharmony_cistruct block_string { 157c72fcc34Sopenharmony_ci uint8_t type; 158c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to the length of string with 0x00. 159c72fcc34Sopenharmony_ci 160c72fcc34Sopenharmony_ci uint8_t chars[0]; 161c72fcc34Sopenharmony_ci}; 162c72fcc34Sopenharmony_ci 163c72fcc34Sopenharmony_cistruct block_repeat_start { 164c72fcc34Sopenharmony_ci uint8_t type; 165c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to 2. 166c72fcc34Sopenharmony_ci 167c72fcc34Sopenharmony_ci uint16_t count; 168c72fcc34Sopenharmony_ci}; 169c72fcc34Sopenharmony_ci 170c72fcc34Sopenharmony_cistruct block_repeat_end { 171c72fcc34Sopenharmony_ci uint8_t type; 172c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to 0. 173c72fcc34Sopenharmony_ci}; 174c72fcc34Sopenharmony_ci 175c72fcc34Sopenharmony_ci// Extended v1.10 format: 176c72fcc34Sopenharmony_ci// - manaural/stereo. 177c72fcc34Sopenharmony_ci// - frames_per_second = 178c72fcc34Sopenharmony_ci// 256,000,000 / (samples_per_frame * (65536 - time_const)). 179c72fcc34Sopenharmony_ci// - Appear just before v110_data block. 180c72fcc34Sopenharmony_cistruct block_extended_v110_format { 181c72fcc34Sopenharmony_ci uint8_t type; 182c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to 4. 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_ci uint16_t time_const; 185c72fcc34Sopenharmony_ci uint8_t code_id; 186c72fcc34Sopenharmony_ci uint8_t ch_mode; // 0 is monaural, 1 is stereo. 187c72fcc34Sopenharmony_ci}; 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ci// v1.20 format: 190c72fcc34Sopenharmony_ci// - monaural/stereo. 191c72fcc34Sopenharmony_ci// - 8/16 bits_per_sample. 192c72fcc34Sopenharmony_ci// - time_const is not used. 193c72fcc34Sopenharmony_ci// - code_id is extended. 194c72fcc34Sopenharmony_cistruct block_v120_format { 195c72fcc34Sopenharmony_ci uint8_t type; 196c72fcc34Sopenharmony_ci uint8_t size[3]; // Equals to (12 + ). 197c72fcc34Sopenharmony_ci 198c72fcc34Sopenharmony_ci uint32_t frames_per_second; 199c72fcc34Sopenharmony_ci uint8_t bits_per_sample; 200c72fcc34Sopenharmony_ci uint8_t samples_per_frame; 201c72fcc34Sopenharmony_ci uint16_t code_id; 202c72fcc34Sopenharmony_ci uint8_t reserved[4]; 203c72fcc34Sopenharmony_ci 204c72fcc34Sopenharmony_ci uint8_t frames[0]; // Aligned to little-endian. 205c72fcc34Sopenharmony_ci}; 206c72fcc34Sopenharmony_ci 207c72fcc34Sopenharmony_ci// Aligned to little endian order but 24 bits field. 208c72fcc34Sopenharmony_cistatic uint32_t parse_block_data_size(uint8_t fields[3]) 209c72fcc34Sopenharmony_ci{ 210c72fcc34Sopenharmony_ci return (fields[2] << 16) | (fields[1] << 8) | fields[0]; 211c72fcc34Sopenharmony_ci} 212c72fcc34Sopenharmony_ci 213c72fcc34Sopenharmony_cistatic void build_block_data_size(uint8_t fields[3], unsigned int size) 214c72fcc34Sopenharmony_ci{ 215c72fcc34Sopenharmony_ci fields[0] = (size & 0x0000ff); 216c72fcc34Sopenharmony_ci fields[1] = (size & 0x00ff00) >> 8; 217c72fcc34Sopenharmony_ci fields[2] = (size & 0xff0000) >> 16; 218c72fcc34Sopenharmony_ci} 219c72fcc34Sopenharmony_ci 220c72fcc34Sopenharmony_cistatic int build_time_constant(unsigned int frames_per_second, 221c72fcc34Sopenharmony_ci unsigned int samples_per_frame, uint16_t *code, 222c72fcc34Sopenharmony_ci bool extended) 223c72fcc34Sopenharmony_ci{ 224c72fcc34Sopenharmony_ci unsigned int i; 225c72fcc34Sopenharmony_ci 226c72fcc34Sopenharmony_ci // 16 bits are available for this purpose. 227c72fcc34Sopenharmony_ci if (extended) { 228c72fcc34Sopenharmony_ci if (samples_per_frame > 2) 229c72fcc34Sopenharmony_ci return -EINVAL; 230c72fcc34Sopenharmony_ci frames_per_second *= samples_per_frame; 231c72fcc34Sopenharmony_ci 232c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ex_v110_time_consts); ++i) { 233c72fcc34Sopenharmony_ci if (ex_v110_time_consts[i].frames_per_second == 234c72fcc34Sopenharmony_ci frames_per_second) 235c72fcc34Sopenharmony_ci break; 236c72fcc34Sopenharmony_ci } 237c72fcc34Sopenharmony_ci if (i < ARRAY_SIZE(ex_v110_time_consts) && 238c72fcc34Sopenharmony_ci frames_per_second <= 192000) { 239c72fcc34Sopenharmony_ci *code = ex_v110_time_consts[i].code; 240c72fcc34Sopenharmony_ci } else { 241c72fcc34Sopenharmony_ci *code = 65536 - 256000000 / frames_per_second; 242c72fcc34Sopenharmony_ci } 243c72fcc34Sopenharmony_ci } else { 244c72fcc34Sopenharmony_ci if (samples_per_frame != 1) 245c72fcc34Sopenharmony_ci return -EINVAL; 246c72fcc34Sopenharmony_ci 247c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v110_time_consts); ++i) { 248c72fcc34Sopenharmony_ci if (v110_time_consts[i].frames_per_second == 249c72fcc34Sopenharmony_ci frames_per_second) 250c72fcc34Sopenharmony_ci break; 251c72fcc34Sopenharmony_ci } 252c72fcc34Sopenharmony_ci // Should be within 8 bit. 253c72fcc34Sopenharmony_ci if (i < ARRAY_SIZE(v110_time_consts)) 254c72fcc34Sopenharmony_ci *code = (uint8_t)v110_time_consts[i].code; 255c72fcc34Sopenharmony_ci else 256c72fcc34Sopenharmony_ci *code = 256 - 1000000 / frames_per_second; 257c72fcc34Sopenharmony_ci } 258c72fcc34Sopenharmony_ci 259c72fcc34Sopenharmony_ci return 0; 260c72fcc34Sopenharmony_ci} 261c72fcc34Sopenharmony_ci 262c72fcc34Sopenharmony_cistatic unsigned int parse_time_constant(uint16_t code, 263c72fcc34Sopenharmony_ci unsigned int samples_per_frame, 264c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 265c72fcc34Sopenharmony_ci bool extended) 266c72fcc34Sopenharmony_ci{ 267c72fcc34Sopenharmony_ci unsigned int i; 268c72fcc34Sopenharmony_ci 269c72fcc34Sopenharmony_ci if (extended) { 270c72fcc34Sopenharmony_ci if (samples_per_frame > 2) 271c72fcc34Sopenharmony_ci return -EINVAL; 272c72fcc34Sopenharmony_ci 273c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ex_v110_time_consts); ++i) { 274c72fcc34Sopenharmony_ci if (ex_v110_time_consts[i].code == code || 275c72fcc34Sopenharmony_ci ex_v110_time_consts[i].code - 1 == code) 276c72fcc34Sopenharmony_ci break; 277c72fcc34Sopenharmony_ci } 278c72fcc34Sopenharmony_ci if (i < ARRAY_SIZE(ex_v110_time_consts)) { 279c72fcc34Sopenharmony_ci *frames_per_second = 280c72fcc34Sopenharmony_ci ex_v110_time_consts[i].frames_per_second / 281c72fcc34Sopenharmony_ci samples_per_frame; 282c72fcc34Sopenharmony_ci } else { 283c72fcc34Sopenharmony_ci *frames_per_second = 256000000 / samples_per_frame / 284c72fcc34Sopenharmony_ci (65536 - code); 285c72fcc34Sopenharmony_ci } 286c72fcc34Sopenharmony_ci } else { 287c72fcc34Sopenharmony_ci if (samples_per_frame != 1) 288c72fcc34Sopenharmony_ci return -EINVAL; 289c72fcc34Sopenharmony_ci 290c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v110_time_consts); ++i) { 291c72fcc34Sopenharmony_ci if (v110_time_consts[i].code == code || 292c72fcc34Sopenharmony_ci v110_time_consts[i].code - 1 == code) 293c72fcc34Sopenharmony_ci break; 294c72fcc34Sopenharmony_ci } 295c72fcc34Sopenharmony_ci if (i < ARRAY_SIZE(v110_time_consts)) { 296c72fcc34Sopenharmony_ci *frames_per_second = 297c72fcc34Sopenharmony_ci v110_time_consts[i].frames_per_second; 298c72fcc34Sopenharmony_ci } else { 299c72fcc34Sopenharmony_ci *frames_per_second = 1000000 / (256 - code); 300c72fcc34Sopenharmony_ci } 301c72fcc34Sopenharmony_ci } 302c72fcc34Sopenharmony_ci 303c72fcc34Sopenharmony_ci return 0; 304c72fcc34Sopenharmony_ci} 305c72fcc34Sopenharmony_ci 306c72fcc34Sopenharmony_cistruct parser_state { 307c72fcc34Sopenharmony_ci unsigned int version; 308c72fcc34Sopenharmony_ci bool extended; 309c72fcc34Sopenharmony_ci 310c72fcc34Sopenharmony_ci unsigned int frames_per_second; 311c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 312c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 313c72fcc34Sopenharmony_ci enum code_id code_id; 314c72fcc34Sopenharmony_ci uint32_t byte_count; 315c72fcc34Sopenharmony_ci}; 316c72fcc34Sopenharmony_ci 317c72fcc34Sopenharmony_cistatic int parse_container_header(struct parser_state *state, 318c72fcc34Sopenharmony_ci struct container_header *header) 319c72fcc34Sopenharmony_ci{ 320c72fcc34Sopenharmony_ci uint16_t hdr_size; 321c72fcc34Sopenharmony_ci uint16_t version; 322c72fcc34Sopenharmony_ci uint16_t version_compr; 323c72fcc34Sopenharmony_ci 324c72fcc34Sopenharmony_ci hdr_size = le16toh(header->hdr_size); 325c72fcc34Sopenharmony_ci version = le16toh(header->version); 326c72fcc34Sopenharmony_ci version_compr = le16toh(header->version_compr); 327c72fcc34Sopenharmony_ci 328c72fcc34Sopenharmony_ci if (memcmp(header->magic, VOC_MAGIC, sizeof(header->magic))) 329c72fcc34Sopenharmony_ci return -EIO; 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_ci if (hdr_size != sizeof(*header)) 332c72fcc34Sopenharmony_ci return -EIO; 333c72fcc34Sopenharmony_ci 334c72fcc34Sopenharmony_ci if (version_compr != 0x1234 + ~version) 335c72fcc34Sopenharmony_ci return -EIO; 336c72fcc34Sopenharmony_ci 337c72fcc34Sopenharmony_ci if (version != VOC_VERSION_1_10 && version != VOC_VERSION_1_20) 338c72fcc34Sopenharmony_ci return -EIO; 339c72fcc34Sopenharmony_ci 340c72fcc34Sopenharmony_ci state->version = version; 341c72fcc34Sopenharmony_ci 342c72fcc34Sopenharmony_ci return 0; 343c72fcc34Sopenharmony_ci} 344c72fcc34Sopenharmony_ci 345c72fcc34Sopenharmony_cistatic bool check_code_id(uint8_t code_id, unsigned int version) 346c72fcc34Sopenharmony_ci{ 347c72fcc34Sopenharmony_ci unsigned int i; 348c72fcc34Sopenharmony_ci 349c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 350c72fcc34Sopenharmony_ci if (code_id != format_maps[i].code_id) 351c72fcc34Sopenharmony_ci continue; 352c72fcc34Sopenharmony_ci if (version >= format_maps[i].minimal_version) 353c72fcc34Sopenharmony_ci return true; 354c72fcc34Sopenharmony_ci } 355c72fcc34Sopenharmony_ci 356c72fcc34Sopenharmony_ci return false; 357c72fcc34Sopenharmony_ci} 358c72fcc34Sopenharmony_ci 359c72fcc34Sopenharmony_cistatic int parse_v120_format_block(struct parser_state *state, 360c72fcc34Sopenharmony_ci struct block_v120_format *block) 361c72fcc34Sopenharmony_ci{ 362c72fcc34Sopenharmony_ci state->frames_per_second = le32toh(block->frames_per_second); 363c72fcc34Sopenharmony_ci state->bytes_per_sample = block->bits_per_sample / 8; 364c72fcc34Sopenharmony_ci state->samples_per_frame = block->samples_per_frame; 365c72fcc34Sopenharmony_ci state->code_id = le16toh(block->code_id); 366c72fcc34Sopenharmony_ci state->byte_count = parse_block_data_size(block->size) - 12; 367c72fcc34Sopenharmony_ci 368c72fcc34Sopenharmony_ci if (!check_code_id(state->code_id, VOC_VERSION_1_20)) 369c72fcc34Sopenharmony_ci return -EIO; 370c72fcc34Sopenharmony_ci 371c72fcc34Sopenharmony_ci return 0; 372c72fcc34Sopenharmony_ci} 373c72fcc34Sopenharmony_ci 374c72fcc34Sopenharmony_cistatic int parse_extended_v110_format(struct parser_state *state, 375c72fcc34Sopenharmony_ci struct block_extended_v110_format *block) 376c72fcc34Sopenharmony_ci{ 377c72fcc34Sopenharmony_ci unsigned int time_const; 378c72fcc34Sopenharmony_ci unsigned int frames_per_second; 379c72fcc34Sopenharmony_ci int err; 380c72fcc34Sopenharmony_ci 381c72fcc34Sopenharmony_ci state->code_id = block->code_id; 382c72fcc34Sopenharmony_ci if (!check_code_id(state->code_id, VOC_VERSION_1_10)) 383c72fcc34Sopenharmony_ci return -EIO; 384c72fcc34Sopenharmony_ci 385c72fcc34Sopenharmony_ci if (block->ch_mode == 0) 386c72fcc34Sopenharmony_ci state->samples_per_frame = 1; 387c72fcc34Sopenharmony_ci else if (block->ch_mode == 1) 388c72fcc34Sopenharmony_ci state->samples_per_frame = 2; 389c72fcc34Sopenharmony_ci else 390c72fcc34Sopenharmony_ci return -EIO; 391c72fcc34Sopenharmony_ci 392c72fcc34Sopenharmony_ci time_const = le16toh(block->time_const); 393c72fcc34Sopenharmony_ci err = parse_time_constant(time_const, state->samples_per_frame, 394c72fcc34Sopenharmony_ci &frames_per_second, true); 395c72fcc34Sopenharmony_ci if (err < 0) 396c72fcc34Sopenharmony_ci return err; 397c72fcc34Sopenharmony_ci state->frames_per_second = frames_per_second; 398c72fcc34Sopenharmony_ci 399c72fcc34Sopenharmony_ci state->extended = true; 400c72fcc34Sopenharmony_ci 401c72fcc34Sopenharmony_ci return 0; 402c72fcc34Sopenharmony_ci} 403c72fcc34Sopenharmony_ci 404c72fcc34Sopenharmony_cistatic int parse_v110_data(struct parser_state *state, 405c72fcc34Sopenharmony_ci struct block_v110_data *block) 406c72fcc34Sopenharmony_ci{ 407c72fcc34Sopenharmony_ci unsigned int time_const; 408c72fcc34Sopenharmony_ci unsigned int frames_per_second; 409c72fcc34Sopenharmony_ci int err; 410c72fcc34Sopenharmony_ci 411c72fcc34Sopenharmony_ci if (!state->extended) { 412c72fcc34Sopenharmony_ci state->code_id = block->code_id; 413c72fcc34Sopenharmony_ci if (!check_code_id(state->code_id, VOC_VERSION_1_10)) 414c72fcc34Sopenharmony_ci return -EIO; 415c72fcc34Sopenharmony_ci 416c72fcc34Sopenharmony_ci time_const = block->time_const; 417c72fcc34Sopenharmony_ci err = parse_time_constant(time_const, 1, &frames_per_second, 418c72fcc34Sopenharmony_ci false); 419c72fcc34Sopenharmony_ci if (err < 0) 420c72fcc34Sopenharmony_ci return err; 421c72fcc34Sopenharmony_ci state->frames_per_second = frames_per_second; 422c72fcc34Sopenharmony_ci state->samples_per_frame = 1; 423c72fcc34Sopenharmony_ci } 424c72fcc34Sopenharmony_ci 425c72fcc34Sopenharmony_ci state->bytes_per_sample = 1; 426c72fcc34Sopenharmony_ci state->byte_count = parse_block_data_size(block->size) - 2; 427c72fcc34Sopenharmony_ci 428c72fcc34Sopenharmony_ci return 0; 429c72fcc34Sopenharmony_ci} 430c72fcc34Sopenharmony_ci 431c72fcc34Sopenharmony_cistatic int detect_container_version(struct container_context *cntr) 432c72fcc34Sopenharmony_ci{ 433c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 434c72fcc34Sopenharmony_ci struct container_header header = {0}; 435c72fcc34Sopenharmony_ci int err; 436c72fcc34Sopenharmony_ci 437c72fcc34Sopenharmony_ci // 4 bytes were alread read to detect container type. 438c72fcc34Sopenharmony_ci memcpy(&header.magic, cntr->magic, sizeof(cntr->magic)); 439c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, 440c72fcc34Sopenharmony_ci (char *)&header + sizeof(cntr->magic), 441c72fcc34Sopenharmony_ci sizeof(header) - sizeof(cntr->magic)); 442c72fcc34Sopenharmony_ci if (err < 0) 443c72fcc34Sopenharmony_ci return err; 444c72fcc34Sopenharmony_ci if (cntr->eof) 445c72fcc34Sopenharmony_ci return 0; 446c72fcc34Sopenharmony_ci 447c72fcc34Sopenharmony_ci return parse_container_header(state, &header); 448c72fcc34Sopenharmony_ci} 449c72fcc34Sopenharmony_ci 450c72fcc34Sopenharmony_cistatic int allocate_for_block_cache(struct container_context *cntr, 451c72fcc34Sopenharmony_ci struct block_header *header, void **buf) 452c72fcc34Sopenharmony_ci{ 453c72fcc34Sopenharmony_ci uint32_t block_size; 454c72fcc34Sopenharmony_ci char *cache; 455c72fcc34Sopenharmony_ci int err; 456c72fcc34Sopenharmony_ci 457c72fcc34Sopenharmony_ci if (header->type == BLOCK_TYPE_V110_DATA) 458c72fcc34Sopenharmony_ci block_size = sizeof(struct block_v110_data); 459c72fcc34Sopenharmony_ci else if (header->type == BLOCK_TYPE_CONTINUOUS_DATA) 460c72fcc34Sopenharmony_ci block_size = sizeof(struct block_continuous_data); 461c72fcc34Sopenharmony_ci else if (header->type == BLOCK_TYPE_EXTENDED_V110_FORMAT) 462c72fcc34Sopenharmony_ci block_size = sizeof(struct block_extended_v110_format); 463c72fcc34Sopenharmony_ci else if (header->type == BLOCK_TYPE_V120_DATA) 464c72fcc34Sopenharmony_ci block_size = sizeof(struct block_v120_format); 465c72fcc34Sopenharmony_ci else 466c72fcc34Sopenharmony_ci block_size = parse_block_data_size(header->size); 467c72fcc34Sopenharmony_ci 468c72fcc34Sopenharmony_ci cache = malloc(block_size); 469c72fcc34Sopenharmony_ci if (cache == NULL) 470c72fcc34Sopenharmony_ci return -ENOMEM; 471c72fcc34Sopenharmony_ci memset(cache, 0, block_size); 472c72fcc34Sopenharmony_ci 473c72fcc34Sopenharmony_ci memcpy(cache, header, sizeof(*header)); 474c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, cache + sizeof(*header), 475c72fcc34Sopenharmony_ci block_size - sizeof(*header)); 476c72fcc34Sopenharmony_ci if (err < 0) { 477c72fcc34Sopenharmony_ci free(cache); 478c72fcc34Sopenharmony_ci return err; 479c72fcc34Sopenharmony_ci } 480c72fcc34Sopenharmony_ci if (cntr->eof) { 481c72fcc34Sopenharmony_ci free(cache); 482c72fcc34Sopenharmony_ci return 0; 483c72fcc34Sopenharmony_ci } 484c72fcc34Sopenharmony_ci 485c72fcc34Sopenharmony_ci *buf = cache; 486c72fcc34Sopenharmony_ci 487c72fcc34Sopenharmony_ci return 0; 488c72fcc34Sopenharmony_ci} 489c72fcc34Sopenharmony_ci 490c72fcc34Sopenharmony_cistatic int cache_data_block(struct container_context *cntr, 491c72fcc34Sopenharmony_ci struct block_header *header, void **buf) 492c72fcc34Sopenharmony_ci{ 493c72fcc34Sopenharmony_ci int err; 494c72fcc34Sopenharmony_ci 495c72fcc34Sopenharmony_ci // Check type of this block. 496c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &header->type, 497c72fcc34Sopenharmony_ci sizeof(header->type)); 498c72fcc34Sopenharmony_ci if (err < 0) 499c72fcc34Sopenharmony_ci return err; 500c72fcc34Sopenharmony_ci if (cntr->eof) 501c72fcc34Sopenharmony_ci return 0; 502c72fcc34Sopenharmony_ci 503c72fcc34Sopenharmony_ci if (header->type > BLOCK_TYPE_V120_DATA) 504c72fcc34Sopenharmony_ci return -EIO; 505c72fcc34Sopenharmony_ci if (header->type == BLOCK_TYPE_TERMINATOR) 506c72fcc34Sopenharmony_ci return 0; 507c72fcc34Sopenharmony_ci 508c72fcc34Sopenharmony_ci // Check size of this block. If the block includes a batch of data, 509c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, &header->size, 510c72fcc34Sopenharmony_ci sizeof(header->size)); 511c72fcc34Sopenharmony_ci if (err < 0) 512c72fcc34Sopenharmony_ci return err; 513c72fcc34Sopenharmony_ci if (cntr->eof) 514c72fcc34Sopenharmony_ci return 0; 515c72fcc34Sopenharmony_ci 516c72fcc34Sopenharmony_ci return allocate_for_block_cache(cntr, header, buf); 517c72fcc34Sopenharmony_ci} 518c72fcc34Sopenharmony_ci 519c72fcc34Sopenharmony_cistatic int detect_format_block(struct container_context *cntr) 520c72fcc34Sopenharmony_ci{ 521c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 522c72fcc34Sopenharmony_ci struct block_header header; 523c72fcc34Sopenharmony_ci void *buf; 524c72fcc34Sopenharmony_ci int err; 525c72fcc34Sopenharmony_ci 526c72fcc34Sopenharmony_ciagain: 527c72fcc34Sopenharmony_ci buf = NULL; 528c72fcc34Sopenharmony_ci err = cache_data_block(cntr, &header, &buf); 529c72fcc34Sopenharmony_ci if (err < 0) 530c72fcc34Sopenharmony_ci return err; 531c72fcc34Sopenharmony_ci if (buf) { 532c72fcc34Sopenharmony_ci if (header.type == BLOCK_TYPE_EXTENDED_V110_FORMAT) { 533c72fcc34Sopenharmony_ci err = parse_extended_v110_format(state, buf); 534c72fcc34Sopenharmony_ci } else if (header.type == BLOCK_TYPE_V120_DATA) { 535c72fcc34Sopenharmony_ci err = parse_v120_format_block(state, buf); 536c72fcc34Sopenharmony_ci } else if (header.type == BLOCK_TYPE_V110_DATA) { 537c72fcc34Sopenharmony_ci err = parse_v110_data(state, buf); 538c72fcc34Sopenharmony_ci } else { 539c72fcc34Sopenharmony_ci free(buf); 540c72fcc34Sopenharmony_ci goto again; 541c72fcc34Sopenharmony_ci } 542c72fcc34Sopenharmony_ci 543c72fcc34Sopenharmony_ci free(buf); 544c72fcc34Sopenharmony_ci 545c72fcc34Sopenharmony_ci if (err < 0) 546c72fcc34Sopenharmony_ci return err; 547c72fcc34Sopenharmony_ci } 548c72fcc34Sopenharmony_ci 549c72fcc34Sopenharmony_ci // Expect to detect block_v110_data. 550c72fcc34Sopenharmony_ci if (header.type == BLOCK_TYPE_EXTENDED_V110_FORMAT) 551c72fcc34Sopenharmony_ci goto again; 552c72fcc34Sopenharmony_ci 553c72fcc34Sopenharmony_ci return 0; 554c72fcc34Sopenharmony_ci} 555c72fcc34Sopenharmony_ci 556c72fcc34Sopenharmony_cistatic int voc_parser_pre_process(struct container_context *cntr, 557c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 558c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 559c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 560c72fcc34Sopenharmony_ci uint64_t *byte_count) 561c72fcc34Sopenharmony_ci{ 562c72fcc34Sopenharmony_ci struct parser_state *state = cntr->private_data; 563c72fcc34Sopenharmony_ci unsigned int i; 564c72fcc34Sopenharmony_ci int err; 565c72fcc34Sopenharmony_ci 566c72fcc34Sopenharmony_ci err = detect_container_version(cntr); 567c72fcc34Sopenharmony_ci if (err < 0) 568c72fcc34Sopenharmony_ci return err; 569c72fcc34Sopenharmony_ci 570c72fcc34Sopenharmony_ci err = detect_format_block(cntr); 571c72fcc34Sopenharmony_ci if (err < 0) 572c72fcc34Sopenharmony_ci return err; 573c72fcc34Sopenharmony_ci 574c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 575c72fcc34Sopenharmony_ci if (format_maps[i].code_id == state->code_id) 576c72fcc34Sopenharmony_ci break; 577c72fcc34Sopenharmony_ci } 578c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 579c72fcc34Sopenharmony_ci return -EINVAL; 580c72fcc34Sopenharmony_ci 581c72fcc34Sopenharmony_ci *format = format_maps[i].format; 582c72fcc34Sopenharmony_ci *samples_per_frame = state->samples_per_frame; 583c72fcc34Sopenharmony_ci *frames_per_second = state->frames_per_second; 584c72fcc34Sopenharmony_ci 585c72fcc34Sopenharmony_ci // This program handles PCM frames in this data block only. 586c72fcc34Sopenharmony_ci *byte_count = state->byte_count; 587c72fcc34Sopenharmony_ci 588c72fcc34Sopenharmony_ci return 0; 589c72fcc34Sopenharmony_ci} 590c72fcc34Sopenharmony_ci 591c72fcc34Sopenharmony_cistruct builder_state { 592c72fcc34Sopenharmony_ci unsigned int version; 593c72fcc34Sopenharmony_ci bool extended; 594c72fcc34Sopenharmony_ci enum code_id code_id; 595c72fcc34Sopenharmony_ci 596c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 597c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 598c72fcc34Sopenharmony_ci}; 599c72fcc34Sopenharmony_ci 600c72fcc34Sopenharmony_cistatic int write_container_header(struct container_context *cntr, 601c72fcc34Sopenharmony_ci struct container_header *header) 602c72fcc34Sopenharmony_ci{ 603c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 604c72fcc34Sopenharmony_ci 605c72fcc34Sopenharmony_ci // Process container header. 606c72fcc34Sopenharmony_ci memcpy(header->magic, VOC_MAGIC, sizeof(header->magic)); 607c72fcc34Sopenharmony_ci header->hdr_size = htole16(sizeof(*header)); 608c72fcc34Sopenharmony_ci header->version = htole16(state->version); 609c72fcc34Sopenharmony_ci header->version_compr = htole16(0x1234 + ~state->version); 610c72fcc34Sopenharmony_ci 611c72fcc34Sopenharmony_ci return container_recursive_write(cntr, header, sizeof(*header)); 612c72fcc34Sopenharmony_ci} 613c72fcc34Sopenharmony_ci 614c72fcc34Sopenharmony_cistatic int write_v120_format_block(struct container_context *cntr, 615c72fcc34Sopenharmony_ci struct block_v120_format *block, 616c72fcc34Sopenharmony_ci unsigned int frames_per_second, 617c72fcc34Sopenharmony_ci uint64_t byte_count) 618c72fcc34Sopenharmony_ci{ 619c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 620c72fcc34Sopenharmony_ci 621c72fcc34Sopenharmony_ci block->type = BLOCK_TYPE_V120_DATA; 622c72fcc34Sopenharmony_ci build_block_data_size(block->size, 12 + byte_count); 623c72fcc34Sopenharmony_ci 624c72fcc34Sopenharmony_ci block->frames_per_second = htole32(frames_per_second); 625c72fcc34Sopenharmony_ci block->bits_per_sample = state->bytes_per_sample * 8; 626c72fcc34Sopenharmony_ci block->samples_per_frame = state->samples_per_frame; 627c72fcc34Sopenharmony_ci block->code_id = htole16(state->code_id); 628c72fcc34Sopenharmony_ci 629c72fcc34Sopenharmony_ci return container_recursive_write(cntr, block, sizeof(*block)); 630c72fcc34Sopenharmony_ci} 631c72fcc34Sopenharmony_ci 632c72fcc34Sopenharmony_cistatic int write_extended_v110_format_block(struct container_context *cntr, 633c72fcc34Sopenharmony_ci unsigned int frames_per_second, 634c72fcc34Sopenharmony_ci struct block_extended_v110_format *block) 635c72fcc34Sopenharmony_ci{ 636c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 637c72fcc34Sopenharmony_ci uint16_t time_const; 638c72fcc34Sopenharmony_ci int err; 639c72fcc34Sopenharmony_ci 640c72fcc34Sopenharmony_ci block->type = BLOCK_TYPE_EXTENDED_V110_FORMAT; 641c72fcc34Sopenharmony_ci build_block_data_size(block->size, 4); 642c72fcc34Sopenharmony_ci 643c72fcc34Sopenharmony_ci // 16 bits are available for this purpose. 644c72fcc34Sopenharmony_ci err = build_time_constant(frames_per_second, state->samples_per_frame, 645c72fcc34Sopenharmony_ci &time_const, true); 646c72fcc34Sopenharmony_ci if (err < 0) 647c72fcc34Sopenharmony_ci return err; 648c72fcc34Sopenharmony_ci block->time_const = htole16(time_const); 649c72fcc34Sopenharmony_ci block->code_id = htole16(state->code_id); 650c72fcc34Sopenharmony_ci 651c72fcc34Sopenharmony_ci if (state->samples_per_frame == 1) 652c72fcc34Sopenharmony_ci block->ch_mode = 0; 653c72fcc34Sopenharmony_ci else 654c72fcc34Sopenharmony_ci block->ch_mode = 1; 655c72fcc34Sopenharmony_ci 656c72fcc34Sopenharmony_ci return container_recursive_write(cntr, block, sizeof(*block)); 657c72fcc34Sopenharmony_ci} 658c72fcc34Sopenharmony_ci 659c72fcc34Sopenharmony_cistatic int write_v110_format_block(struct container_context *cntr, 660c72fcc34Sopenharmony_ci struct block_v110_data *block, 661c72fcc34Sopenharmony_ci unsigned int frames_per_second, 662c72fcc34Sopenharmony_ci uint64_t byte_count) 663c72fcc34Sopenharmony_ci{ 664c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 665c72fcc34Sopenharmony_ci uint16_t time_const; 666c72fcc34Sopenharmony_ci int err; 667c72fcc34Sopenharmony_ci 668c72fcc34Sopenharmony_ci block->type = BLOCK_TYPE_V110_DATA; 669c72fcc34Sopenharmony_ci build_block_data_size(block->size, 2 + byte_count); 670c72fcc34Sopenharmony_ci 671c72fcc34Sopenharmony_ci // These fields were obsoleted by extension. 672c72fcc34Sopenharmony_ci err = build_time_constant(frames_per_second, 1, &time_const, false); 673c72fcc34Sopenharmony_ci if (err < 0) 674c72fcc34Sopenharmony_ci return err; 675c72fcc34Sopenharmony_ci block->time_const = (uint8_t)time_const; 676c72fcc34Sopenharmony_ci block->code_id = state->code_id; 677c72fcc34Sopenharmony_ci return container_recursive_write(cntr, block, sizeof(*block)); 678c72fcc34Sopenharmony_ci} 679c72fcc34Sopenharmony_ci 680c72fcc34Sopenharmony_cistatic int write_data_blocks(struct container_context *cntr, 681c72fcc34Sopenharmony_ci unsigned int frames_per_second, 682c72fcc34Sopenharmony_ci uint64_t byte_count) 683c72fcc34Sopenharmony_ci{ 684c72fcc34Sopenharmony_ci union { 685c72fcc34Sopenharmony_ci struct container_header header; 686c72fcc34Sopenharmony_ci struct block_v110_data v110_data; 687c72fcc34Sopenharmony_ci struct block_extended_v110_format extended_v110_format; 688c72fcc34Sopenharmony_ci struct block_v120_format v120_format; 689c72fcc34Sopenharmony_ci } buf = {0}; 690c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 691c72fcc34Sopenharmony_ci int err; 692c72fcc34Sopenharmony_ci 693c72fcc34Sopenharmony_ci err = write_container_header(cntr, &buf.header); 694c72fcc34Sopenharmony_ci if (err < 0) 695c72fcc34Sopenharmony_ci return err; 696c72fcc34Sopenharmony_ci 697c72fcc34Sopenharmony_ci if (state->version == VOC_VERSION_1_20) { 698c72fcc34Sopenharmony_ci err = write_v120_format_block(cntr, &buf.v120_format, 699c72fcc34Sopenharmony_ci frames_per_second, byte_count); 700c72fcc34Sopenharmony_ci } else { 701c72fcc34Sopenharmony_ci if (state->extended) { 702c72fcc34Sopenharmony_ci err = write_extended_v110_format_block(cntr, 703c72fcc34Sopenharmony_ci frames_per_second, 704c72fcc34Sopenharmony_ci &buf.extended_v110_format); 705c72fcc34Sopenharmony_ci if (err < 0) 706c72fcc34Sopenharmony_ci return err; 707c72fcc34Sopenharmony_ci } 708c72fcc34Sopenharmony_ci err = write_v110_format_block(cntr, &buf.v110_data, 709c72fcc34Sopenharmony_ci frames_per_second, byte_count); 710c72fcc34Sopenharmony_ci } 711c72fcc34Sopenharmony_ci 712c72fcc34Sopenharmony_ci return err; 713c72fcc34Sopenharmony_ci} 714c72fcc34Sopenharmony_ci 715c72fcc34Sopenharmony_cistatic int voc_builder_pre_process(struct container_context *cntr, 716c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 717c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 718c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 719c72fcc34Sopenharmony_ci uint64_t *byte_count) 720c72fcc34Sopenharmony_ci{ 721c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 722c72fcc34Sopenharmony_ci unsigned int i; 723c72fcc34Sopenharmony_ci 724c72fcc34Sopenharmony_ci // Validate parameters. 725c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(format_maps); ++i) { 726c72fcc34Sopenharmony_ci if (format_maps[i].format == *format) 727c72fcc34Sopenharmony_ci break; 728c72fcc34Sopenharmony_ci } 729c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(format_maps)) 730c72fcc34Sopenharmony_ci return -EINVAL; 731c72fcc34Sopenharmony_ci state->code_id = format_maps[i].code_id; 732c72fcc34Sopenharmony_ci 733c72fcc34Sopenharmony_ci // Decide container version. 734c72fcc34Sopenharmony_ci if (*samples_per_frame > 2) 735c72fcc34Sopenharmony_ci state->version = VOC_VERSION_1_20; 736c72fcc34Sopenharmony_ci else 737c72fcc34Sopenharmony_ci state->version = format_maps[i].minimal_version; 738c72fcc34Sopenharmony_ci if (state->version == VOC_VERSION_1_10) { 739c72fcc34Sopenharmony_ci if (*samples_per_frame == 2) { 740c72fcc34Sopenharmony_ci for (i = 0; 741c72fcc34Sopenharmony_ci i < ARRAY_SIZE(ex_v110_time_consts); ++i) { 742c72fcc34Sopenharmony_ci if (ex_v110_time_consts[i].frames_per_second == 743c72fcc34Sopenharmony_ci *frames_per_second) 744c72fcc34Sopenharmony_ci break; 745c72fcc34Sopenharmony_ci } 746c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(ex_v110_time_consts)) 747c72fcc34Sopenharmony_ci state->version = VOC_VERSION_1_20; 748c72fcc34Sopenharmony_ci else 749c72fcc34Sopenharmony_ci state->extended = true; 750c72fcc34Sopenharmony_ci } else { 751c72fcc34Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v110_time_consts); ++i) { 752c72fcc34Sopenharmony_ci if (v110_time_consts[i].frames_per_second == 753c72fcc34Sopenharmony_ci *frames_per_second) 754c72fcc34Sopenharmony_ci break; 755c72fcc34Sopenharmony_ci } 756c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(v110_time_consts)) 757c72fcc34Sopenharmony_ci state->version = VOC_VERSION_1_20; 758c72fcc34Sopenharmony_ci } 759c72fcc34Sopenharmony_ci } 760c72fcc34Sopenharmony_ci 761c72fcc34Sopenharmony_ci state->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8; 762c72fcc34Sopenharmony_ci state->samples_per_frame = *samples_per_frame; 763c72fcc34Sopenharmony_ci 764c72fcc34Sopenharmony_ci return write_data_blocks(cntr, *frames_per_second, *byte_count); 765c72fcc34Sopenharmony_ci} 766c72fcc34Sopenharmony_ci 767c72fcc34Sopenharmony_cistatic int write_block_terminator(struct container_context *cntr) 768c72fcc34Sopenharmony_ci{ 769c72fcc34Sopenharmony_ci struct block_terminator block = {0}; 770c72fcc34Sopenharmony_ci 771c72fcc34Sopenharmony_ci block.type = BLOCK_TYPE_TERMINATOR; 772c72fcc34Sopenharmony_ci return container_recursive_write(cntr, &block, sizeof(block)); 773c72fcc34Sopenharmony_ci} 774c72fcc34Sopenharmony_ci 775c72fcc34Sopenharmony_cistatic int write_data_size(struct container_context *cntr, uint64_t byte_count) 776c72fcc34Sopenharmony_ci{ 777c72fcc34Sopenharmony_ci struct builder_state *state = cntr->private_data; 778c72fcc34Sopenharmony_ci off_t offset; 779c72fcc34Sopenharmony_ci uint8_t size_field[3]; 780c72fcc34Sopenharmony_ci int err; 781c72fcc34Sopenharmony_ci 782c72fcc34Sopenharmony_ci offset = sizeof(struct container_header) + sizeof(uint8_t); 783c72fcc34Sopenharmony_ci if (state->version == VOC_VERSION_1_10 && state->extended) 784c72fcc34Sopenharmony_ci offset += sizeof(struct block_extended_v110_format); 785c72fcc34Sopenharmony_ci err = container_seek_offset(cntr, offset); 786c72fcc34Sopenharmony_ci if (err < 0) 787c72fcc34Sopenharmony_ci return err; 788c72fcc34Sopenharmony_ci 789c72fcc34Sopenharmony_ci if (state->version == VOC_VERSION_1_10) 790c72fcc34Sopenharmony_ci offset = 2; 791c72fcc34Sopenharmony_ci else 792c72fcc34Sopenharmony_ci offset = 12; 793c72fcc34Sopenharmony_ci 794c72fcc34Sopenharmony_ci if (byte_count > cntr->max_size - offset) 795c72fcc34Sopenharmony_ci byte_count = cntr->max_size; 796c72fcc34Sopenharmony_ci else 797c72fcc34Sopenharmony_ci byte_count += offset; 798c72fcc34Sopenharmony_ci build_block_data_size(size_field, byte_count); 799c72fcc34Sopenharmony_ci 800c72fcc34Sopenharmony_ci return container_recursive_write(cntr, &size_field, sizeof(size_field)); 801c72fcc34Sopenharmony_ci} 802c72fcc34Sopenharmony_ci 803c72fcc34Sopenharmony_cistatic int voc_builder_post_process(struct container_context *cntr, 804c72fcc34Sopenharmony_ci uint64_t handled_byte_count) 805c72fcc34Sopenharmony_ci{ 806c72fcc34Sopenharmony_ci int err; 807c72fcc34Sopenharmony_ci 808c72fcc34Sopenharmony_ci err = write_block_terminator(cntr); 809c72fcc34Sopenharmony_ci if (err < 0) 810c72fcc34Sopenharmony_ci return err; 811c72fcc34Sopenharmony_ci 812c72fcc34Sopenharmony_ci return write_data_size(cntr, handled_byte_count); 813c72fcc34Sopenharmony_ci} 814c72fcc34Sopenharmony_ci 815c72fcc34Sopenharmony_ciconst struct container_parser container_parser_voc = { 816c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_VOC, 817c72fcc34Sopenharmony_ci .magic = VOC_MAGIC, 818c72fcc34Sopenharmony_ci .max_size = 0xffffff - // = UINT24_MAX. 819c72fcc34Sopenharmony_ci sizeof(struct block_terminator), 820c72fcc34Sopenharmony_ci .ops = { 821c72fcc34Sopenharmony_ci .pre_process = voc_parser_pre_process, 822c72fcc34Sopenharmony_ci }, 823c72fcc34Sopenharmony_ci .private_size = sizeof(struct parser_state), 824c72fcc34Sopenharmony_ci}; 825c72fcc34Sopenharmony_ci 826c72fcc34Sopenharmony_ciconst struct container_builder container_builder_voc = { 827c72fcc34Sopenharmony_ci .format = CONTAINER_FORMAT_VOC, 828c72fcc34Sopenharmony_ci .max_size = 0xffffff - // = UINT24_MAX. 829c72fcc34Sopenharmony_ci sizeof(struct block_terminator), 830c72fcc34Sopenharmony_ci .ops = { 831c72fcc34Sopenharmony_ci .pre_process = voc_builder_pre_process, 832c72fcc34Sopenharmony_ci .post_process = voc_builder_post_process, 833c72fcc34Sopenharmony_ci }, 834c72fcc34Sopenharmony_ci .private_size = sizeof(struct builder_state), 835c72fcc34Sopenharmony_ci}; 836