Blame axfer/container-riff-wave.c

Packit Service a9274b
// SPDX-License-Identifier: GPL-2.0
Packit Service a9274b
//
Packit Service a9274b
// container-riff-wave.c - a parser/builder for a container of RIFF/Wave File.
Packit Service a9274b
//
Packit Service a9274b
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
Packit Service a9274b
//
Packit Service a9274b
// Licensed under the terms of the GNU General Public License, version 2.
Packit Service a9274b
Packit Service a9274b
#include "container.h"
Packit Service a9274b
#include "misc.h"
Packit Service a9274b
Packit Service a9274b
// Not portable to all of UNIX platforms.
Packit Service a9274b
#include <endian.h>
Packit Service a9274b
Packit Service a9274b
// References:
Packit Service a9274b
// - 'Resource Interchange File Format (RIFF)' at msdn.microsoft.com
Packit Service a9274b
// - 'Multiple channel audio data and WAVE files' at msdn.microsoft.com
Packit Service a9274b
// - RFC 2361 'WAVE and AVI Codec Registries' at ietf.org
Packit Service a9274b
// - 'mmreg.h' in Wine project
Packit Service a9274b
// - 'mmreg.h' in ReactOS project
Packit Service a9274b
Packit Service a9274b
#define RIFF_MAGIC		"RIF"	// A common part.
Packit Service a9274b
Packit Service a9274b
#define RIFF_CHUNK_ID_LE	"RIFF"
Packit Service a9274b
#define RIFF_CHUNK_ID_BE	"RIFX"
Packit Service a9274b
#define RIFF_FORM_WAVE		"WAVE"
Packit Service a9274b
#define FMT_SUBCHUNK_ID		"fmt "
Packit Service a9274b
#define DATA_SUBCHUNK_ID	"data"
Packit Service a9274b
Packit Service a9274b
// See 'WAVE and AVI Codec Registries (Historic Registry)' in 'iana.org'.
Packit Service a9274b
// https://www.iana.org/assignments/wave-avi-codec-registry/
Packit Service a9274b
enum wave_format {
Packit Service a9274b
	WAVE_FORMAT_PCM			= 0x0001,
Packit Service a9274b
	WAVE_FORMAT_ADPCM		= 0x0002,
Packit Service a9274b
	WAVE_FORMAT_IEEE_FLOAT		= 0x0003,
Packit Service a9274b
	WAVE_FORMAT_ALAW		= 0x0006,
Packit Service a9274b
	WAVE_FORMAT_MULAW		= 0x0007,
Packit Service a9274b
	WAVE_FORMAT_G723_ADPCM		= 0x0014,
Packit Service a9274b
	// The others are not supported.
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct format_map {
Packit Service a9274b
	enum wave_format wformat;
Packit Service a9274b
	snd_pcm_format_t format;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static const struct format_map format_maps[] = {
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_U8},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S16_LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S16_BE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S24_LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S24_BE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S32_LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S32_BE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S24_3LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S24_3BE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S20_3LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S20_3BE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S18_3LE},
Packit Service a9274b
	{WAVE_FORMAT_PCM,	SND_PCM_FORMAT_S18_3BE},
Packit Service a9274b
	{WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT_LE},
Packit Service a9274b
	{WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT_BE},
Packit Service a9274b
	{WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT64_LE},
Packit Service a9274b
	{WAVE_FORMAT_IEEE_FLOAT, SND_PCM_FORMAT_FLOAT64_BE},
Packit Service a9274b
	{WAVE_FORMAT_ALAW,	SND_PCM_FORMAT_A_LAW},
Packit Service a9274b
	{WAVE_FORMAT_MULAW,	SND_PCM_FORMAT_MU_LAW},
Packit Service a9274b
	// Below sample formats are not currently supported, due to width of
Packit Service a9274b
	// its sample.
Packit Service a9274b
	//  - WAVE_FORMAT_ADPCM
Packit Service a9274b
	//  - WAVE_FORMAT_G723_ADPCM
Packit Service a9274b
	//  - WAVE_FORMAT_G723_ADPCM
Packit Service a9274b
	//  - WAVE_FORMAT_G723_ADPCM
Packit Service a9274b
	//  - WAVE_FORMAT_G723_ADPCM
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct riff_chunk {
Packit Service a9274b
	uint8_t id[4];
Packit Service a9274b
	uint32_t size;
Packit Service a9274b
Packit Service a9274b
	uint8_t data[0];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct riff_chunk_data {
Packit Service a9274b
	uint8_t id[4];
Packit Service a9274b
Packit Service a9274b
	uint8_t subchunks[0];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct riff_subchunk {
Packit Service a9274b
	uint8_t id[4];
Packit Service a9274b
	uint32_t size;
Packit Service a9274b
Packit Service a9274b
	uint8_t data[0];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct wave_fmt_subchunk {
Packit Service a9274b
	uint8_t id[4];
Packit Service a9274b
	uint32_t size;
Packit Service a9274b
Packit Service a9274b
	uint16_t format;
Packit Service a9274b
	uint16_t samples_per_frame;
Packit Service a9274b
	uint32_t frames_per_second;
Packit Service a9274b
	uint32_t average_bytes_per_second;
Packit Service a9274b
	uint16_t bytes_per_frame;
Packit Service a9274b
	uint16_t bits_per_sample;
Packit Service a9274b
	uint8_t extension[0];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct wave_data_subchunk {
Packit Service a9274b
	uint8_t id[4];
Packit Service a9274b
	uint32_t size;
Packit Service a9274b
Packit Service a9274b
	uint8_t frames[0];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
struct parser_state {
Packit Service a9274b
	bool be;
Packit Service a9274b
	enum wave_format format;
Packit Service a9274b
	unsigned int samples_per_frame;
Packit Service a9274b
	unsigned int frames_per_second;
Packit Service a9274b
	unsigned int average_bytes_per_second;
Packit Service a9274b
	unsigned int bytes_per_frame;
Packit Service a9274b
	unsigned int bytes_per_sample;
Packit Service a9274b
	unsigned int avail_bits_in_sample;
Packit Service a9274b
	unsigned int byte_count;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int parse_riff_chunk_header(struct parser_state *state,
Packit Service a9274b
				   struct riff_chunk *chunk,
Packit Service a9274b
				   uint64_t *byte_count)
Packit Service a9274b
{
Packit Service a9274b
	if (!memcmp(chunk->id, RIFF_CHUNK_ID_BE, sizeof(chunk->id)))
Packit Service a9274b
		state->be = true;
Packit Service a9274b
	else if (!memcmp(chunk->id, RIFF_CHUNK_ID_LE, sizeof(chunk->id)))
Packit Service a9274b
		state->be = false;
Packit Service a9274b
	else
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	if (state->be)
Packit Service a9274b
		*byte_count = be32toh(chunk->size);
Packit Service a9274b
	else
Packit Service a9274b
		*byte_count = le32toh(chunk->size);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_riff_chunk(struct container_context *cntr,
Packit Service a9274b
			    uint64_t *byte_count)
Packit Service a9274b
{
Packit Service a9274b
	struct parser_state *state = cntr->private_data;
Packit Service a9274b
	union {
Packit Service a9274b
		struct riff_chunk chunk;
Packit Service a9274b
		struct riff_chunk_data chunk_data;
Packit Service a9274b
	} buf = {0};
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	// Chunk header. 4 bytes were alread read to detect container type.
Packit Service a9274b
	memcpy(buf.chunk.id, cntr->magic, sizeof(cntr->magic));
Packit Service a9274b
	err = container_recursive_read(cntr,
Packit Service a9274b
				       (char *)&buf.chunk + sizeof(cntr->magic),
Packit Service a9274b
				       sizeof(buf.chunk) - sizeof(cntr->magic));
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
	if (cntr->eof)
Packit Service a9274b
		return 0;
Packit Service a9274b
Packit Service a9274b
	err = parse_riff_chunk_header(state, &buf.chunk, byte_count);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// Chunk data header.
Packit Service a9274b
	err = container_recursive_read(cntr, &buf, sizeof(buf.chunk_data));
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
	if (cntr->eof)
Packit Service a9274b
		return 0;
Packit Service a9274b
Packit Service a9274b
	if (memcmp(buf.chunk_data.id, RIFF_FORM_WAVE,
Packit Service a9274b
		   sizeof(buf.chunk_data.id)))
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_wave_fmt_subchunk(struct parser_state *state,
Packit Service a9274b
				   struct wave_fmt_subchunk *subchunk)
Packit Service a9274b
{
Packit Service a9274b
	if (state->be) {
Packit Service a9274b
		state->format = be16toh(subchunk->format);
Packit Service a9274b
		state->samples_per_frame = be16toh(subchunk->samples_per_frame);
Packit Service a9274b
		state->frames_per_second = be32toh(subchunk->frames_per_second);
Packit Service a9274b
		state->average_bytes_per_second =
Packit Service a9274b
				be32toh(subchunk->average_bytes_per_second);
Packit Service a9274b
		state->bytes_per_frame = be16toh(subchunk->bytes_per_frame);
Packit Service a9274b
		state->avail_bits_in_sample =
Packit Service a9274b
					be16toh(subchunk->bits_per_sample);
Packit Service a9274b
	} else {
Packit Service a9274b
		state->format = le16toh(subchunk->format);
Packit Service a9274b
		state->samples_per_frame = le16toh(subchunk->samples_per_frame);
Packit Service a9274b
		state->frames_per_second = le32toh(subchunk->frames_per_second);
Packit Service a9274b
		state->average_bytes_per_second =
Packit Service a9274b
				le32toh(subchunk->average_bytes_per_second);
Packit Service a9274b
		state->bytes_per_frame = le16toh(subchunk->bytes_per_frame);
Packit Service a9274b
		state->avail_bits_in_sample =
Packit Service a9274b
					le16toh(subchunk->bits_per_sample);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (state->average_bytes_per_second !=
Packit Service a9274b
			state->bytes_per_frame * state->frames_per_second)
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_wave_data_subchunk(struct parser_state *state,
Packit Service a9274b
				    struct wave_data_subchunk *subchunk)
Packit Service a9274b
{
Packit Service a9274b
	if (state->be)
Packit Service a9274b
		state->byte_count = be32toh(subchunk->size);
Packit Service a9274b
	else
Packit Service a9274b
		state->byte_count = le32toh(subchunk->size);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_wave_subchunk(struct container_context *cntr)
Packit Service a9274b
{
Packit Service a9274b
	union {
Packit Service a9274b
		struct riff_subchunk subchunk;
Packit Service a9274b
		struct wave_fmt_subchunk fmt_subchunk;
Packit Service a9274b
		struct wave_data_subchunk data_subchunk;
Packit Service a9274b
	} buf = {0};
Packit Service a9274b
	enum {
Packit Service a9274b
		SUBCHUNK_TYPE_UNKNOWN = -1,
Packit Service a9274b
		SUBCHUNK_TYPE_FMT,
Packit Service a9274b
		SUBCHUNK_TYPE_DATA,
Packit Service a9274b
	} subchunk_type;
Packit Service a9274b
	struct parser_state *state = cntr->private_data;
Packit Service a9274b
	unsigned int required_size;
Packit Service a9274b
	unsigned int subchunk_data_size;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	while (1) {
Packit Service a9274b
		err = container_recursive_read(cntr, &buf,
Packit Service a9274b
					       sizeof(buf.subchunk));
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			return err;
Packit Service a9274b
		if (cntr->eof)
Packit Service a9274b
			return 0;
Packit Service a9274b
Packit Service a9274b
		// Calculate the size of subchunk data.
Packit Service a9274b
		if (state->be)
Packit Service a9274b
			subchunk_data_size = be32toh(buf.subchunk.size);
Packit Service a9274b
		else
Packit Service a9274b
			subchunk_data_size = le32toh(buf.subchunk.size);
Packit Service a9274b
Packit Service a9274b
		// Detect type of subchunk.
Packit Service a9274b
		if (!memcmp(buf.subchunk.id, FMT_SUBCHUNK_ID,
Packit Service a9274b
			    sizeof(buf.subchunk.id))) {
Packit Service a9274b
			subchunk_type = SUBCHUNK_TYPE_FMT;
Packit Service a9274b
		} else if (!memcmp(buf.subchunk.id, DATA_SUBCHUNK_ID,
Packit Service a9274b
				   sizeof(buf.subchunk.id))) {
Packit Service a9274b
			subchunk_type = SUBCHUNK_TYPE_DATA;
Packit Service a9274b
		} else {
Packit Service a9274b
			subchunk_type = SUBCHUNK_TYPE_UNKNOWN;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		if (subchunk_type != SUBCHUNK_TYPE_UNKNOWN) {
Packit Service a9274b
			// Parse data of this subchunk.
Packit Service a9274b
			if (subchunk_type == SUBCHUNK_TYPE_FMT) {
Packit Service a9274b
				required_size =
Packit Service a9274b
					sizeof(struct wave_fmt_subchunk) -
Packit Service a9274b
					sizeof(struct riff_chunk);
Packit Service a9274b
			} else {
Packit Service a9274b
				required_size =
Packit Service a9274b
					sizeof(struct wave_data_subchunk)-
Packit Service a9274b
					sizeof(struct riff_chunk);
Packit Service a9274b
			}
Packit Service a9274b
Packit Service a9274b
			if (subchunk_data_size < required_size)
Packit Service a9274b
				return -EINVAL;
Packit Service a9274b
Packit Service a9274b
			err = container_recursive_read(cntr, &buf.subchunk.data,
Packit Service a9274b
						       required_size);
Packit Service a9274b
			if (err < 0)
Packit Service a9274b
				return err;
Packit Service a9274b
			if (cntr->eof)
Packit Service a9274b
				return 0;
Packit Service a9274b
			subchunk_data_size -= required_size;
Packit Service a9274b
Packit Service a9274b
			if (subchunk_type == SUBCHUNK_TYPE_FMT) {
Packit Service a9274b
				err = parse_wave_fmt_subchunk(state,
Packit Service a9274b
							&buf.fmt_subchunk);
Packit Service a9274b
			} else if (subchunk_type == SUBCHUNK_TYPE_DATA) {
Packit Service a9274b
				err = parse_wave_data_subchunk(state,
Packit Service a9274b
							 &buf.data_subchunk);
Packit Service a9274b
			}
Packit Service a9274b
			if (err < 0)
Packit Service a9274b
				return err;
Packit Service a9274b
Packit Service a9274b
			// Found frame data.
Packit Service a9274b
			if (subchunk_type == SUBCHUNK_TYPE_DATA)
Packit Service a9274b
				break;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		// Go to next subchunk.
Packit Service a9274b
		while (subchunk_data_size > 0) {
Packit Service a9274b
			unsigned int consume;
Packit Service a9274b
Packit Service a9274b
			if (subchunk_data_size > sizeof(buf))
Packit Service a9274b
				consume = sizeof(buf);
Packit Service a9274b
			else
Packit Service a9274b
				consume = subchunk_data_size;
Packit Service a9274b
Packit Service a9274b
			err = container_recursive_read(cntr, &buf, consume);
Packit Service a9274b
			if (err < 0)
Packit Service a9274b
				return err;
Packit Service a9274b
			if (cntr->eof)
Packit Service a9274b
				return 0;
Packit Service a9274b
			subchunk_data_size -= consume;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_riff_wave_format(struct container_context *cntr)
Packit Service a9274b
{
Packit Service a9274b
	uint64_t byte_count;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	err = parse_riff_chunk(cntr, &byte_count);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	err = parse_wave_subchunk(cntr);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int wave_parser_pre_process(struct container_context *cntr,
Packit Service a9274b
				   snd_pcm_format_t *format,
Packit Service a9274b
				   unsigned int *samples_per_frame,
Packit Service a9274b
				   unsigned int *frames_per_second,
Packit Service a9274b
				   uint64_t *byte_count)
Packit Service a9274b
{
Packit Service a9274b
	struct parser_state *state = cntr->private_data;
Packit Service a9274b
	int phys_width;
Packit Service a9274b
	const struct format_map *map;
Packit Service a9274b
	int i;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	err = parse_riff_wave_format(cntr);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	phys_width = 8 * state->average_bytes_per_second /
Packit Service a9274b
		     state->samples_per_frame / state->frames_per_second;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(format_maps); ++i) {
Packit Service a9274b
		map = &format_maps[i];
Packit Service a9274b
		if (state->format != map->wformat)
Packit Service a9274b
			continue;
Packit Service a9274b
		if (state->avail_bits_in_sample !=
Packit Service a9274b
					snd_pcm_format_width(map->format))
Packit Service a9274b
			continue;
Packit Service a9274b
		if (phys_width != snd_pcm_format_physical_width(map->format))
Packit Service a9274b
			continue;
Packit Service a9274b
Packit Service a9274b
		if (state->be && snd_pcm_format_big_endian(map->format) != 1)
Packit Service a9274b
			continue;
Packit Service a9274b
Packit Service a9274b
		break;
Packit Service a9274b
	}
Packit Service a9274b
	if (i == ARRAY_SIZE(format_maps))
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	// Set parameters.
Packit Service a9274b
	*format = format_maps[i].format;
Packit Service a9274b
	*samples_per_frame = state->samples_per_frame;
Packit Service a9274b
	*frames_per_second = state->frames_per_second;
Packit Service a9274b
	*byte_count = state->byte_count;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
struct builder_state {
Packit Service a9274b
	bool be;
Packit Service a9274b
	enum wave_format format;
Packit Service a9274b
	unsigned int avail_bits_in_sample;
Packit Service a9274b
	unsigned int bytes_per_sample;
Packit Service a9274b
	unsigned int samples_per_frame;
Packit Service a9274b
	unsigned int frames_per_second;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static void build_riff_chunk_header(struct riff_chunk *chunk,
Packit Service a9274b
				    uint64_t byte_count, bool be)
Packit Service a9274b
{
Packit Service a9274b
	uint64_t data_size = sizeof(struct riff_chunk_data) +
Packit Service a9274b
			     sizeof(struct wave_fmt_subchunk) +
Packit Service a9274b
			     sizeof(struct wave_data_subchunk) + byte_count;
Packit Service a9274b
Packit Service a9274b
	if (be) {
Packit Service a9274b
		memcpy(chunk->id, RIFF_CHUNK_ID_BE, sizeof(chunk->id));
Packit Service a9274b
		chunk->size = htobe32(data_size);
Packit Service a9274b
	} else {
Packit Service a9274b
		memcpy(chunk->id, RIFF_CHUNK_ID_LE, sizeof(chunk->id));
Packit Service a9274b
		chunk->size = htole32(data_size);
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void build_subchunk_header(struct riff_subchunk *subchunk,
Packit Service a9274b
				  const char *const form, uint64_t size,
Packit Service a9274b
				  bool be)
Packit Service a9274b
{
Packit Service a9274b
	memcpy(subchunk->id, form, sizeof(subchunk->id));
Packit Service a9274b
	if (be)
Packit Service a9274b
		subchunk->size = htobe32(size);
Packit Service a9274b
	else
Packit Service a9274b
		subchunk->size = htole32(size);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void build_wave_format_subchunk(struct wave_fmt_subchunk *subchunk,
Packit Service a9274b
				       struct builder_state *state)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int bytes_per_frame =
Packit Service a9274b
			state->bytes_per_sample * state->samples_per_frame;
Packit Service a9274b
	unsigned int average_bytes_per_second = state->bytes_per_sample *
Packit Service a9274b
			state->samples_per_frame * state->frames_per_second;
Packit Service a9274b
	uint64_t size;
Packit Service a9274b
Packit Service a9274b
	// No extensions.
Packit Service a9274b
	size = sizeof(struct wave_fmt_subchunk) - sizeof(struct riff_subchunk);
Packit Service a9274b
	build_subchunk_header((struct riff_subchunk *)subchunk, FMT_SUBCHUNK_ID,
Packit Service a9274b
			      size, state->be);
Packit Service a9274b
Packit Service a9274b
	if (state->be) {
Packit Service a9274b
		subchunk->format = htobe16(state->format);
Packit Service a9274b
		subchunk->samples_per_frame = htobe16(state->samples_per_frame);
Packit Service a9274b
		subchunk->frames_per_second = htobe32(state->frames_per_second);
Packit Service a9274b
		subchunk->average_bytes_per_second =
Packit Service a9274b
					htobe32(average_bytes_per_second);
Packit Service a9274b
		subchunk->bytes_per_frame = htobe16(bytes_per_frame);
Packit Service a9274b
		subchunk->bits_per_sample =
Packit Service a9274b
					htobe16(state->avail_bits_in_sample);
Packit Service a9274b
	} else {
Packit Service a9274b
		subchunk->format = htole16(state->format);
Packit Service a9274b
		subchunk->samples_per_frame = htole16(state->samples_per_frame);
Packit Service a9274b
		subchunk->frames_per_second = htole32(state->frames_per_second);
Packit Service a9274b
		subchunk->average_bytes_per_second =
Packit Service a9274b
					htole32(average_bytes_per_second);
Packit Service a9274b
		subchunk->bytes_per_frame = htole16(bytes_per_frame);
Packit Service a9274b
		subchunk->bits_per_sample =
Packit Service a9274b
					htole16(state->avail_bits_in_sample);
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void build_wave_data_subchunk(struct wave_data_subchunk *subchunk,
Packit Service a9274b
				     uint64_t byte_count, bool be)
Packit Service a9274b
{
Packit Service a9274b
	build_subchunk_header((struct riff_subchunk *)subchunk,
Packit Service a9274b
			      DATA_SUBCHUNK_ID, byte_count, be);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int write_riff_chunk_for_wave(struct container_context *cntr,
Packit Service a9274b
				     uint64_t byte_count)
Packit Service a9274b
{
Packit Service a9274b
	struct builder_state *state = cntr->private_data;
Packit Service a9274b
	union {
Packit Service a9274b
		struct riff_chunk chunk;
Packit Service a9274b
		struct riff_chunk_data chunk_data;
Packit Service a9274b
		struct wave_fmt_subchunk fmt_subchunk;
Packit Service a9274b
		struct wave_data_subchunk data_subchunk;
Packit Service a9274b
	} buf = {0};
Packit Service a9274b
	uint64_t total_byte_count;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	// Chunk header.
Packit Service a9274b
	total_byte_count = sizeof(struct riff_chunk_data) +
Packit Service a9274b
			   sizeof(struct wave_fmt_subchunk) +
Packit Service a9274b
			   sizeof(struct wave_data_subchunk);
Packit Service a9274b
	if (byte_count > cntr->max_size - total_byte_count)
Packit Service a9274b
		total_byte_count = cntr->max_size;
Packit Service a9274b
	else
Packit Service a9274b
		total_byte_count += byte_count;
Packit Service a9274b
	build_riff_chunk_header(&buf.chunk, total_byte_count, state->be);
Packit Service a9274b
	err = container_recursive_write(cntr, &buf, sizeof(buf.chunk));
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// Chunk data header.
Packit Service a9274b
	memcpy(buf.chunk_data.id, RIFF_FORM_WAVE, sizeof(buf.chunk_data.id));
Packit Service a9274b
	err = container_recursive_write(cntr, &buf, sizeof(buf.chunk_data));
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// A subchunk in the chunk data for WAVE format.
Packit Service a9274b
	build_wave_format_subchunk(&buf.fmt_subchunk, state);
Packit Service a9274b
	err = container_recursive_write(cntr, &buf, sizeof(buf.fmt_subchunk));
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// A subchunk in the chunk data for WAVE data.
Packit Service a9274b
	build_wave_data_subchunk(&buf.data_subchunk, byte_count, state->be);
Packit Service a9274b
	return container_recursive_write(cntr, &buf, sizeof(buf.data_subchunk));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int wave_builder_pre_process(struct container_context *cntr,
Packit Service a9274b
				    snd_pcm_format_t *format,
Packit Service a9274b
				    unsigned int *samples_per_frame,
Packit Service a9274b
				    unsigned int *frames_per_second,
Packit Service a9274b
				    uint64_t *byte_count)
Packit Service a9274b
{
Packit Service a9274b
	struct builder_state *state = cntr->private_data;
Packit Service a9274b
	int i;
Packit Service a9274b
Packit Service a9274b
	// Validate parameters.
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(format_maps); ++i) {
Packit Service a9274b
		if (format_maps[i].format == *format)
Packit Service a9274b
			break;
Packit Service a9274b
	}
Packit Service a9274b
	if (i == ARRAY_SIZE(format_maps))
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	state->format = format_maps[i].wformat;
Packit Service a9274b
	state->avail_bits_in_sample = snd_pcm_format_width(*format);
Packit Service a9274b
	state->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8;
Packit Service a9274b
	state->samples_per_frame = *samples_per_frame;
Packit Service a9274b
	state->frames_per_second = *frames_per_second;
Packit Service a9274b
Packit Service a9274b
	state->be = (snd_pcm_format_big_endian(*format) == 1);
Packit Service a9274b
Packit Service a9274b
	return write_riff_chunk_for_wave(cntr, *byte_count);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int wave_builder_post_process(struct container_context *cntr,
Packit Service a9274b
				     uint64_t handled_byte_count)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	err = container_seek_offset(cntr, 0);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	return write_riff_chunk_for_wave(cntr, handled_byte_count);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
const struct container_parser container_parser_riff_wave = {
Packit Service a9274b
	.format = CONTAINER_FORMAT_RIFF_WAVE,
Packit Service a9274b
	.magic =  RIFF_MAGIC,
Packit Service a9274b
	.max_size = UINT32_MAX -
Packit Service a9274b
		    sizeof(struct riff_chunk_data) -
Packit Service a9274b
		    sizeof(struct wave_fmt_subchunk) -
Packit Service a9274b
		    sizeof(struct wave_data_subchunk),
Packit Service a9274b
	.ops = {
Packit Service a9274b
		.pre_process	= wave_parser_pre_process,
Packit Service a9274b
	},
Packit Service a9274b
	.private_size = sizeof(struct parser_state),
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
const struct container_builder container_builder_riff_wave = {
Packit Service a9274b
	.format = CONTAINER_FORMAT_RIFF_WAVE,
Packit Service a9274b
	.max_size = UINT32_MAX -
Packit Service a9274b
		    sizeof(struct riff_chunk_data) -
Packit Service a9274b
		    sizeof(struct wave_fmt_subchunk) -
Packit Service a9274b
		    sizeof(struct wave_data_subchunk),
Packit Service a9274b
	.ops = {
Packit Service a9274b
		.pre_process	= wave_builder_pre_process,
Packit Service a9274b
		.post_process	= wave_builder_post_process,
Packit Service a9274b
	},
Packit Service a9274b
	.private_size = sizeof(struct builder_state),
Packit Service a9274b
};