aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:07:23 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:07:23 +0000
commit46026a4ff1f68e7cf694c4564283687551e93398 (patch)
tree0e78b5091d67fc1025e4628ca2558a3c94f5a8ce
parentcf88eafb16038b092ee9fa14c45be927dc41a70e (diff)
parent82eab38b0705f238e583226a49d22a1f391999bf (diff)
downloadtinyalsa_new-android13-mainline-wifi-release.tar.gz
Change-Id: Ife6ae7d404d989e204990da8ca58c99480da0052
-rw-r--r--Android.bp11
-rw-r--r--NOTICE2
-rw-r--r--OWNERS5
-rw-r--r--WORKSPACE2
-rw-r--r--examples/plugins/Android.bp24
-rw-r--r--examples/plugins/sample_mixer_plugin.c320
-rw-r--r--examples/plugins/sample_pcm_plugin.c332
-rw-r--r--examples/sndcardparser/Android.bp15
-rw-r--r--examples/sndcardparser/sample_sndcardparser.c270
-rw-r--r--include/tinyalsa/meson.build2
-rw-r--r--include/tinyalsa/pcm.h10
-rw-r--r--src/mixer.c19
-rw-r--r--src/mixer_plugin.c6
-rw-r--r--src/pcm_hw.c2
-rw-r--r--src/pcm_plugin.c9
-rw-r--r--utils/tinyplay.c112
16 files changed, 1078 insertions, 63 deletions
diff --git a/Android.bp b/Android.bp
index d6fec57..8fc5ed6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,10 +49,11 @@ cc_library {
darwin: {
enabled: false,
},
+ bionic: {
+ system_shared_libs: ["libc", "libdl"],
+ },
},
- system_shared_libs: ["libc", "libdl"],
-
sanitize: {
integer_overflow: true,
misc_undefined: ["bounds"],
@@ -63,6 +64,12 @@ cc_library {
},
}
+cc_library_headers {
+ name: "libtinyalsav2_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+}
+
cc_binary {
name: "tinyplay2",
host_supported: true,
diff --git a/NOTICE b/NOTICE
index 5debd99..5e78690 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,5 @@
Copyright 2011, The Android Open Source Project
+Copyright (c) 2019, The Linux Foundation.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -22,4 +23,3 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
-
diff --git a/OWNERS b/OWNERS
index e1e3676..ccb311a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1,5 @@
dvdli@google.com
-gkasten@google.com
+elaurent@google.com
+mnaganov@google.com
+carterhsu@google.com
+
diff --git a/WORKSPACE b/WORKSPACE
index 02b57bf..133cfc5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,5 +3,5 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "googletest",
remote = "https://github.com/google/googletest",
- branch = "master",
+ branch = "main",
)
diff --git a/examples/plugins/Android.bp b/examples/plugins/Android.bp
new file mode 100644
index 0000000..ea275f1
--- /dev/null
+++ b/examples/plugins/Android.bp
@@ -0,0 +1,24 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_tinyalsa_new_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-BSD
+ default_applicable_licenses: ["external_tinyalsa_new_license"],
+}
+
+cc_library {
+ name: "libtinyalsav2_example_plugin_pcm",
+ vendor: true,
+ srcs: ["sample_pcm_plugin.c"],
+ cflags: ["-Werror", "-Wno-unused-parameter"],
+ header_libs: ["libtinyalsav2_headers"],
+}
+
+cc_library {
+ name: "libtinyalsav2_example_plugin_mixer",
+ vendor: true,
+ srcs: ["sample_mixer_plugin.c"],
+ cflags: ["-Werror", "-Wno-unused-parameter"],
+ header_libs: ["libtinyalsav2_headers"],
+}
diff --git a/examples/plugins/sample_mixer_plugin.c b/examples/plugins/sample_mixer_plugin.c
new file mode 100644
index 0000000..8ecf56d
--- /dev/null
+++ b/examples/plugins/sample_mixer_plugin.c
@@ -0,0 +1,320 @@
+/* sample_mixer_plugin.c
+**
+** Copyright (c) 2021, The Linux Foundation. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above
+** copyright notice, this list of conditions and the following
+** disclaimer in the documentation and/or other materials provided
+** with the distribution.
+** * Neither the name of The Linux Foundation nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sound/asound.h>
+#include <tinyalsa/plugin.h>
+#include <tinyalsa/asoundlib.h>
+
+#define SAMPLE_MIXER_PRIV_GET_CTL_PTR(p, idx) (p->ctls + idx)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static const char *const sample_enum_text[] = {"One", "Two", "Three"};
+
+struct sample_mixer_priv {
+ struct snd_control *ctls;
+ int ctl_count;
+
+ struct snd_value_enum sample_enum;
+
+ mixer_event_callback event_cb;
+};
+
+static int sample_mixer_int_ctl_get(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+ return 0;
+}
+
+static int sample_mixer_int_ctl_put(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+/*
+ * Integer values can be retrieved using:
+ * uint32_t val1 = (uint32_t)ev->value.integer.value[0];
+ * uint32_t val2 = (uint32_t)ev->value.integer.value[1];
+ * uint32_t val3 = (uint32_t)ev->value.integer.value[2];
+ */
+ return 0;
+}
+
+static int sample_mixer_byte_array_ctl_get(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+ return 0;
+}
+
+static int sample_mixer_byte_array_ctl_put(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+/*
+ * Byte array payload can be retrieved using:
+ * void *payload = ev->value.bytes.data;
+ */
+
+ return 0;
+}
+
+static int sample_mixer_tlv_ctl_get(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_tlv *ev)
+{
+ return 0;
+}
+
+static int sample_mixer_tlv_ctl_put(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_tlv *tlv)
+{
+/*
+ * TLV payload and len can be retrieved using:
+ * void *payload = &tlv->tlv[0];
+ * size_t tlv_size = tlv->length;
+ */
+
+ return 0;
+}
+
+static int sample_mixer_enum_ctl_get(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+ return 0;
+}
+
+static int sample_mixer_enum_ctl_put(struct mixer_plugin *plugin,
+ struct snd_control *ctl, struct snd_ctl_elem_value *ev)
+{
+/*
+ * Enum value can be retrieved using:
+ * unsigned int val = ev->value.enumerated.item[0];
+ */
+ return 0;
+}
+
+static struct snd_value_int sample_mixer_ctl_value_int =
+ SND_VALUE_INTEGER(3, 0, 1000, 100);
+
+/* 512 max bytes for non-tlv byte controls */
+static struct snd_value_bytes byte_array_ctl_bytes =
+ SND_VALUE_BYTES(512);
+
+static struct snd_value_tlv_bytes sample_mixer_tlv_ctl_bytes =
+ SND_VALUE_TLV_BYTES(1024, sample_mixer_tlv_ctl_get, sample_mixer_tlv_ctl_put);
+
+static void create_integer_ctl(struct sample_mixer_priv *priv,
+ int ctl_idx, int pval, void *pdata)
+{
+ struct snd_control *ctl = SAMPLE_MIXER_PRIV_GET_CTL_PTR(priv, ctl_idx);
+ char *ctl_name = strdup("Sample integer control");
+
+ /* pval and pdata can be retrieved using snd_control during get()/put() */
+ INIT_SND_CONTROL_INTEGER(ctl, ctl_name, sample_mixer_int_ctl_get,
+ sample_mixer_int_ctl_put, sample_mixer_ctl_value_int, pval, pdata);
+}
+
+static void create_byte_array_ctl(struct sample_mixer_priv *priv,
+ int ctl_idx, int pval, void *pdata)
+{
+ struct snd_control *ctl = SAMPLE_MIXER_PRIV_GET_CTL_PTR(priv, ctl_idx);
+ char *ctl_name = strdup("Sample byte array control");
+
+ INIT_SND_CONTROL_BYTES(ctl, ctl_name, sample_mixer_byte_array_ctl_get,
+ sample_mixer_byte_array_ctl_put, byte_array_ctl_bytes,
+ pval, pdata);
+}
+
+static void create_tlv_ctl(struct sample_mixer_priv *priv,
+ int ctl_idx, int pval, void *pdata)
+{
+ struct snd_control *ctl = SAMPLE_MIXER_PRIV_GET_CTL_PTR(priv, ctl_idx);
+ char *ctl_name = strdup("Sample tlv control");
+
+ INIT_SND_CONTROL_TLV_BYTES(ctl, ctl_name, sample_mixer_tlv_ctl_bytes,
+ pval, pdata);
+}
+
+static void create_enum_ctl(struct sample_mixer_priv *priv,
+ int ctl_idx, struct snd_value_enum *e,
+ int pval, void *pdata)
+{
+ struct snd_control *ctl = SAMPLE_MIXER_PRIV_GET_CTL_PTR(priv, ctl_idx);
+ char *ctl_name = strdup("Sample enum control");
+
+ INIT_SND_CONTROL_ENUM(ctl, ctl_name, sample_mixer_enum_ctl_get,
+ sample_mixer_enum_ctl_put, e, pval, pdata);
+}
+
+static int sample_mixer_form_ctls(struct sample_mixer_priv *priv, int ctl_idx)
+{
+ create_integer_ctl(priv, ctl_idx, 0, NULL);
+ ctl_idx++;
+ create_byte_array_ctl(priv, ctl_idx, 0, NULL);
+ ctl_idx++;
+ create_tlv_ctl(priv, ctl_idx, 0, NULL);
+ ctl_idx++;
+ create_enum_ctl(priv, ctl_idx, &priv->sample_enum, 0, NULL);
+ ctl_idx++;
+
+ return 0;
+}
+
+static ssize_t sample_mixer_read_event(struct mixer_plugin *plugin,
+ struct snd_ctl_event *ev, size_t size)
+{
+ /* Fill snd_ctl_event *ev before sending.
+ * Return : sizeof(struct snd_ctl_event),
+ * 0 in case no event present.
+ */
+
+ return 0;
+}
+
+static int sample_mixer_subscribe_events(struct mixer_plugin *plugin,
+ mixer_event_callback event_cb)
+{
+ struct sample_mixer_priv *priv = plugin->priv;
+
+ priv->event_cb = event_cb;
+ /* event_cb is the callback function which needs to be called
+ * when an event occurs. This will unblock poll() on mixer fd
+ * which is called from mixer_wait_event().
+ * Once poll is unblocked, clients can call mixer_read_event()
+ * During unsubscribe(), event_cb is NULL.
+ */
+ return 0;
+}
+
+static int sample_mixer_alloc_ctls(struct sample_mixer_priv *priv)
+{
+ int ret = 0, i;
+
+ priv->ctls = calloc(priv->ctl_count, sizeof(*priv->ctls));
+ if (!priv->ctls) {
+ return -ENOMEM;
+ }
+
+ priv->sample_enum.items = ARRAY_SIZE(sample_enum_text);
+ priv->sample_enum.texts = calloc(priv->sample_enum.items, sizeof(*priv->sample_enum.texts));
+
+ for (i = 0; i < ARRAY_SIZE(sample_enum_text); i++)
+ priv->sample_enum.texts[i] = strdup(sample_enum_text[i]);
+
+ return sample_mixer_form_ctls(priv, 0);
+}
+
+static void sample_mixer_free_ctls(struct sample_mixer_priv *priv)
+{
+ int num_enums, i;
+ struct snd_control *ctl = NULL;
+
+ for (i = 0; i < priv->ctl_count; i++) {
+ ctl = SAMPLE_MIXER_PRIV_GET_CTL_PTR(priv, i);
+ if (ctl->name)
+ free((void *)ctl->name);
+ }
+
+ num_enums = priv->sample_enum.items;
+
+ for (i = 0; i < num_enums; i++)
+ free(priv->sample_enum.texts[i]);
+
+ free(priv->sample_enum.texts);
+ priv->ctl_count = 0;
+
+ if (priv->ctls) {
+ free(priv->ctls);
+ priv->ctls = NULL;
+ }
+}
+
+static void sample_mixer_close(struct mixer_plugin **plugin)
+{
+ struct mixer_plugin *mp = *plugin;
+ struct sample_mixer_priv *priv = mp->priv;
+
+ /* unblock mixer event during close */
+ if (priv->event_cb)
+ priv->event_cb(mp);
+ sample_mixer_subscribe_events(mp, NULL);
+ sample_mixer_free_ctls(priv);
+ free(priv);
+ free(*plugin);
+ *plugin = NULL;
+}
+
+int sample_mixer_open(struct mixer_plugin **plugin, unsigned int card)
+{
+ struct mixer_plugin *mp;
+ struct sample_mixer_priv *priv;
+ int i, ret = 0;
+ int ctl_cnt = 4;
+
+ mp = calloc(1, sizeof(*mp));
+ if (!mp) {
+ return -ENOMEM;
+ }
+
+ priv = calloc(1, sizeof(*priv));
+ if (!priv) {
+ ret = -ENOMEM;
+ goto err_priv_alloc;
+ }
+
+ priv->ctl_count = ctl_cnt;
+ ret = sample_mixer_alloc_ctls(priv);
+ if (ret)
+ goto err_ctls_alloc;
+
+ /* Register the controls */
+ mp->controls = priv->ctls;
+ mp->num_controls = priv->ctl_count;
+ mp->priv = priv;
+ *plugin = mp;
+
+ return 0;
+
+err_ctls_alloc:
+ sample_mixer_free_ctls(priv);
+ free(priv);
+
+err_priv_alloc:
+ free(mp);
+ return ret;
+}
+
+struct mixer_plugin_ops mixer_plugin_ops = {
+ .open = sample_mixer_open,
+ .close = sample_mixer_close,
+ .subscribe_events = sample_mixer_subscribe_events,
+ .read_event = sample_mixer_read_event,
+};
diff --git a/examples/plugins/sample_pcm_plugin.c b/examples/plugins/sample_pcm_plugin.c
new file mode 100644
index 0000000..40bf684
--- /dev/null
+++ b/examples/plugins/sample_pcm_plugin.c
@@ -0,0 +1,332 @@
+/* sample_mixer_plugin.c
+**
+** Copyright (c) 2021, The Linux Foundation. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above
+** copyright notice, this list of conditions and the following
+** disclaimer in the documentation and/or other materials provided
+** with the distribution.
+** * Neither the name of The Linux Foundation nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**/
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sound/asound.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <tinyalsa/plugin.h>
+#include <tinyalsa/asoundlib.h>
+
+/* 2 words of uint32_t = 64 bits of mask */
+#define PCM_MASK_SIZE (2)
+#define PCM_FORMAT_BIT(x) (1ULL << x)
+
+struct sample_pcm_priv {
+ FILE *fptr;
+ int session_id;
+ int channels;
+ int bitwidth;
+ int sample_rate;
+ unsigned int period_size;
+ snd_pcm_uframes_t total_size_frames;
+};
+
+struct pcm_plugin_hw_constraints sample_pcm_constrs = {
+ .access = 0,
+ .format = 0,
+ .bit_width = {
+ .min = 16,
+ .max = 32,
+ },
+ .channels = {
+ .min = 1,
+ .max = 8,
+ },
+ .rate = {
+ .min = 8000,
+ .max = 384000,
+ },
+ .periods = {
+ .min = 1,
+ .max = 8,
+ },
+ .period_bytes = {
+ .min = 96,
+ .max = 122880,
+ },
+};
+
+static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+static inline int param_is_interval(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
+}
+
+static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ if (i->integer)
+ return i->max;
+ }
+ return 0;
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline int snd_mask_val(const struct snd_mask *mask)
+{
+ int i;
+ for (i = 0; i < PCM_MASK_SIZE; i++) {
+ if (mask->bits[i])
+ return ffs(mask->bits[i]) + (i << 5) - 1;
+ }
+ return 0;
+}
+
+static int alsaformat_to_bitwidth(int format)
+{
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ return 32;
+ case SNDRV_PCM_FORMAT_S8:
+ return 8;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ return 24;
+ default:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ return 16;
+ };
+}
+
+static int param_get_mask_val(struct snd_pcm_hw_params *p,
+ int n)
+{
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ int val = snd_mask_val(m);
+
+ return alsaformat_to_bitwidth(val);
+ }
+ return 0;
+}
+
+static int sample_session_open(int sess_id, unsigned int mode, struct sample_pcm_priv *priv)
+{
+ char fname[128];
+
+ snprintf(fname, 128, "sample_pcm_data_%d.raw", sess_id);
+ priv->fptr = fopen(fname,"rwb+");
+ if (priv->fptr == NULL) {
+ return -EIO;
+ }
+ rewind(priv->fptr);
+ return 0;
+}
+
+
+static int sample_session_write(struct sample_pcm_priv *priv, void *buff, size_t count)
+{
+ uint8_t *data = (uint8_t *)buff;
+ size_t len;
+
+ len = fwrite(buff, 1, count, priv->fptr);
+
+ if (len != count)
+ return -EIO;
+
+ return 0;
+}
+
+static int sample_pcm_hw_params(struct pcm_plugin *plugin,
+ struct snd_pcm_hw_params *params)
+{
+ struct sample_pcm_priv *priv = plugin->priv;
+
+ priv->sample_rate = param_get_int(params, SNDRV_PCM_HW_PARAM_RATE);
+ priv->channels = param_get_int(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ priv->bitwidth = param_get_mask_val(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ return 0;
+}
+
+static int sample_pcm_sw_params(struct pcm_plugin *plugin,
+ struct snd_pcm_sw_params *sparams)
+{
+ return 0;
+}
+
+static int sample_pcm_sync_ptr(struct pcm_plugin *plugin,
+ struct snd_pcm_sync_ptr *sync_ptr)
+{
+ return 0;
+}
+
+static int sample_pcm_writei_frames(struct pcm_plugin *plugin, struct snd_xferi *x)
+{
+ struct sample_pcm_priv *priv = plugin->priv;
+ void *buff;
+ size_t count;
+
+ buff = x->buf;
+ count = x->frames * (priv->channels * (priv->bitwidth) / 8);
+
+ return sample_session_write(priv, buff, count);
+}
+
+static int sample_pcm_readi_frames(struct pcm_plugin *plugin, struct snd_xferi *x)
+{
+ return 0;
+}
+
+static int sample_pcm_ttstamp(struct pcm_plugin *plugin, int *tstamp)
+{
+ return 0;
+}
+
+static int sample_pcm_prepare(struct pcm_plugin *plugin)
+{
+ return 0;
+}
+
+static int sample_pcm_start(struct pcm_plugin *plugin)
+{
+ return 0;
+}
+
+static int sample_pcm_drop(struct pcm_plugin *plugin)
+{
+ return 0;
+}
+
+static int sample_pcm_close(struct pcm_plugin *plugin)
+{
+ struct sample_pcm_priv *priv = plugin->priv;
+ int ret = 0;
+
+ fclose(priv->fptr);
+ free(plugin->priv);
+ free(plugin);
+
+ return ret;
+}
+
+static int sample_pcm_poll(struct pcm_plugin *plugin, struct pollfd *pfd,
+ nfds_t nfds, int timeout)
+{
+ return 0;
+}
+
+static void* sample_pcm_mmap(struct pcm_plugin *plugin, void *addr, size_t length, int prot,
+ int flags, off_t offset)
+{
+ return MAP_FAILED;
+}
+
+static int sample_pcm_munmap(struct pcm_plugin *plugin, void *addr, size_t length)
+{
+ return 0;
+}
+
+int sample_pcm_open(struct pcm_plugin **plugin, unsigned int card,
+ unsigned int device, unsigned int mode)
+{
+ struct pcm_plugin *sample_pcm_plugin;
+ struct sample_pcm_priv *priv;
+ int ret = 0, session_id = device;
+
+ sample_pcm_plugin = calloc(1, sizeof(struct pcm_plugin));
+ if (!sample_pcm_plugin)
+ return -ENOMEM;
+
+ priv = calloc(1, sizeof(struct sample_pcm_priv));
+ if (!priv) {
+ ret = -ENOMEM;
+ goto err_plugin_free;
+ }
+
+ sample_pcm_constrs.access = (PCM_FORMAT_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
+ PCM_FORMAT_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED));
+ sample_pcm_constrs.format = (PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S16_LE) |
+ PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S24_LE) |
+ PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S24_3LE) |
+ PCM_FORMAT_BIT(SNDRV_PCM_FORMAT_S32_LE));
+
+ sample_pcm_plugin->card = card;
+ sample_pcm_plugin->mode = mode;
+ sample_pcm_plugin->constraints = &sample_pcm_constrs;
+ sample_pcm_plugin->priv = priv;
+
+ priv->session_id = session_id;
+
+ ret = sample_session_open(session_id, mode, priv);
+ if (ret) {
+ errno = -ret;
+ goto err_priv_free;
+ }
+ *plugin = sample_pcm_plugin;
+ return 0;
+
+err_priv_free:
+ free(priv);
+err_plugin_free:
+ free(sample_pcm_plugin);
+ return ret;
+}
+
+struct pcm_plugin_ops pcm_plugin_ops = {
+ .open = sample_pcm_open,
+ .close = sample_pcm_close,
+ .hw_params = sample_pcm_hw_params,
+ .sw_params = sample_pcm_sw_params,
+ .sync_ptr = sample_pcm_sync_ptr,
+ .writei_frames = sample_pcm_writei_frames,
+ .readi_frames = sample_pcm_readi_frames,
+ .ttstamp = sample_pcm_ttstamp,
+ .prepare = sample_pcm_prepare,
+ .start = sample_pcm_start,
+ .drop = sample_pcm_drop,
+ .mmap = sample_pcm_mmap,
+ .munmap = sample_pcm_munmap,
+ .poll = sample_pcm_poll,
+};
diff --git a/examples/sndcardparser/Android.bp b/examples/sndcardparser/Android.bp
new file mode 100644
index 0000000..72bb8ab
--- /dev/null
+++ b/examples/sndcardparser/Android.bp
@@ -0,0 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_tinyalsa_new_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-BSD
+ default_applicable_licenses: ["external_tinyalsa_new_license"],
+}
+
+cc_library {
+ name: "libsndcardparser_example",
+ vendor: true,
+ srcs: ["sample_sndcardparser.c"],
+ cflags: ["-Werror"],
+}
diff --git a/examples/sndcardparser/sample_sndcardparser.c b/examples/sndcardparser/sample_sndcardparser.c
new file mode 100644
index 0000000..b7d7381
--- /dev/null
+++ b/examples/sndcardparser/sample_sndcardparser.c
@@ -0,0 +1,270 @@
+/* sample_sndcardparser.c
+**
+** Copyright (c) 2021, The Linux Foundation. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above
+** copyright notice, this list of conditions and the following
+** disclaimer in the documentation and/or other materials provided
+** with the distribution.
+** * Neither the name of The Linux Foundation nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define VIRTUAL_SND_CARD_ID 100
+#define MAX_PATH 256
+#define BUF_SIZE 1024
+
+enum snd_node_type {
+ NODE_TYPE_HW = 0,
+ NODE_TYPE_PLUGIN,
+ NODE_TYPE_INVALID,
+};
+
+enum {
+ NODE_PCM,
+ NODE_COMPR,
+ NODE_MIXER,
+ NODE_MAX,
+};
+
+struct snd_node_ops {
+ /** Function pointer to get card definition */
+ void* (*open_card)(unsigned int card);
+ /** Function pointer to release card definition */
+ void (*close_card)(void *card);
+ /** Get interger type properties from device definition */
+ int (*get_int)(void *node, const char *prop, int *val);
+ /** Get string type properties from device definition */
+ int (*get_str)(void *node, const char *prop, char **val);
+ /** Function pointer to get mixer definition */
+ void* (*get_mixer)(void *card);
+ /** Function pointer to get PCM definition */
+ void* (*get_pcm)(void *card, unsigned int id);
+ /** Function pointer to get COMPRESS definition */
+ void* (*get_compress)(void *card, unsigned int id);
+};
+
+struct snd_dev_def {
+ unsigned int device;
+ int type;
+ const char *name;
+ const char *so_name;
+ int playback; //used only for pcm node
+ int capture; //used only for pcm node
+ /* add custom props here */
+};
+
+struct snd_dev_def_card {
+ unsigned int card;
+ char *name;
+
+ /* child device details */
+ int num_pcm_nodes;
+ struct snd_dev_def *pcm_dev_def;
+
+ struct snd_dev_def *mixer_dev_def;
+};
+
+struct snd_dev_def pcm_devs[] = {
+ {100, NODE_TYPE_PLUGIN, "PCM100", "libtinyalsav2_example_plugin_pcm.so", 1, 0},
+ /* Add other plugin info here */
+};
+
+struct snd_dev_def mixer_dev =
+ {VIRTUAL_SND_CARD_ID, NODE_TYPE_PLUGIN, "virtual-snd-card", "libtinyalsav2_example_plugin_mixer.so", 0, 0};
+
+void *snd_card_def_open_card(unsigned int card)
+{
+ struct snd_dev_def_card *card_def = NULL;
+ struct snd_dev_def *pcm_dev_def = NULL;
+ struct snd_dev_def *mixer_dev_def = NULL;
+ int num_pcm = ARRAY_SIZE(pcm_devs);
+ int i;
+
+ if (card != VIRTUAL_SND_CARD_ID)
+ return NULL;
+
+ card_def = calloc(1, sizeof(struct snd_dev_def_card));
+ if (!card_def)
+ return card_def;
+
+ card_def->card = card;
+ card_def->name = strdup("virtual-snd-card");
+
+ /* fill pcm device node info */
+ card_def->num_pcm_nodes = num_pcm;
+ pcm_dev_def = calloc(num_pcm, sizeof(struct snd_dev_def));
+ if (!pcm_dev_def)
+ goto free_card_def;
+
+ for (i = 0; i < num_pcm; i++)
+ memcpy(&pcm_dev_def[i], &pcm_devs[i], sizeof(struct snd_dev_def));
+
+ card_def->pcm_dev_def = pcm_dev_def;
+
+ /* fill mixer device node info */
+ mixer_dev_def = calloc(1, sizeof(struct snd_dev_def));
+ if (!mixer_dev_def)
+ goto free_pcm_dev;
+
+ memcpy(mixer_dev_def, &mixer_dev, sizeof(struct snd_dev_def));
+
+ card_def->mixer_dev_def = mixer_dev_def;
+ return card_def;
+free_pcm_dev:
+ free(pcm_dev_def);
+free_card_def:
+ free(card_def->name);
+ free(card_def);
+ return NULL;
+}
+
+void snd_card_def_close_card(void *card_node)
+{
+ struct snd_dev_def_card *defs = (struct snd_dev_def_card *)card_node;
+ struct snd_dev_def *pcm_dev_def = NULL;
+ struct snd_dev_def *mixer_dev_def = NULL;
+
+ if (!defs)
+ return;
+
+ pcm_dev_def = defs->pcm_dev_def;
+ if (pcm_dev_def)
+ free(pcm_dev_def);
+
+ mixer_dev_def = defs->mixer_dev_def;
+ if (!mixer_dev_def)
+ goto free_defs;
+
+ free(mixer_dev_def);
+free_defs:
+ free(defs->name);
+ free(defs);
+}
+
+void *snd_card_def_get_node(void *card_node, unsigned int id, int type)
+{
+ struct snd_dev_def_card *card_def = (struct snd_dev_def_card *)card_node;
+ struct snd_dev_def *dev_def = NULL;
+ int i;
+
+ if (!card_def)
+ return NULL;
+
+ if (type >= NODE_MAX)
+ return NULL;
+
+ if (type == NODE_MIXER)
+ return card_def->mixer_dev_def;
+
+ if (type == NODE_PCM)
+ dev_def = card_def->pcm_dev_def;
+
+ for (i = 0; i < card_def->num_pcm_nodes; i++) {
+ if (dev_def[i].device == id) {
+ return &dev_def[i];
+ }
+ }
+
+ return NULL;
+}
+
+int snd_card_def_get_int(void *node, const char *prop, int *val)
+{
+ struct snd_dev_def *dev_def = (struct snd_dev_def *)node;
+ int ret = -EINVAL;
+
+ if (!dev_def || !prop || !val)
+ return ret;
+
+ if (!strcmp(prop, "type")) {
+ *val = dev_def->type;
+ return 0;
+ } else if (!strcmp(prop, "id")) {
+ *val = dev_def->device;
+ return 0;
+ } else if (!strcmp(prop, "playback")) {
+ *val = dev_def->playback;
+ return 0;
+ } else if (!strcmp(prop, "capture")) {
+ *val = dev_def->capture;
+ return 0;
+ }
+
+ return ret;
+}
+
+int snd_card_def_get_str(void *node, const char *prop, char **val)
+{
+ struct snd_dev_def *dev_def = (struct snd_dev_def *)node;
+ int ret = -EINVAL;
+
+ if (!dev_def || !prop)
+ return ret;
+
+ if (!strcmp(prop, "so-name")) {
+ if (dev_def->so_name) {
+ *val = (char *)dev_def->so_name;
+ return 0;
+ }
+ }
+
+ if (!strcmp(prop, "name")) {
+ if (dev_def->name) {
+ *val = (char *)dev_def->name;
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+void *snd_card_def_get_pcm(void *card_node, unsigned int id)
+{
+ return snd_card_def_get_node(card_node, id, NODE_PCM);
+}
+
+void *snd_card_def_get_compress(void *card_node, unsigned int id)
+{
+ return snd_card_def_get_node(card_node, id, NODE_COMPR);
+}
+
+void *snd_card_def_get_mixer(void *card_node)
+{
+ return snd_card_def_get_node(card_node, 1, NODE_MIXER);
+}
+
+struct snd_node_ops snd_card_ops = {
+ .open_card = snd_card_def_open_card,
+ .close_card = snd_card_def_close_card,
+ .get_int = snd_card_def_get_int,
+ .get_str = snd_card_def_get_str,
+ .get_pcm = snd_card_def_get_pcm,
+ .get_compress = snd_card_def_get_compress,
+ .get_mixer = snd_card_def_get_mixer,
+};
diff --git a/include/tinyalsa/meson.build b/include/tinyalsa/meson.build
index d14b35b..95077be 100644
--- a/include/tinyalsa/meson.build
+++ b/include/tinyalsa/meson.build
@@ -1,9 +1,11 @@
tinyalsa_headers = [
'asoundlib.h',
+ 'attributes.h',
'interval.h',
'limits.h',
'mixer.h',
'pcm.h',
+ 'plugin.h',
'version.h'
]
diff --git a/include/tinyalsa/pcm.h b/include/tinyalsa/pcm.h
index 5c11e2a..9fca92d 100644
--- a/include/tinyalsa/pcm.h
+++ b/include/tinyalsa/pcm.h
@@ -217,16 +217,16 @@ struct pcm_config {
* silence_size : 0
*/
/** The minimum number of frames required to start the PCM */
- unsigned int start_threshold;
+ unsigned long start_threshold;
/** The minimum number of frames required to stop the PCM */
- unsigned int stop_threshold;
+ unsigned long stop_threshold;
/** The minimum number of frames to silence the PCM */
- unsigned int silence_threshold;
+ unsigned long silence_threshold;
/** The number of frames to overwrite the playback buffer when the playback underrun is greater
* than the silence threshold */
- unsigned int silence_size;
+ unsigned long silence_size;
- unsigned int avail_min;
+ unsigned long avail_min;
};
/** Enumeration of a PCM's hardware parameters.
diff --git a/src/mixer.c b/src/mixer.c
index 5581e5d..afbc015 100644
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -732,9 +732,13 @@ struct mixer_ctl *mixer_get_ctl_by_name_and_index(struct mixer *mixer,
ctl = grp->ctl;
for (n = 0; n < grp->count; n++)
- if (!strcmp(name, (char*) ctl[n].info.id.name))
- if (index-- == 0)
+ if (!strcmp(name, (char*) ctl[n].info.id.name)) {
+ if (index == 0) {
return ctl + n;
+ } else {
+ index--;
+ }
+ }
}
#ifdef TINYALSA_USES_PLUGINS
@@ -743,9 +747,13 @@ struct mixer_ctl *mixer_get_ctl_by_name_and_index(struct mixer *mixer,
ctl = grp->ctl;
for (n = 0; n < grp->count; n++)
- if (!strcmp(name, (char*) ctl[n].info.id.name))
- if (index-- == 0)
+ if (!strcmp(name, (char*) ctl[n].info.id.name)) {
+ if (index == 0) {
return ctl + n;
+ } else {
+ index--;
+ }
+ }
}
#endif
return NULL;
@@ -1039,6 +1047,9 @@ int mixer_ctl_get_array(const struct mixer_ctl *ctl, void *array, size_t count)
}
case SNDRV_CTL_ELEM_TYPE_IEC958:
+ ret = grp->ops->ioctl(grp->data, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
+ if (ret < 0)
+ return ret;
size = sizeof(ev.value.iec958);
source = &ev.value.iec958;
break;
diff --git a/src/mixer_plugin.c b/src/mixer_plugin.c
index 34117a9..a07b8f6 100644
--- a/src/mixer_plugin.c
+++ b/src/mixer_plugin.c
@@ -82,7 +82,8 @@ static int mixer_plug_get_elem_id(struct mixer_plug_data *plug_data,
id->iface = ctl->iface;
strncpy((char *)id->name, (char *)ctl->name,
- sizeof(id->name));
+ sizeof(id->name) - 1);
+ ((char *)id->name)[sizeof(id->name) - 1] = '\0';
return 0;
}
@@ -100,7 +101,8 @@ static int mixer_plug_info_enum(struct snd_control *ctl,
strncpy(einfo->value.enumerated.name,
val->texts[einfo->value.enumerated.item],
- sizeof(einfo->value.enumerated.name));
+ sizeof(einfo->value.enumerated.name) - 1);
+ einfo->value.enumerated.name[sizeof(einfo->value.enumerated.name) - 1] = '\0';
return 0;
}
diff --git a/src/pcm_hw.c b/src/pcm_hw.c
index e5588a0..5eb53be 100644
--- a/src/pcm_hw.c
+++ b/src/pcm_hw.c
@@ -1,5 +1,7 @@
/* pcm_hw.c
+**
** Copyright (c) 2019, The Linux Foundation.
+** Copyright 2021, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/src/pcm_plugin.c b/src/pcm_plugin.c
index 15bfc80..47bf4a5 100644
--- a/src/pcm_plugin.c
+++ b/src/pcm_plugin.c
@@ -153,9 +153,12 @@ static int pcm_plug_info(struct pcm_plug_data *plug_data,
return ret;
}
- strncpy((char *)info->id, name, sizeof(info->id));
- strncpy((char *)info->name, name, sizeof(info->name));
- strncpy((char *)info->subname, name, sizeof(info->subname));
+ strncpy((char *)info->id, name, sizeof(info->id) - 1);
+ ((char *)info->id)[sizeof(info->id) - 1] = '\0';
+ strncpy((char *)info->name, name, sizeof(info->name) - 1);
+ ((char *)info->name)[sizeof(info->name) - 1] = '\0';
+ strncpy((char *)info->subname, name, sizeof(info->subname) - 1);
+ ((char *)info->subname)[sizeof(info->subname) - 1] = '\0';
info->subdevices_count = 1;
diff --git a/utils/tinyplay.c b/utils/tinyplay.c
index 96d0f60..9f72bbb 100644
--- a/utils/tinyplay.c
+++ b/utils/tinyplay.c
@@ -104,6 +104,7 @@ struct ctx {
struct chunk_fmt chunk_fmt;
FILE *file;
+ size_t file_size;
};
static bool is_wave_file(const char *filetype)
@@ -127,6 +128,48 @@ static bool signed_pcm_bits_to_format(int bits)
}
}
+static int parse_wave_file(struct ctx *ctx, const char *filename)
+{
+ if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
+ fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", filename);
+ return -1;
+ }
+
+ if (ctx->wave_header.riff_id != ID_RIFF || ctx->wave_header.wave_id != ID_WAVE) {
+ fprintf(stderr, "error: '%s' is not a riff/wave file\n", filename);
+ return -1;
+ }
+
+ bool more_chunks = true;
+ do {
+ if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1) {
+ fprintf(stderr, "error: '%s' does not contain a data chunk\n", filename);
+ return -1;
+ }
+ switch (ctx->chunk_header.id) {
+ case ID_FMT:
+ if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1) {
+ fprintf(stderr, "error: '%s' has incomplete format chunk\n", filename);
+ return -1;
+ }
+ /* If the format header is larger, skip the rest */
+ if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt)) {
+ fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
+ }
+ break;
+ case ID_DATA:
+ /* Stop looking for chunks */
+ more_chunks = false;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
+ }
+ } while (more_chunks);
+
+ return 0;
+}
+
static int ctx_init(struct ctx* ctx, struct cmd *cmd)
{
unsigned int bits = cmd->bits;
@@ -141,6 +184,9 @@ static int ctx_init(struct ctx* ctx, struct cmd *cmd)
ctx->file = stdin;
} else {
ctx->file = fopen(cmd->filename, "rb");
+ fseek(ctx->file, 0L, SEEK_END);
+ ctx->file_size = ftell(ctx->file);
+ fseek(ctx->file, 0L, SEEK_SET);
}
if (ctx->file == NULL) {
@@ -149,48 +195,15 @@ static int ctx_init(struct ctx* ctx, struct cmd *cmd)
}
if (is_wave_file(cmd->filetype)) {
- if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
- fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", cmd->filename);
- fclose(ctx->file);
- return -1;
- }
- if ((ctx->wave_header.riff_id != ID_RIFF) ||
- (ctx->wave_header.wave_id != ID_WAVE)) {
- fprintf(stderr, "error: '%s' is not a riff/wave file\n", cmd->filename);
+ if (parse_wave_file(ctx, cmd->filename) != 0) {
fclose(ctx->file);
return -1;
}
- unsigned int more_chunks = 1;
- do {
- if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1){
- fprintf(stderr, "error: '%s' does not contain a data chunk\n", cmd->filename);
- fclose(ctx->file);
- return -1;
- }
- switch (ctx->chunk_header.id) {
- case ID_FMT:
- if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1){
- fprintf(stderr, "error: '%s' has incomplete format chunk\n", cmd->filename);
- fclose(ctx->file);
- return -1;
- }
- /* If the format header is larger, skip the rest */
- if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt))
- fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
- break;
- case ID_DATA:
- /* Stop looking for chunks */
- more_chunks = 0;
- break;
- default:
- /* Unknown chunk, skip bytes */
- fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
- }
- } while (more_chunks);
config->channels = ctx->chunk_fmt.num_channels;
config->rate = ctx->chunk_fmt.sample_rate;
bits = ctx->chunk_fmt.bits_per_sample;
is_float = ctx->chunk_fmt.audio_format == WAVE_FORMAT_IEEE_FLOAT;
+ ctx->file_size = (size_t) ctx->chunk_header.sz;
}
if (is_float) {
@@ -386,20 +399,20 @@ int check_param(struct pcm_params *params, unsigned int param, unsigned int valu
{
unsigned int min;
unsigned int max;
- int is_within_bounds = 1;
+ bool is_within_bounds = true;
min = pcm_params_get_min(params, param);
if (value < min) {
fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
param_unit, min, param_unit);
- is_within_bounds = 0;
+ is_within_bounds = false;
}
max = pcm_params_get_max(params, param);
if (value > max) {
fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
param_unit, max, param_unit);
- is_within_bounds = 0;
+ is_within_bounds = false;
}
return is_within_bounds;
@@ -417,12 +430,13 @@ int sample_is_playable(const struct cmd *cmd)
}
can_play = check_param(params, PCM_PARAM_RATE, cmd->config.rate, "sample rate", "hz");
- can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample", " channels");
+ can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample",
+ " channels");
can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, cmd->bits, "bits", " bits");
can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, cmd->config.period_size, "period size",
- " frames");
+ " frames");
can_play &= check_param(params, PCM_PARAM_PERIODS, cmd->config.period_count, "period count",
- " frames");
+ "");
pcm_params_free(params);
@@ -432,9 +446,10 @@ int sample_is_playable(const struct cmd *cmd)
int play_sample(struct ctx *ctx)
{
char *buffer;
+ bool is_stdin_source = ctx->file == stdin;
size_t buffer_size = 0;
size_t num_read = 0;
- size_t remaining_data_size = ctx->chunk_header.sz;
+ size_t remaining_data_size = is_stdin_source ? SIZE_MAX : ctx->file_size;
size_t played_data_size = 0;
size_t read_size = 0;
const struct pcm_config *config = pcm_get_config(ctx->pcm);
@@ -464,12 +479,21 @@ int play_sample(struct ctx *ctx)
fprintf(stderr, "error playing sample. %s\n", pcm_get_error(ctx->pcm));
break;
}
- remaining_data_size -= num_read;
+
+ if (!is_stdin_source) {
+ remaining_data_size -= num_read;
+ }
played_data_size += pcm_frames_to_bytes(ctx->pcm, written_frames);
}
} while (!close && num_read > 0 && remaining_data_size > 0);
- printf("Played %zu bytes. Remains %zu bytes.\n", played_data_size, remaining_data_size);
+ printf("Played %zu bytes. ", played_data_size);
+ if (is_stdin_source) {
+ printf("\n");
+ } else {
+ printf("Remains %zu bytes.\n", remaining_data_size);
+ }
+
pcm_wait(ctx->pcm, -1);
free(buffer);