diff options
author | Chase Brandon <qchaseb@google.com> | 2016-07-12 16:13:10 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-05 06:28:29 -0700 |
commit | 81b3032369be1bdb5976a1f7772b6c9fb94229ac (patch) | |
tree | 022092b89799875b28fcd9457b63521a75b914e3 | |
parent | 6233e2d706ac5fb74b78365d6c844d558660d21c (diff) | |
download | adhd-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.am | 10 | ||||
-rw-r--r-- | cras/src/tests/cras_router.c | 269 |
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; +} |