summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChase Brandon <qchaseb@google.com>2016-07-12 16:13:10 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-05 06:28:29 -0700
commit81b3032369be1bdb5976a1f7772b6c9fb94229ac (patch)
tree022092b89799875b28fcd9457b63521a75b914e3
parent6233e2d706ac5fb74b78365d6c844d558660d21c (diff)
downloadadhd-81b3032369be1bdb5976a1f7772b6c9fb94229ac.tar.gz
CRAS: cras_router - Audio routing using cras
Routes from user selected input to user selected output to create closed loop testing environment. Now functions as a command line program with options. Seperate commit from cras_test_helper. DSP will be on seperate commit after discussing exactly where to put the change. Select input/output now removed from router as it is now done with python on the front end. BUG=None TEST=ran file to/from various outputs/inputs on samus Change-Id: I21ec7c6cd62f9b711a58ae0fcd28fb4db86c0192 Reviewed-on: https://chromium-review.googlesource.com/358130 Commit-Ready: Cheng-Yi Chiang <cychiang@chromium.org> Tested-by: Cheng-Yi Chiang <cychiang@chromium.org> Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
-rw-r--r--cras/src/Makefile.am10
-rw-r--r--cras/src/tests/cras_router.c269
2 files changed, 278 insertions, 1 deletions
diff --git a/cras/src/Makefile.am b/cras/src/Makefile.am
index d688bfbf..e83e9481 100644
--- a/cras/src/Makefile.am
+++ b/cras/src/Makefile.am
@@ -33,7 +33,7 @@ CRAS_UT_TMPDIR_CFLAGS=-DCRAS_UT_TMPDIR=\"/tmp\"
COMMON_CPPFLAGS = -O2 -Wall -Werror -Wno-error=cpp
COMMON_SIMD_CPPFLAGS = -O3 -Wall -Werror -Wno-error=cpp
-bin_PROGRAMS = cras cras_test_client cras_monitor
+bin_PROGRAMS = cras cras_test_client cras_monitor cras_router
if HAVE_DBUS
CRAS_DBUS_SOURCES = \
@@ -331,6 +331,14 @@ cras_monitor_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/libcras \
tests/cras_monitor.c: common/cras_version.h
+cras_router_SOURCES = tests/cras_router.c
+cras_router_LDADD = -lm libcras.la
+cras_router_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/libcras \
+ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/dsp \
+ -I$(top_srcdir)/src/server -I$(top_builddir)/src/common
+
+tests/cras_router.c: common/cras_version.h
+
CLEANFILES = common/cras_version.h
.PHONY: common/cras_version.h
common/cras_version.h:
diff --git a/cras/src/tests/cras_router.c b/cras/src/tests/cras_router.c
new file mode 100644
index 00000000..d813bc64
--- /dev/null
+++ b/cras/src/tests/cras_router.c
@@ -0,0 +1,269 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <fcntl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "cras_client.h"
+#include "cras_types.h"
+#include "cras_util.h"
+#include "cras_version.h"
+
+#define PLAYBACK_BUFFERED_TIME_IN_NS (5000000)
+
+#define BUF_SIZE 32768
+
+static int keep_looping = 1;
+static int pipefd[2];
+struct cras_audio_format *aud_format;
+
+static int terminate_stream_loop(void)
+{
+ keep_looping = 0;
+ return write(pipefd[1], "1", 1);
+}
+
+static size_t get_block_size(uint64_t buffer_time_in_ns, size_t rate)
+{
+ static struct timespec t;
+
+ t.tv_nsec = buffer_time_in_ns;
+ t.tv_sec = 0;
+ return (size_t)cras_time_to_frames(&t, rate);
+}
+
+/* Run from callback thread. */
+static int got_samples(struct cras_client *client,
+ cras_stream_id_t stream_id,
+ uint8_t *captured_samples,
+ uint8_t *playback_samples,
+ unsigned int frames,
+ const struct timespec *captured_time,
+ const struct timespec *playback_time,
+ void *user_arg)
+{
+ int *fd = (int *)user_arg;
+ int ret;
+ int write_size;
+ int frame_bytes;
+
+ frame_bytes = cras_client_format_bytes_per_frame(aud_format);
+ write_size = frames * frame_bytes;
+ ret = write(*fd, captured_samples, write_size);
+ if (ret != write_size)
+ printf("Error writing file\n");
+ return frames;
+}
+
+/* Run from callback thread. */
+static int put_samples(struct cras_client *client,
+ cras_stream_id_t stream_id,
+ uint8_t *captured_samples,
+ uint8_t *playback_samples,
+ unsigned int frames,
+ const struct timespec *captured_time,
+ const struct timespec *playback_time,
+ void *user_arg)
+{
+ uint32_t frame_bytes = cras_client_format_bytes_per_frame(aud_format);
+ int fd = *(int *)user_arg;
+ uint8_t buff[BUF_SIZE];
+ int nread;
+
+ nread = read(fd, buff, MIN(frames * frame_bytes, BUF_SIZE));
+ if (nread <= 0) {
+ terminate_stream_loop();
+ return nread;
+ }
+
+ memcpy(playback_samples, buff, nread);
+ return nread / frame_bytes;
+}
+
+static int stream_error(struct cras_client *client,
+ cras_stream_id_t stream_id,
+ int err,
+ void *arg)
+{
+ printf("Stream error %d\n", err);
+ terminate_stream_loop();
+ return 0;
+}
+
+static int start_stream(struct cras_client *client,
+ cras_stream_id_t *stream_id,
+ struct cras_stream_params *params,
+ float stream_volume)
+{
+ int rc;
+
+ rc = cras_client_add_stream(client, stream_id, params);
+ if (rc < 0) {
+ fprintf(stderr, "adding a stream %d\n", rc);
+ return rc;
+ }
+ return cras_client_set_stream_volume(client,
+ *stream_id,
+ stream_volume);
+}
+
+static int run_file_io_stream(struct cras_client *client,
+ int fd,
+ int loop_fd,
+ enum CRAS_STREAM_DIRECTION direction,
+ size_t block_size,
+ size_t rate,
+ size_t num_channels)
+{
+ struct cras_stream_params *params;
+ cras_stream_id_t stream_id = 0;
+ int stream_playing = 0;
+ int *pfd = malloc(sizeof(*pfd));
+ *pfd = fd;
+ float volume_scaler = 1.0;
+
+ if (pipe(pipefd) == -1) {
+ perror("failed to open pipe");
+ return -errno;
+ }
+ aud_format = cras_audio_format_create(SND_PCM_FORMAT_S16_LE, rate,
+ num_channels);
+ if (aud_format == NULL)
+ return -ENOMEM;
+
+ params = cras_client_unified_params_create(direction,
+ block_size,
+ 0,
+ 0,
+ pfd,
+ got_samples,
+ stream_error,
+ aud_format);
+ if (params == NULL)
+ return -ENOMEM;
+
+ cras_client_run_thread(client);
+ stream_playing =
+ start_stream(client, &stream_id, params, volume_scaler) == 0;
+ if (!stream_playing)
+ return -EINVAL;
+
+ int *pfd1 = malloc(sizeof(*pfd1));
+ *pfd1 = loop_fd;
+ struct cras_stream_params *loop_params;
+ cras_stream_id_t loop_stream_id = 0;
+
+ direction = CRAS_STREAM_OUTPUT;
+
+ loop_params = cras_client_unified_params_create(direction,
+ block_size,
+ 0,
+ 0,
+ pfd1,
+ put_samples,
+ stream_error,
+ aud_format);
+ stream_playing =
+ start_stream(client, &loop_stream_id,
+ loop_params, volume_scaler) == 0;
+ if (!stream_playing)
+ return -EINVAL;
+
+ fd_set poll_set;
+
+ FD_ZERO(&poll_set);
+ FD_SET(pipefd[0], &poll_set);
+ pselect(pipefd[0] + 1, &poll_set, NULL, NULL, NULL, NULL);
+ cras_client_stop(client);
+ cras_audio_format_destroy(aud_format);
+ cras_client_stream_params_destroy(params);
+ free(pfd);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ return 0;
+}
+
+static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"rate", required_argument, 0, 'r'},
+ {0, 0, 0, 0}
+};
+
+static void show_usage(void)
+{
+ printf("--help - shows this message and exits\n");
+ printf("--rate <N> - desired sample rate\n\n");
+ printf("Running cras_router will run a loop through ");
+ printf("from the currently set input to the currently set output.\n");
+ printf("Use cras_test_client --dump_s to see all avaiable nodes and");
+ printf(" cras_test_client --set_input/output to set a node.\n");
+}
+
+int main(int argc, char **argv)
+{
+ struct cras_client *client;
+ size_t rate = 44100;
+ size_t num_channels = 2;
+ size_t block_size;
+ int rc = 0;
+ int c, option_index;
+
+ option_index = 0;
+
+ rc = cras_client_create(&client);
+ if (rc < 0) {
+ fprintf(stderr, "Couldn't create client.\n");
+ return rc;
+ }
+
+ rc = cras_client_connect(client);
+ if (rc) {
+ fprintf(stderr, "Couldn't connect to server.\n");
+ goto destroy_exit;
+ }
+
+ while (1) {
+ c = getopt_long(argc, argv, "hr:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'h':
+ show_usage();
+ goto destroy_exit;
+ case 'r':
+ rate = atoi(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ block_size = get_block_size(PLAYBACK_BUFFERED_TIME_IN_NS, rate);
+
+ /* Run loopthrough */
+ int pfd[2];
+
+ rc = pipe(pfd);
+ if (rc < 0) {
+ fprintf(stderr, "Couldn't create loopthrough pipe.\n");
+ return rc;
+ }
+ run_file_io_stream(client, pfd[1], pfd[0], CRAS_STREAM_INPUT,
+ block_size, rate, num_channels);
+
+destroy_exit:
+ cras_client_destroy(client);
+ return rc;
+}