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