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