@@ -7,7 +7,8 @@ bin_PROGRAMS = aplay
man_MANS = aplay.1 arecord.1
noinst_HEADERS = \
formats.h \
- container.h
+ container.h \
+ aligner.h
aplay_SOURCES = \
formats.h \
@@ -17,6 +18,8 @@ aplay_SOURCES = \
container-riff-wave.c \
container-au.c \
container-voc.c
+ aligner.h \
+ aligner.c
EXTRA_DIST = aplay.1 arecord.1
EXTRA_CLEAN = arecord
new file mode 100644
@@ -0,0 +1,104 @@
+/*
+ * aligner.c - a muxer/demuxer between data frams and file containers.
+ *
+ * Copyright (c) 2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "aligner.h"
+
+#include <gettext.h>
+
+static const char *const aligner_type_labels[] = {
+ [ALIGNER_TYPE_MUXER] = "muxer",
+ [ALIGNER_TYPE_DEMUXER] = "demuxer",
+};
+
+static const char *const aligner_target_labels[] = {
+ [ALIGNER_TARGET_COUNT] = "",
+};
+
+int aligner_context_init(struct aligner_context *aligner,
+ enum aligner_type type, unsigned int cntr_count,
+ unsigned int verbose)
+{
+ const struct aligner_data *data = NULL;
+
+ aligner->ops = &data->ops;
+ aligner->type = type;
+
+ aligner->private_data = malloc(data->private_size);
+ if (aligner->private_data == NULL)
+ return -ENOMEM;
+ memset(aligner->private_data, 0, data->private_size);
+
+ aligner->cntr_count = cntr_count;
+ aligner->verbose = verbose;
+
+ return 0;
+}
+
+int aligner_context_pre_process(struct aligner_context *aligner,
+ snd_pcm_access_t access,
+ snd_pcm_format_t format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_buffer,
+ struct container_context *cntrs)
+{
+ int err;
+
+ /*
+ * The purpose of multiple target is to mux/demux each channels to/from
+ * containers.
+ */
+ if (aligner->target == ALIGNER_TARGET_MULTIPLE &&
+ samples_per_frame != aligner->cntr_count)
+ return -EINVAL;
+
+ aligner->access = access;
+ aligner->bytes_per_sample = snd_pcm_format_physical_width(format) / 8;
+ aligner->samples_per_frame = samples_per_frame;
+ aligner->frames_per_buffer = frames_per_buffer;
+
+ err = aligner->ops->pre_process(aligner, cntrs, aligner->cntr_count);
+ if (err < 0)
+ return err;
+
+ if (aligner->verbose > 0) {
+ printf(_("Aligner: %s\n"),
+ aligner_type_labels[aligner->type]);
+ printf(_(" target: %s\n"),
+ aligner_target_labels[aligner->target]);
+ printf(_(" access: %s\n"),
+ snd_pcm_access_name(aligner->access));
+ printf(_(" bytes/sample: %u\n"), aligner->bytes_per_sample);
+ printf(_(" samples/frame: %u\n"), aligner->samples_per_frame);
+ printf(_(" frames/buffer: %lu\n"), aligner->frames_per_buffer);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int aligner_context_process_frames(struct aligner_context *aligner,
+ void *frame_buffer,
+ unsigned int *frame_count,
+ struct container_context *cntrs)
+{
+ return aligner->ops->process_frames(aligner, frame_buffer, frame_count,
+ cntrs, aligner->cntr_count);
+}
+
+void aligner_context_post_process(struct aligner_context *aligner)
+{
+ if (aligner->ops && aligner->ops->post_process)
+ aligner->ops->post_process(aligner);
+}
+
+void aligner_context_destroy(struct aligner_context *aligner)
+{
+ if (aligner->private_data)
+ free(aligner->private_data);
+ aligner->private_data = NULL;
+}
new file mode 100644
@@ -0,0 +1,80 @@
+/*
+ * aligner.h - a header muxer/demuxer between data frames and file containers.
+ *
+ * Copyright (c) 2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef __ALSA_UTILS_APLAY_ALIGNER__H_
+#define __ALSA_UTILS_APLAY_ALIGNER__H_
+
+#include "container.h"
+
+#include <string.h>
+
+enum aligner_type {
+ ALIGNER_TYPE_MUXER = 0,
+ ALIGNER_TYPE_DEMUXER,
+ ALIGNER_TYPE_COUNT,
+};
+
+enum aligner_target {
+ ALIGNER_TARGET_COUNT,
+};
+
+struct aligner_ops;
+
+struct aligner_context {
+ enum aligner_type type;
+ enum aligner_target target;
+ const struct aligner_ops *ops;
+ unsigned int private_size;
+
+ void *private_data;
+ unsigned int cntr_count;
+
+ /* A part of parameters of PCM substream. */
+ snd_pcm_access_t access;
+ unsigned int bytes_per_sample;
+ unsigned int samples_per_frame;
+ snd_pcm_uframes_t frames_per_buffer;
+
+ unsigned int verbose;
+};
+
+int aligner_context_init(struct aligner_context *aligner,
+ enum aligner_type type, unsigned int cntr_count,
+ unsigned int verbose);
+int aligner_context_pre_process(struct aligner_context *aligner,
+ snd_pcm_access_t access,
+ snd_pcm_format_t format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_buffer,
+ struct container_context *cntrs);
+int aligner_context_process_frames(struct aligner_context *aligner,
+ void *frame_buffer,
+ unsigned int *frame_count,
+ struct container_context *cntrs);
+void aligner_context_post_process(struct aligner_context *aligner);
+void aligner_context_destroy(struct aligner_context *aligner);
+
+/* For internal use in 'aligner' module. */
+
+struct aligner_ops {
+ int (*pre_process)(struct aligner_context *aligner,
+ struct container_context *cntrs,
+ unsigned int cntr_count);
+ int (*process_frames)(struct aligner_context *aligner,
+ void *frame_buffer, unsigned int *frame_count,
+ struct container_context *cntrs,
+ unsigned int cntr_count);
+ void (*post_process)(struct aligner_context *aligner);
+};
+
+struct aligner_data {
+ struct aligner_ops ops;
+ unsigned int private_size;
+};
+
+#endif