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