aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Li <dvdli@google.com>2023-09-18 18:58:18 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-09-18 18:58:18 +0000
commit9c4d4dbf6a92f90070f298e550db35a74773e520 (patch)
treece094436772521d150e24b67d56d5cb9d01a27b2
parent92ae2cff418243681df7cf36555a57c71641d54e (diff)
parentadb8f11a109e8199eb4b5a7ee264d941ed9b05b4 (diff)
downloadtinyalsa_new-9c4d4dbf6a92f90070f298e550db35a74773e520.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into audio am: 152d9ce1fd am: 88bf0f3e6e am: adb8f11a10
Original change: https://android-review.googlesource.com/c/platform/external/tinyalsa_new/+/2752232 Change-Id: I15613819794e36086e0e75f7a953ce2d3ae8c57c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--include/tinyalsa/mixer.h6
-rw-r--r--include/tinyalsa/pcm.h2
-rw-r--r--include/tinyalsa/plugin.h5
-rw-r--r--src/mixer.c57
-rw-r--r--src/pcm.c20
-rw-r--r--src/pcm_plugin.c13
-rw-r--r--utils/tinycap.15
-rw-r--r--utils/tinycap.c26
-rw-r--r--utils/tinymix.c9
-rw-r--r--utils/tinyplay.c2
10 files changed, 130 insertions, 15 deletions
diff --git a/include/tinyalsa/mixer.h b/include/tinyalsa/mixer.h
index 7d0580f..149b395 100644
--- a/include/tinyalsa/mixer.h
+++ b/include/tinyalsa/mixer.h
@@ -103,6 +103,10 @@ struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
+struct mixer_ctl *mixer_get_ctl_by_name_and_device(struct mixer *mixer,
+ const char *name,
+ unsigned int device);
+
struct mixer_ctl *mixer_get_ctl_by_name_and_index(struct mixer *mixer,
const char *name,
unsigned int index);
@@ -153,6 +157,8 @@ int mixer_ctl_get_range_min(const struct mixer_ctl *ctl);
int mixer_ctl_get_range_max(const struct mixer_ctl *ctl);
+unsigned int mixer_ctl_get_device(const struct mixer_ctl *ctl);
+
int mixer_read_event(struct mixer *mixer, struct mixer_ctl_event *event);
int mixer_consume_event(struct mixer *mixer);
diff --git a/include/tinyalsa/pcm.h b/include/tinyalsa/pcm.h
index 9fca92d..35318a5 100644
--- a/include/tinyalsa/pcm.h
+++ b/include/tinyalsa/pcm.h
@@ -361,6 +361,8 @@ int pcm_prepare(struct pcm *pcm);
int pcm_start(struct pcm *pcm);
+int pcm_drain(struct pcm *pcm);
+
int pcm_stop(struct pcm *pcm);
int pcm_wait(struct pcm *pcm, int timeout);
diff --git a/include/tinyalsa/plugin.h b/include/tinyalsa/plugin.h
index b2f97b9..055734c 100644
--- a/include/tinyalsa/plugin.h
+++ b/include/tinyalsa/plugin.h
@@ -124,7 +124,10 @@ struct pcm_plugin_ops {
int (*prepare) (struct pcm_plugin *plugin);
/** Start data transfer from/to the plugin */
int (*start) (struct pcm_plugin *plugin);
- /** Drop pcm frames */
+ /** Signal the plugin to drain PCM */
+ int (*drain) (struct pcm_plugin *plugin);
+ /** Stop a PCM dropping pending frames if drain() is NOT called.
+ * Stop a PCM preserving pending frames if drain() is called. */
int (*drop) (struct pcm_plugin *plugin);
/** Any custom or alsa specific ioctl implementation */
int (*ioctl) (struct pcm_plugin *plugin,
diff --git a/src/mixer.c b/src/mixer.c
index 029fc84..f2c21c3 100644
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -760,6 +760,55 @@ struct mixer_ctl *mixer_get_ctl_by_name_and_index(struct mixer *mixer,
return NULL;
}
+/** Gets an instance of mixer control handle, by the mixer control's name and device.
+ * For instance, if two controls have same name,
+ * e.g. 'Playback Channel map', then PCM device returns the specific control.
+ * @param mixer An initialized mixer handle.
+ * @param name The control's name in the given mixer.
+ * @param device The PCM device
+ * @returns A handle to the mixer control.
+ * @ingroup libtinyalsa-mixer
+ */
+struct mixer_ctl *mixer_get_ctl_by_name_and_device(struct mixer *mixer,
+ const char *name,
+ unsigned int device)
+{
+ struct mixer_ctl_group *grp;
+ unsigned int n;
+ struct mixer_ctl *ctl;
+
+ if (!mixer || !name) {
+ return NULL;
+ }
+
+ if (mixer->h_grp) {
+ grp = mixer->h_grp;
+ ctl = grp->ctl;
+
+ for (n = 0; n < grp->count; n++) {
+ if (!strcmp(name, (char*) ctl[n].info.id.name) &&
+ device == ctl[n].info.id.device) {
+ return ctl + n;
+ }
+ }
+ }
+
+#ifdef TINYALSA_USES_PLUGINS
+ if (mixer->v_grp) {
+ grp = mixer->v_grp;
+ ctl = grp->ctl;
+
+ for (n = 0; n < grp->count; n++) {
+ if (!strcmp(name, (char*) ctl[n].info.id.name) &&
+ device == ctl[n].info.id.device) {
+ return ctl + n;
+ }
+ }
+ }
+#endif
+ return NULL;
+}
+
/** Updates the control's info.
* This is useful for a program that may be idle for a period of time.
* @param ctl An initialized control handle.
@@ -822,6 +871,14 @@ const char *mixer_ctl_get_name(const struct mixer_ctl *ctl)
return (const char *)ctl->info.id.name;
}
+unsigned int mixer_ctl_get_device(const struct mixer_ctl *ctl)
+{
+ if (!ctl)
+ return UINT_MAX;
+
+ return ctl->info.id.device;
+}
+
/** Gets the value type of the control.
* @param ctl An initialized control handle
* @returns On success, the type of mixer control.
diff --git a/src/pcm.c b/src/pcm.c
index d460593..1b2103a 100644
--- a/src/pcm.c
+++ b/src/pcm.c
@@ -1092,8 +1092,10 @@ struct pcm *pcm_open(unsigned int card, unsigned int device,
}
pcm->subdevice = info.subdevice;
- if (pcm_set_config(pcm, config) != 0)
+ if (pcm_set_config(pcm, config) != 0) {
+ memcpy(bad_pcm.error, pcm->error, sizeof(pcm->error));
goto fail_close;
+ }
rc = pcm_hw_mmap_status(pcm);
if (rc < 0) {
@@ -1216,6 +1218,22 @@ int pcm_start(struct pcm *pcm)
return 0;
}
+/** Drains a PCM.
+ * @param pcm A PCM handle.
+ * @return On success, zero; on failure, a negative number.
+ * @ingroup libtinyalsa-pcm
+ */
+int pcm_drain(struct pcm *pcm)
+{
+ if (!pcm_is_ready(pcm))
+ return -1;
+
+ if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_DRAIN) < 0)
+ return oops(pcm, errno, "cannot drain channel");
+
+ return 0;
+}
+
/** Stops a PCM.
* @param pcm A PCM handle.
* @return On success, zero; on failure, a negative number.
diff --git a/src/pcm_plugin.c b/src/pcm_plugin.c
index b6b69aa..4d2651c 100644
--- a/src/pcm_plugin.c
+++ b/src/pcm_plugin.c
@@ -622,6 +622,16 @@ static int pcm_plug_drop(struct pcm_plug_data *plug_data)
return rc;
}
+static int pcm_plug_drain(struct pcm_plug_data *plug_data)
+{
+ struct pcm_plugin *plugin = plug_data->plugin;
+
+ if (plugin->state != PCM_PLUG_STATE_RUNNING)
+ return -EBADFD;
+
+ return plug_data->ops->drain(plugin);
+}
+
static int pcm_plug_ioctl(void *data, unsigned int cmd, ...)
{
struct pcm_plug_data *plug_data = data;
@@ -659,6 +669,9 @@ static int pcm_plug_ioctl(void *data, unsigned int cmd, ...)
case SNDRV_PCM_IOCTL_START:
ret = pcm_plug_start(plug_data);
break;
+ case SNDRV_PCM_IOCTL_DRAIN:
+ ret = pcm_plug_drain(plug_data);
+ break;
case SNDRV_PCM_IOCTL_DROP:
ret = pcm_plug_drop(plug_data);
break;
diff --git a/utils/tinycap.1 b/utils/tinycap.1
index ad60a2e..d18dd12 100644
--- a/utils/tinycap.1
+++ b/utils/tinycap.1
@@ -24,6 +24,11 @@ Device number of the PCM.
The default is 0.
.TP
+\fB\-M\fR
+Use memory-mapped I/O method.
+If this option is not specified, then read and write I/O method will be used.
+
+.TP
\fB\-c\fR \fIchannels\fR
Number of channels the PCM will have.
The default is 2.
diff --git a/utils/tinycap.c b/utils/tinycap.c
index 7d4b8a4..617d16a 100644
--- a/utils/tinycap.c
+++ b/utils/tinycap.c
@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#include <signal.h>
#include <string.h>
#include <limits.h>
@@ -64,7 +65,7 @@ int capturing = 1;
int prinfo = 1;
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
- unsigned int channels, unsigned int rate,
+ bool use_mmap, unsigned int channels, unsigned int rate,
enum pcm_format format, unsigned int period_size,
unsigned int period_count, unsigned int capture_time);
@@ -88,12 +89,13 @@ int main(int argc, char **argv)
unsigned int period_size = 1024;
unsigned int period_count = 4;
unsigned int capture_time = UINT_MAX;
+ bool use_mmap = false;
enum pcm_format format;
int no_header = 0, c;
struct optparse opts;
if (argc < 2) {
- fprintf(stderr, "Usage: %s {file.wav | --} [-D card] [-d device] [-c channels] "
+ fprintf(stderr, "Usage: %s {file.wav | --} [-D card] [-d device] [-M] [-c channels] "
"[-r rate] [-b bits] [-p period_size] [-n n_periods] [-t time_in_seconds]\n\n"
"Use -- for filename to send raw PCM to stdout\n", argv[0]);
return 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
/* parse command line arguments */
optparse_init(&opts, argv + 1);
- while ((c = optparse(&opts, "D:d:c:r:b:p:n:t:")) != -1) {
+ while ((c = optparse(&opts, "D:d:c:r:b:p:n:t:M")) != -1) {
switch (c) {
case 'd':
device = atoi(opts.optarg);
@@ -139,6 +141,9 @@ int main(int argc, char **argv)
case 't':
capture_time = atoi(opts.optarg);
break;
+ case 'M':
+ use_mmap = true;
+ break;
case '?':
fprintf(stderr, "%s\n", opts.errmsg);
return EXIT_FAILURE;
@@ -182,9 +187,9 @@ int main(int argc, char **argv)
/* install signal handler and begin capturing */
signal(SIGINT, sigint_handler);
- frames = capture_sample(file, card, device, header.num_channels,
- header.sample_rate, format,
- period_size, period_count, capture_time);
+ frames = capture_sample(file, card, device, use_mmap,
+ header.num_channels, header.sample_rate,
+ format, period_size, period_count, capture_time);
if (prinfo) {
printf("Captured %u frames\n", frames);
}
@@ -203,11 +208,12 @@ int main(int argc, char **argv)
}
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
- unsigned int channels, unsigned int rate,
+ bool use_mmap, unsigned int channels, unsigned int rate,
enum pcm_format format, unsigned int period_size,
unsigned int period_count, unsigned int capture_time)
{
struct pcm_config config;
+ unsigned int pcm_open_flags;
struct pcm *pcm;
char *buffer;
unsigned int size;
@@ -225,7 +231,11 @@ unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
config.stop_threshold = 0;
config.silence_threshold = 0;
- pcm = pcm_open(card, device, PCM_IN, &config);
+ pcm_open_flags = PCM_IN;
+ if (use_mmap)
+ pcm_open_flags |= PCM_MMAP;
+
+ pcm = pcm_open(card, device, pcm_open_flags, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device (%s)\n",
pcm_get_error(pcm));
diff --git a/utils/tinymix.c b/utils/tinymix.c
index e272ade..edeb6ad 100644
--- a/utils/tinymix.c
+++ b/utils/tinymix.c
@@ -201,7 +201,7 @@ static void list_controls(struct mixer *mixer, int print_all)
{
struct mixer_ctl *ctl;
const char *name, *type;
- unsigned int num_ctls, num_values;
+ unsigned int num_ctls, num_values, device;
unsigned int i;
num_ctls = mixer_get_num_ctls(mixer);
@@ -209,9 +209,9 @@ static void list_controls(struct mixer *mixer, int print_all)
printf("Number of controls: %u\n", num_ctls);
if (print_all)
- printf("ctl\ttype\tnum\t%-40svalue\n", "name");
+ printf("ctl\ttype\tnum\t%-40s\tdevice\tvalue\n", "name");
else
- printf("ctl\ttype\tnum\t%-40s\n", "name");
+ printf("ctl\ttype\tnum\t%-40s\tdevice\n", "name");
for (i = 0; i < num_ctls; i++) {
ctl = mixer_get_ctl(mixer, i);
@@ -219,7 +219,8 @@ static void list_controls(struct mixer *mixer, int print_all)
name = mixer_ctl_get_name(ctl);
type = mixer_ctl_get_type_string(ctl);
num_values = mixer_ctl_get_num_values(ctl);
- printf("%u\t%s\t%u\t%-40s", i, type, num_values, name);
+ device = mixer_ctl_get_device(ctl);
+ printf("%u\t%s\t%u\t%-40s\t%u", i, type, num_values, name, device);
if (print_all)
print_control_values(ctl);
printf("\n");
diff --git a/utils/tinyplay.c b/utils/tinyplay.c
index 9f72bbb..d617074 100644
--- a/utils/tinyplay.c
+++ b/utils/tinyplay.c
@@ -112,7 +112,7 @@ static bool is_wave_file(const char *filetype)
return filetype != NULL && strcmp(filetype, "wav") == 0;
}
-static bool signed_pcm_bits_to_format(int bits)
+static enum pcm_format signed_pcm_bits_to_format(int bits)
{
switch (bits) {
case 8: