| /* Copyright (c) 2012 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 <errno.h> |
| #include <fcntl.h> |
| #include <getopt.h> |
| #include <math.h> |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <syslog.h> |
| #include <sys/param.h> |
| #include <sys/select.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "cras_client.h" |
| #include "cras_types.h" |
| #include "cras_util.h" |
| #include "cras_version.h" |
| |
| #define NOT_ASSIGNED (0) |
| #define PLAYBACK_BUFFERED_TIME_IN_US (5000) |
| |
| #define BUF_SIZE 32768 |
| |
| static const size_t MAX_IODEVS = 10; /* Max devices to print out. */ |
| static const size_t MAX_IONODES = 20; /* Max ionodes to print out. */ |
| static const size_t MAX_ATTACHED_CLIENTS = 10; /* Max clients to print out. */ |
| |
| static int pipefd[2]; |
| static struct timespec last_latency; |
| static int show_latency; |
| static float last_rms_sqr_sum; |
| static int last_rms_size; |
| static float total_rms_sqr_sum; |
| static int total_rms_size; |
| static int show_rms; |
| static int show_total_rms; |
| static int keep_looping = 1; |
| static int exit_after_done_playing = 1; |
| static size_t duration_frames; |
| static int pause_client = 0; |
| static int pause_a_reply = 0; |
| static int pause_in_playback_reply = 1000; |
| |
| static char *channel_layout = NULL; |
| static int pin_device_id; |
| |
| static int play_short_sound = 0; |
| static int play_short_sound_periods = 0; |
| static int play_short_sound_periods_left = 0; |
| |
| /* Conditional so the client thread can signal that main should exit. */ |
| static pthread_mutex_t done_mutex = PTHREAD_MUTEX_INITIALIZER; |
| static pthread_cond_t done_cond = PTHREAD_COND_INITIALIZER; |
| |
| struct cras_audio_format *aud_format; |
| |
| static int terminate_stream_loop() |
| { |
| keep_looping = 0; |
| return write(pipefd[1], "1", 1); |
| } |
| |
| static size_t get_block_size(uint64_t buffer_time_in_us, size_t rate) |
| { |
| return (size_t)(buffer_time_in_us * rate / 1000000); |
| } |
| |
| static void check_stream_terminate(size_t frames) |
| { |
| if (duration_frames) { |
| if (duration_frames <= frames) |
| terminate_stream_loop(); |
| else |
| duration_frames -= frames; |
| } |
| } |
| |
| /* Compute square sum of samples (for calculation of RMS value). */ |
| float compute_sqr_sum_16(const int16_t *samples, int size) |
| { |
| unsigned i; |
| float sqr_sum = 0; |
| |
| for (i = 0; i < size; i++) |
| sqr_sum += samples[i] * samples[i]; |
| |
| return sqr_sum; |
| } |
| |
| /* Update the RMS values with the given samples. */ |
| int update_rms(const uint8_t *samples, int size) |
| { |
| switch (aud_format->format) { |
| case SND_PCM_FORMAT_S16_LE: { |
| last_rms_sqr_sum = compute_sqr_sum_16((int16_t *)samples, size / 2); |
| last_rms_size = size / 2; |
| break; |
| } |
| default: |
| return -EINVAL; |
| } |
| |
| total_rms_sqr_sum += last_rms_sqr_sum; |
| total_rms_size += last_rms_size; |
| |
| return 0; |
| } |
| |
| /* 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; |
| |
| while (pause_client) |
| usleep(10000); |
| |
| cras_client_calc_capture_latency(captured_time, &last_latency); |
| |
| frame_bytes = cras_client_format_bytes_per_frame(aud_format); |
| write_size = frames * frame_bytes; |
| |
| /* Update RMS values with all available frames. */ |
| if (keep_looping) { |
| update_rms(captured_samples, |
| MIN(write_size, duration_frames * frame_bytes)); |
| } |
| |
| check_stream_terminate(frames); |
| |
| ret = write(*fd, captured_samples, write_size); |
| if (ret != write_size) |
| printf("Error writing file\n"); |
| return frames; |
| } |
| |
| /* Run from callback thread. */ |
| static int got_hotword(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) |
| { |
| printf("got hotword %u frames\n", frames); |
| |
| 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; |
| |
| while (pause_client) |
| usleep(10000); |
| |
| if (pause_a_reply) { |
| usleep(pause_in_playback_reply); |
| pause_a_reply = 0; |
| } |
| |
| check_stream_terminate(frames); |
| |
| cras_client_calc_playback_latency(playback_time, &last_latency); |
| |
| if (play_short_sound) { |
| if (play_short_sound_periods_left) |
| /* Play a period from file. */ |
| play_short_sound_periods_left--; |
| else { |
| /* Fill zeros to play silence. */ |
| memset(playback_samples, 0, |
| MIN(frames * frame_bytes, BUF_SIZE)); |
| return frames; |
| } |
| } |
| |
| nread = read(fd, buff, MIN(frames * frame_bytes, BUF_SIZE)); |
| if (nread <= 0) { |
| if (exit_after_done_playing) |
| terminate_stream_loop(); |
| return nread; |
| } |
| |
| memcpy(playback_samples, buff, nread); |
| return nread / frame_bytes; |
| } |
| |
| /* Run from callback thread. */ |
| static int put_stdin_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 rc = 0; |
| uint32_t frame_bytes = cras_client_format_bytes_per_frame(aud_format); |
| |
| rc = read(0, playback_samples, frames * frame_bytes); |
| if (rc <= 0) { |
| terminate_stream_loop(); |
| return -1; |
| } |
| |
| return rc / 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 void print_last_latency() |
| { |
| if (last_latency.tv_sec > 0 || last_latency.tv_nsec > 0) |
| printf("%u.%09u\n", (unsigned)last_latency.tv_sec, |
| (unsigned)last_latency.tv_nsec); |
| else { |
| printf("-%lld.%09lld\n", (long long)-last_latency.tv_sec, |
| (long long)-last_latency.tv_nsec); |
| } |
| } |
| |
| static void print_last_rms() |
| { |
| if (last_rms_size != 0) |
| printf("%.9f\n", sqrt(last_rms_sqr_sum / last_rms_size)); |
| } |
| |
| static void print_total_rms() |
| { |
| if (total_rms_size != 0) |
| printf("%.9f\n", sqrt(total_rms_sqr_sum / total_rms_size)); |
| } |
| |
| static void print_dev_info(const struct cras_iodev_info *devs, int num_devs) |
| { |
| unsigned i; |
| |
| printf("\tID\tName\n"); |
| for (i = 0; i < num_devs; i++) |
| printf("\t%u\t%s\n", devs[i].idx, devs[i].name); |
| } |
| |
| static void print_node_info(const struct cras_ionode_info *nodes, int num_nodes, |
| int is_input) |
| { |
| unsigned i; |
| |
| printf("\tStable Id\t ID\t%4s Plugged\tL/R swapped\t " |
| "Time Hotword\tType\t\t Name\n", is_input ? "Gain" : " Vol"); |
| for (i = 0; i < num_nodes; i++) |
| printf("\t(%08x)\t%u:%u\t%5g %7s\t%14s\t%10ld %-7s\t%-16s%c%s\n", |
| nodes[i].stable_id, |
| nodes[i].iodev_idx, |
| nodes[i].ionode_idx, |
| is_input ? nodes[i].capture_gain / 100.0 |
| : (double) nodes[i].volume, |
| nodes[i].plugged ? "yes" : "no", |
| nodes[i].left_right_swapped ? "yes" : "no", |
| (long) nodes[i].plugged_time.tv_sec, |
| nodes[i].active_hotword_model, |
| nodes[i].type, |
| nodes[i].active ? '*' : ' ', |
| nodes[i].name); |
| } |
| |
| static void print_device_lists(struct cras_client *client) |
| { |
| struct cras_iodev_info devs[MAX_IODEVS]; |
| struct cras_ionode_info nodes[MAX_IONODES]; |
| size_t num_devs, num_nodes; |
| int rc; |
| |
| num_devs = MAX_IODEVS; |
| num_nodes = MAX_IONODES; |
| rc = cras_client_get_output_devices(client, devs, nodes, &num_devs, |
| &num_nodes); |
| if (rc < 0) |
| return; |
| printf("Output Devices:\n"); |
| print_dev_info(devs, num_devs); |
| printf("Output Nodes:\n"); |
| print_node_info(nodes, num_nodes, 0); |
| |
| num_devs = MAX_IODEVS; |
| num_nodes = MAX_IONODES; |
| rc = cras_client_get_input_devices(client, devs, nodes, &num_devs, |
| &num_nodes); |
| printf("Input Devices:\n"); |
| print_dev_info(devs, num_devs); |
| printf("Input Nodes:\n"); |
| print_node_info(nodes, num_nodes, 1); |
| } |
| |
| static void print_attached_client_list(struct cras_client *client) |
| { |
| struct cras_attached_client_info clients[MAX_ATTACHED_CLIENTS]; |
| size_t i; |
| int num_clients; |
| |
| num_clients = cras_client_get_attached_clients(client, |
| clients, |
| MAX_ATTACHED_CLIENTS); |
| if (num_clients < 0) |
| return; |
| num_clients = MIN(num_clients, MAX_ATTACHED_CLIENTS); |
| printf("Attached clients:\n"); |
| printf("\tID\tpid\tuid\n"); |
| for (i = 0; i < num_clients; i++) |
| printf("\t%u\t%d\t%d\n", |
| clients[i].id, |
| clients[i].pid, |
| clients[i].gid); |
| } |
| |
| static void print_active_stream_info(struct cras_client *client) |
| { |
| struct timespec ts; |
| unsigned num_streams; |
| |
| num_streams = cras_client_get_num_active_streams(client, &ts); |
| printf("Num active streams: %u\n", num_streams); |
| printf("Last audio active time: %llu, %llu\n", |
| (long long)ts.tv_sec, (long long)ts.tv_nsec); |
| } |
| |
| static void print_system_volumes(struct cras_client *client) |
| { |
| printf("System Volume (0-100): %zu %s\n" |
| "Capture Gain (%.2f - %.2f): %.2fdB %s\n", |
| cras_client_get_system_volume(client), |
| cras_client_get_system_muted(client) ? "(Muted)" : "", |
| cras_client_get_system_min_capture_gain(client) / 100.0, |
| cras_client_get_system_max_capture_gain(client) / 100.0, |
| cras_client_get_system_capture_gain(client) / 100.0, |
| cras_client_get_system_capture_muted(client) ? "(Muted)" : ""); |
| } |
| |
| static void print_user_muted(struct cras_client *client) |
| { |
| printf("User muted: %s\n", |
| cras_client_get_user_muted(client) ? "Muted" : "Not muted"); |
| } |
| |
| static void show_alog_tag(const struct audio_thread_event_log *log, |
| unsigned int tag_idx) |
| { |
| unsigned int tag = (log->log[tag_idx].tag_sec >> 24) & 0xff; |
| unsigned int sec = log->log[tag_idx].tag_sec & 0x00ffffff; |
| unsigned int nsec = log->log[tag_idx].nsec; |
| unsigned int data1 = log->log[tag_idx].data1; |
| unsigned int data2 = log->log[tag_idx].data2; |
| unsigned int data3 = log->log[tag_idx].data3; |
| |
| /* Skip unused log entries. */ |
| if (log->log[tag_idx].tag_sec == 0 && log->log[tag_idx].nsec == 0) |
| return; |
| |
| printf("%10u.%09u ", sec, nsec); |
| |
| switch (tag) { |
| case AUDIO_THREAD_WAKE: |
| printf("%-30s num_fds:%d\n", "WAKE", (int)data1); |
| break; |
| case AUDIO_THREAD_SLEEP: |
| printf("%-30s sleep:%09d.%09d longest_wake:%09d\n", |
| "SLEEP", (int)data1, (int)data2, (int)data3); |
| break; |
| case AUDIO_THREAD_READ_AUDIO: |
| printf("%-30s dev:%u hw_level:%u read:%u\n", |
| "READ_AUDIO", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_READ_AUDIO_TSTAMP: |
| printf("%-30s dev:%u tstamp:%09d.%09d\n", |
| "READ_AUDIO_TSTAMP", data1, (int)data2, (int)data3); |
| break; |
| case AUDIO_THREAD_READ_AUDIO_DONE: |
| printf("%-30s read_remainder:%u\n", "READ_AUDIO_DONE", data1); |
| break; |
| case AUDIO_THREAD_READ_OVERRUN: |
| printf("%-30s dev:%u stream:%x num_overruns:%u\n", |
| "READ_AUDIO_OVERRUN", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_FILL_AUDIO: |
| printf("%-30s dev:%u hw_level:%u\n", |
| "FILL_AUDIO", data1, data2); |
| break; |
| case AUDIO_THREAD_FILL_AUDIO_TSTAMP: |
| printf("%-30s dev:%u tstamp:%09d.%09d\n", |
| "FILL_AUDIO_TSTAMP", data1, (int)data2, (int)data3); |
| break; |
| case AUDIO_THREAD_FILL_AUDIO_DONE: |
| printf("%-30s hw_level:%u total_written:%u min_cb_level:%u\n", |
| "FILL_AUDIO_DONE", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_WRITE_STREAMS_WAIT: |
| printf("%-30s stream:%x\n", "WRITE_STREAMS_WAIT", data1); |
| break; |
| case AUDIO_THREAD_WRITE_STREAMS_WAIT_TO: |
| printf("%-30s\n", "WRITE_STREAMS_WAIT_TO"); |
| break; |
| case AUDIO_THREAD_WRITE_STREAMS_MIX: |
| printf("%-30s write_limit:%u max_offset:%u\n", |
| "WRITE_STREAMS_MIX", data1, data2); |
| break; |
| case AUDIO_THREAD_WRITE_STREAMS_MIXED: |
| printf("%-30s write_limit:%u\n", "WRITE_STREAMS_MIXED", data1); |
| break; |
| case AUDIO_THREAD_WRITE_STREAMS_STREAM: |
| printf("%-30s id:%x shm_frames:%u cb_pending:%u\n", |
| "WRITE_STREAMS_STREAM", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_FETCH_STREAM: |
| printf("%-30s id:%x cbth:%u delay:%u\n", |
| "WRITE_STREAMS_FETCH_STREAM", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_STREAM_ADDED: |
| printf("%-30s id:%x dev:%u\n", |
| "STREAM_ADDED", data1, data2); |
| break; |
| case AUDIO_THREAD_STREAM_REMOVED: |
| printf("%-30s id:%x\n", "STREAM_REMOVED", data1); |
| break; |
| case AUDIO_THREAD_A2DP_ENCODE: |
| printf("%-30s proc:%d queued:%u readable:%u\n", |
| "A2DP_ENCODE", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_A2DP_WRITE: |
| printf("%-30s written:%d queued:%u\n", |
| "A2DP_WRITE", data1, data2); |
| break; |
| case AUDIO_THREAD_DEV_STREAM_MIX: |
| printf("%-30s written:%u read:%u\n", |
| "DEV_STREAM_MIX", data1, data2); |
| break; |
| case AUDIO_THREAD_CAPTURE_POST: |
| printf("%-30s stream:%x thresh:%u rd_buf:%u\n", |
| "CAPTURE_POST", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_CAPTURE_WRITE: |
| printf("%-30s stream:%x write:%u shm_fr:%u\n", |
| "CAPTURE_WRITE", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_CONV_COPY: |
| printf("%-30s wr_buf:%u shm_writable:%u offset:%u\n", |
| "CONV_COPY", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_STREAM_SLEEP_TIME: |
| printf("%-30s id:%x wake:%09u.%09d\n", |
| "STREAM_SLEEP_TIME", data1, (int)data2, (int)data3); |
| break; |
| case AUDIO_THREAD_STREAM_SLEEP_ADJUST: |
| printf("%-30s id:%x from:%09u.%09d\n", |
| "STREAM_SLEEP_ADJUST", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_STREAM_SKIP_CB: |
| printf("%-30s id:%x write_offset_0:%u write_offset_1:%u\n", |
| "STREAM_SKIP_CB", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_DEV_SLEEP_TIME: |
| printf("%-30s dev:%u wake:%09u.%09d\n", |
| "DEV_SLEEP_TIME", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_SET_DEV_WAKE: |
| printf("%-30s dev:%u hw_level:%u sleep:%u\n", |
| "SET_DEV_WAKE", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_DEV_ADDED: |
| printf("%-30s dev:%u\n", "DEV_ADDED", data1); |
| break; |
| case AUDIO_THREAD_DEV_REMOVED: |
| printf("%-30s dev:%u\n", "DEV_REMOVED", data1); |
| break; |
| case AUDIO_THREAD_IODEV_CB: |
| printf("%-30s is_write:%u\n", "IODEV_CB", data1); |
| break; |
| case AUDIO_THREAD_PB_MSG: |
| printf("%-30s msg_id:%u\n", "PB_MSG", data1); |
| break; |
| case AUDIO_THREAD_ODEV_NO_STREAMS: |
| printf("%-30s dev:%u\n", |
| "ODEV_NO_STREAMS", data1); |
| break; |
| case AUDIO_THREAD_ODEV_LEAVE_NO_STREAMS: |
| printf("%-30s dev:%u\n", |
| "ODEV_LEAVE_NO_STREAMS", data1); |
| break; |
| case AUDIO_THREAD_ODEV_START: |
| printf("%-30s dev:%u min_cb_level:%u\n", |
| "ODEV_START", data1, data2); |
| break; |
| case AUDIO_THREAD_FILL_ODEV_ZEROS: |
| printf("%-30s dev:%u write:%u\n", |
| "FILL_ODEV_ZEROS", data1, data2); |
| break; |
| case AUDIO_THREAD_ODEV_DEFAULT_NO_STREAMS: |
| printf("%-30s dev:%u hw_level:%u target:%u\n", |
| "DEFAULT_NO_STREAMS", data1, data2, data3); |
| break; |
| case AUDIO_THREAD_SEVERE_UNDERRUN: |
| printf("%-30s dev:%u\n", "SEVERE_UNDERRUN", data1); |
| break; |
| default: |
| printf("%-30s tag:%u\n","UNKNOWN", tag); |
| break; |
| } |
| } |
| |
| static void audio_debug_info(struct cras_client *client) |
| { |
| const struct audio_debug_info *info; |
| int i, j; |
| |
| info = cras_client_get_audio_debug_info(client); |
| if (!info) |
| return; |
| |
| printf("Audio Debug Stats:\n"); |
| printf("-------------devices------------\n"); |
| if (info->num_devs > MAX_DEBUG_DEVS) |
| return; |
| |
| for (i = 0; i < info->num_devs; i++) { |
| printf("%s dev: %s\n", |
| (info->devs[i].direction == CRAS_STREAM_INPUT) |
| ? "Input" : "Output", |
| info->devs[i].dev_name); |
| printf("buffer_size: %u\n" |
| "min_buffer_level: %u\n" |
| "min_cb_level: %u\n" |
| "max_cb_level: %u\n" |
| "frame_rate: %u\n" |
| "num_channels: %u\n" |
| "est_rate_ratio: %lf\n" |
| "num_underruns: %u\n" |
| "num_severe_underruns: %u\n", |
| (unsigned int)info->devs[i].buffer_size, |
| (unsigned int)info->devs[i].min_buffer_level, |
| (unsigned int)info->devs[i].min_cb_level, |
| (unsigned int)info->devs[i].max_cb_level, |
| (unsigned int)info->devs[i].frame_rate, |
| (unsigned int)info->devs[i].num_channels, |
| info->devs[i].est_rate_ratio, |
| (unsigned int)info->devs[i].num_underruns, |
| (unsigned int)info->devs[i].num_severe_underruns); |
| printf("\n"); |
| } |
| |
| printf("-------------stream_dump------------\n"); |
| if (info->num_streams > MAX_DEBUG_STREAMS) |
| return; |
| |
| for (i = 0; i < info->num_streams; i++) { |
| int channel; |
| printf("stream: %llx dev: %u\n", |
| (unsigned long long)info->streams[i].stream_id, |
| (unsigned int)info->streams[i].dev_idx); |
| printf("direction: %s\n", |
| (info->streams[i].direction == CRAS_STREAM_INPUT) |
| ? "Input" : "Output"); |
| printf("stream_type: %s\n", |
| cras_stream_type_str(info->streams[i].stream_type)); |
| printf("buffer_frames: %u\n" |
| "cb_threshold: %u\n" |
| "frame_rate: %u\n" |
| "num_channels: %u\n" |
| "longest_fetch_sec: %u.%09u\n" |
| "num_overruns: %u\n", |
| (unsigned int)info->streams[i].buffer_frames, |
| (unsigned int)info->streams[i].cb_threshold, |
| (unsigned int)info->streams[i].frame_rate, |
| (unsigned int)info->streams[i].num_channels, |
| (unsigned int)info->streams[i].longest_fetch_sec, |
| (unsigned int)info->streams[i].longest_fetch_nsec, |
| (unsigned int)info->streams[i].num_overruns); |
| printf("channel map:"); |
| for (channel = 0; channel < CRAS_CH_MAX; channel++) |
| printf("%d ", info->streams[i].channel_layout[channel]); |
| printf("\n\n"); |
| } |
| |
| printf("Audio Thread Event Log:\n"); |
| |
| j = info->log.write_pos; |
| i = 0; |
| printf("start at %d\n", j); |
| for (; i < info->log.len; i++) { |
| show_alog_tag(&info->log, j); |
| j++; |
| j %= info->log.len; |
| } |
| |
| /* Signal main thread we are done after the last chunk. */ |
| pthread_mutex_lock(&done_mutex); |
| pthread_cond_signal(&done_cond); |
| pthread_mutex_unlock(&done_mutex); |
| } |
| |
| static int start_stream(struct cras_client *client, |
| cras_stream_id_t *stream_id, |
| struct cras_stream_params *params, |
| float stream_volume) |
| { |
| int rc; |
| |
| if (pin_device_id) |
| rc = cras_client_add_pinned_stream(client, pin_device_id, |
| stream_id, params); |
| else |
| 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 parse_channel_layout(char *channel_layout_str, |
| int8_t channel_layout[CRAS_CH_MAX]) |
| { |
| int i = 0; |
| char *chp; |
| |
| chp = strtok(channel_layout_str, ","); |
| while (chp && i < CRAS_CH_MAX) { |
| channel_layout[i++] = atoi(chp); |
| chp = strtok(NULL, ","); |
| } |
| |
| return 0; |
| } |
| |
| static int run_file_io_stream(struct cras_client *client, |
| int fd, |
| enum CRAS_STREAM_DIRECTION direction, |
| size_t block_size, |
| enum CRAS_STREAM_TYPE stream_type, |
| size_t rate, |
| size_t num_channels, |
| uint32_t flags, |
| int is_loopback) |
| { |
| int rc, tty; |
| struct cras_stream_params *params; |
| cras_unified_cb_t aud_cb; |
| cras_stream_id_t stream_id = 0; |
| int stream_playing = 0; |
| int *pfd = malloc(sizeof(*pfd)); |
| *pfd = fd; |
| fd_set poll_set; |
| struct timespec sleep_ts; |
| float volume_scaler = 1.0; |
| size_t sys_volume = 100; |
| long cap_gain = 0; |
| int mute = 0; |
| int8_t layout[CRAS_CH_MAX]; |
| |
| /* Set the sleep interval between latency/RMS prints. */ |
| sleep_ts.tv_sec = 1; |
| sleep_ts.tv_nsec = 0; |
| |
| /* Open the pipe file descriptor. */ |
| rc = pipe(pipefd); |
| if (rc == -1) { |
| perror("failed to open pipe"); |
| return -errno; |
| } |
| |
| /* Reset the total RMS value. */ |
| total_rms_sqr_sum = 0; |
| total_rms_size = 0; |
| |
| if (direction == CRAS_STREAM_INPUT) { |
| if (flags == HOTWORD_STREAM) |
| aud_cb = got_hotword; |
| else |
| aud_cb = got_samples; |
| } else { |
| aud_cb = put_samples; |
| } |
| |
| if (fd == 0) { |
| if (direction != CRAS_STREAM_OUTPUT) |
| return -EINVAL; |
| aud_cb = put_stdin_samples; |
| } |
| |
| aud_format = cras_audio_format_create(SND_PCM_FORMAT_S16_LE, rate, |
| num_channels); |
| if (aud_format == NULL) |
| return -ENOMEM; |
| |
| if (channel_layout) { |
| /* Set channel layout to format */ |
| parse_channel_layout(channel_layout, layout); |
| cras_audio_format_set_channel_layout(aud_format, layout); |
| } |
| |
| params = cras_client_unified_params_create(direction, |
| block_size, |
| stream_type, |
| flags, |
| pfd, |
| aud_cb, |
| stream_error, |
| aud_format); |
| if (params == NULL) |
| return -ENOMEM; |
| |
| cras_client_run_thread(client); |
| if (is_loopback) { |
| cras_client_connected_wait(client); |
| pin_device_id = cras_client_get_first_dev_type_idx(client, |
| CRAS_NODE_TYPE_POST_MIX_PRE_DSP, |
| CRAS_STREAM_INPUT); |
| } |
| |
| stream_playing = |
| start_stream(client, &stream_id, params, volume_scaler) == 0; |
| |
| tty = open("/dev/tty", O_RDONLY); |
| |
| // There could be no terminal available when run in autotest. |
| if (tty == -1) |
| perror("warning: failed to open /dev/tty"); |
| |
| while (keep_looping) { |
| char input; |
| int nread; |
| |
| FD_ZERO(&poll_set); |
| if (tty >= 0) |
| FD_SET(tty, &poll_set); |
| FD_SET(pipefd[0], &poll_set); |
| pselect(MAX(tty, pipefd[0]) + 1, |
| &poll_set, |
| NULL, |
| NULL, |
| show_latency || show_rms ? &sleep_ts : NULL, |
| NULL); |
| |
| if (stream_playing && show_latency) |
| print_last_latency(); |
| |
| if (stream_playing && show_rms) |
| print_last_rms(); |
| |
| if (tty < 0 || !FD_ISSET(tty, &poll_set)) |
| continue; |
| |
| nread = read(tty, &input, 1); |
| if (nread < 1) { |
| fprintf(stderr, "Error reading stdin\n"); |
| return nread; |
| } |
| switch (input) { |
| case 'p': |
| pause_client = !pause_client; |
| break; |
| case 'i': |
| pause_a_reply = 1; |
| break; |
| case 'q': |
| terminate_stream_loop(); |
| break; |
| case 's': |
| if (stream_playing) |
| break; |
| |
| /* If started by hand keep running after it finishes. */ |
| exit_after_done_playing = 0; |
| |
| stream_playing = start_stream(client, |
| &stream_id, |
| params, |
| volume_scaler) == 0; |
| break; |
| case 'r': |
| if (!stream_playing) |
| break; |
| cras_client_rm_stream(client, stream_id); |
| stream_playing = 0; |
| break; |
| case 'u': |
| volume_scaler = MIN(volume_scaler + 0.1, 1.0); |
| cras_client_set_stream_volume(client, |
| stream_id, |
| volume_scaler); |
| break; |
| case 'd': |
| volume_scaler = MAX(volume_scaler - 0.1, 0.0); |
| cras_client_set_stream_volume(client, |
| stream_id, |
| volume_scaler); |
| break; |
| case 'k': |
| sys_volume = MIN(sys_volume + 1, 100); |
| cras_client_set_system_volume(client, sys_volume); |
| break; |
| case 'j': |
| sys_volume = sys_volume == 0 ? 0 : sys_volume - 1; |
| cras_client_set_system_volume(client, sys_volume); |
| break; |
| case 'K': |
| cap_gain = MIN(cap_gain + 100, 5000); |
| cras_client_set_system_capture_gain(client, cap_gain); |
| break; |
| case 'J': |
| cap_gain = cap_gain == -5000 ? -5000 : cap_gain - 100; |
| cras_client_set_system_capture_gain(client, cap_gain); |
| break; |
| case 'm': |
| mute = !mute; |
| cras_client_set_system_mute(client, mute); |
| break; |
| case '@': |
| print_device_lists(client); |
| break; |
| case '#': |
| print_attached_client_list(client); |
| break; |
| case 'v': |
| printf("Volume: %zu%s Min dB: %ld Max dB: %ld\n" |
| "Capture: %ld%s Min dB: %ld Max dB: %ld\n", |
| cras_client_get_system_volume(client), |
| cras_client_get_system_muted(client) ? "(Muted)" |
| : "", |
| cras_client_get_system_min_volume(client), |
| cras_client_get_system_max_volume(client), |
| cras_client_get_system_capture_gain(client), |
| cras_client_get_system_capture_muted(client) ? |
| "(Muted)" : "", |
| cras_client_get_system_min_capture_gain(client), |
| cras_client_get_system_max_capture_gain(client)); |
| break; |
| case '\'': |
| play_short_sound_periods_left = play_short_sound_periods; |
| break; |
| case '\n': |
| break; |
| default: |
| printf("Invalid key\n"); |
| break; |
| } |
| } |
| |
| if (show_total_rms) |
| print_total_rms(); |
| |
| 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 int run_capture(struct cras_client *client, |
| const char *file, |
| size_t block_size, |
| enum CRAS_STREAM_TYPE stream_type, |
| size_t rate, |
| size_t num_channels, |
| int is_loopback) |
| { |
| int fd = open(file, O_CREAT | O_RDWR | O_TRUNC, 0666); |
| if (fd == -1) { |
| perror("failed to open file"); |
| return -errno; |
| } |
| |
| run_file_io_stream(client, fd, CRAS_STREAM_INPUT, block_size, |
| stream_type, rate, num_channels, 0, is_loopback); |
| |
| close(fd); |
| return 0; |
| } |
| |
| static int run_playback(struct cras_client *client, |
| const char *file, |
| size_t block_size, |
| enum CRAS_STREAM_TYPE stream_type, |
| size_t rate, |
| size_t num_channels) |
| { |
| int fd; |
| |
| fd = open(file, O_RDONLY); |
| if (fd == -1) { |
| perror("failed to open file"); |
| return -errno; |
| } |
| |
| run_file_io_stream(client, fd, CRAS_STREAM_OUTPUT, block_size, |
| stream_type, rate, num_channels, 0, 0); |
| |
| close(fd); |
| return 0; |
| } |
| |
| static int run_hotword(struct cras_client *client, |
| size_t block_size, |
| size_t rate) |
| { |
| run_file_io_stream(client, -1, CRAS_STREAM_INPUT, block_size, |
| CRAS_STREAM_TYPE_DEFAULT, rate, 1, HOTWORD_STREAM, |
| 0); |
| return 0; |
| } |
| static void print_server_info(struct cras_client *client) |
| { |
| cras_client_run_thread(client); |
| cras_client_connected_wait(client); /* To synchronize data. */ |
| print_system_volumes(client); |
| print_user_muted(client); |
| print_device_lists(client); |
| print_attached_client_list(client); |
| print_active_stream_info(client); |
| } |
| |
| static void print_audio_debug_info(struct cras_client *client) |
| { |
| struct timespec wait_time; |
| |
| cras_client_run_thread(client); |
| cras_client_connected_wait(client); /* To synchronize data. */ |
| cras_client_update_audio_debug_info(client, audio_debug_info); |
| |
| clock_gettime(CLOCK_REALTIME, &wait_time); |
| wait_time.tv_sec += 2; |
| |
| pthread_mutex_lock(&done_mutex); |
| pthread_cond_timedwait(&done_cond, &done_mutex, &wait_time); |
| pthread_mutex_unlock(&done_mutex); |
| } |
| |
| static void hotword_models_cb(struct cras_client *client, |
| const char *hotword_models) |
| { |
| printf("Hotword models: %s\n", hotword_models); |
| } |
| |
| static void print_hotword_models(struct cras_client *client, |
| cras_node_id_t id) |
| { |
| struct timespec wait_time; |
| |
| cras_client_run_thread(client); |
| cras_client_connected_wait(client); |
| cras_client_get_hotword_models(client, id, |
| hotword_models_cb); |
| |
| clock_gettime(CLOCK_REALTIME, &wait_time); |
| wait_time.tv_sec += 2; |
| |
| pthread_mutex_lock(&done_mutex); |
| pthread_cond_timedwait(&done_cond, &done_mutex, &wait_time); |
| pthread_mutex_unlock(&done_mutex); |
| } |
| |
| static void check_output_plugged(struct cras_client *client, const char *name) |
| { |
| cras_client_run_thread(client); |
| cras_client_connected_wait(client); /* To synchronize data. */ |
| printf("%s\n", |
| cras_client_output_dev_plugged(client, name) ? "Yes" : "No"); |
| } |
| |
| /* Repeatedly mute and unmute the output until there is an error. */ |
| static void mute_loop_test(struct cras_client *client, int auto_reconnect) |
| { |
| int mute = 0; |
| int rc; |
| |
| if (auto_reconnect) |
| cras_client_run_thread(client); |
| while(1) { |
| rc = cras_client_set_user_mute(client, mute); |
| printf("cras_client_set_user_mute(%d): %d\n", mute, rc); |
| if (rc != 0 && !auto_reconnect) |
| return; |
| mute = !mute; |
| sleep(2); |
| } |
| } |
| |
| static struct option long_options[] = { |
| {"show_latency", no_argument, &show_latency, 1}, |
| {"show_rms", no_argument, &show_rms, 1}, |
| {"show_total_rms", no_argument, &show_total_rms, 1}, |
| {"select_input", required_argument, 0, 'a'}, |
| {"block_size", required_argument, 0, 'b'}, |
| {"capture_file", required_argument, 0, 'c'}, |
| {"duration_seconds", required_argument, 0, 'd'}, |
| {"dump_dsp", no_argument, 0, 'f'}, |
| {"capture_gain", required_argument, 0, 'g'}, |
| {"help", no_argument, 0, 'h'}, |
| {"dump_server_info", no_argument, 0, 'i'}, |
| {"check_output_plugged",required_argument, 0, 'j'}, |
| {"add_active_input", required_argument, 0, 'k'}, |
| {"add_active_output", required_argument, 0, 't'}, |
| {"loopback_file", required_argument, 0, 'l'}, |
| {"dump_audio_thread", no_argument, 0, 'm'}, |
| {"num_channels", required_argument, 0, 'n'}, |
| {"channel_layout", required_argument, 0, 'o'}, |
| {"playback_file", required_argument, 0, 'p'}, |
| {"user_mute", required_argument, 0, 'q'}, |
| {"rate", required_argument, 0, 'r'}, |
| {"reload_dsp", no_argument, 0, 's'}, |
| {"mute", required_argument, 0, 'u'}, |
| {"volume", required_argument, 0, 'v'}, |
| {"set_node_volume", required_argument, 0, 'w'}, |
| {"plug", required_argument, 0, 'x'}, |
| {"select_output", required_argument, 0, 'y'}, |
| {"playback_delay_us", required_argument, 0, 'z'}, |
| {"capture_mute", required_argument, 0, '0'}, |
| {"rm_active_input", required_argument, 0, '1'}, |
| {"rm_active_output", required_argument, 0, '2'}, |
| {"swap_left_right", required_argument, 0, '3'}, |
| {"version", no_argument, 0, '4'}, |
| {"add_test_dev", required_argument, 0, '5'}, |
| {"test_hotword_file", required_argument, 0, '6'}, |
| {"listen_for_hotword", no_argument, 0, '7'}, |
| {"pin_device", required_argument, 0, '8'}, |
| {"suspend", required_argument, 0, '9'}, |
| {"set_node_gain", required_argument, 0, ':'}, |
| {"play_short_sound", required_argument, 0, '!'}, |
| {"config_global_remix", required_argument, 0, ';'}, |
| {"set_hotword_model", required_argument, 0, '<'}, |
| {"get_hotword_models", required_argument, 0, '>'}, |
| {"syslog_mask", required_argument, 0, 'L'}, |
| {"mute_loop_test", required_argument, 0, 'M'}, |
| {"stream_type", required_argument, 0, 'T'}, |
| {0, 0, 0, 0} |
| }; |
| |
| static void show_usage() |
| { |
| printf("--add_active_input <N>:<M> - Add the ionode with the given id" |
| "to active input device list\n"); |
| printf("--add_active_output <N>:<M> - Add the ionode with the given id" |
| "to active output device list\n"); |
| printf("--add_test_dev <type> - add a test iodev.\n"); |
| printf("--block_size <N> - The number for frames per callback(dictates latency).\n"); |
| printf("--capture_file <name> - Name of file to record to.\n"); |
| printf("--capture_gain <dB> - Set system caputre gain in dB*100 (100 = 1dB).\n"); |
| printf("--capture_mute <0|1> - Set capture mute state.\n"); |
| printf("--channel_layout <layout_str> - Set multiple channel layout.\n"); |
| printf("--check_output_plugged <output name> - Check if the output is plugged in\n"); |
| printf("--dump_audio_thread - Dumps audio thread info.\n"); |
| printf("--dump_dsp - Print status of dsp to syslog.\n"); |
| printf("--dump_server_info - Print status of the server.\n"); |
| printf("--duration_seconds <N> - Seconds to record or playback.\n"); |
| printf("--get_hotword_models <N>:<M> - Get the supported hotword models of node\n"); |
| printf("--help - Print this message.\n"); |
| printf("--listen_for_hotword - Listen for a hotword if supported\n"); |
| printf("--loopback_file <name> - Name of file to record loopback to.\n"); |
| printf("--mute <0|1> - Set system mute state.\n"); |
| printf("--mute_loop_test <0|1> - Continuously loop mute/umute. Argument: 0 - stop on error.\n" |
| " 1 - automatically reconnect to CRAS.\n"); |
| printf("--num_channels <N> - Two for stereo.\n"); |
| printf("--pin_device <N> - Playback/Capture only on the given device." |
| "\n"); |
| printf("--playback_file <name> - Name of file to play, " |
| "\"-\" to playback raw audio from stdin.\n"); |
| printf("--play_short_sound <N> - Plays the content in the file for N periods when ' is pressed.\n"); |
| printf("--plug <N>:<M>:<0|1> - Set the plug state (0 or 1) for the" |
| " ionode with the given index M on the device with index N\n"); |
| printf("--rate <N> - Specifies the sample rate in Hz.\n"); |
| printf("--reload_dsp - Reload dsp configuration from the ini file\n"); |
| printf("--rm_active_input <N>:<M> - Removes the ionode with the given" |
| "id from active input device list\n"); |
| printf("--rm_active_output <N>:<M> - Removes the ionode with the given" |
| "id from active output device list\n"); |
| printf("--select_input <N>:<M> - Select the ionode with the given id as preferred input\n"); |
| printf("--select_output <N>:<M> - Select the ionode with the given id as preferred output\n"); |
| printf("--set_hotword_model <N>:<M>:<model> - Set the model to node\n"); |
| printf("--playback_delay_us <N> - Set the time in us to delay a reply for playback when i is pressed\n"); |
| printf("--set_node_volume <N>:<M>:<0-100> - Set the volume of the ionode with the given id\n"); |
| printf("--show_latency - Display latency while playing or recording.\n"); |
| printf("--show_rms - Display RMS value of loopback stream.\n"); |
| printf("--show_total_rms - Display total RMS value of loopback stream at the end.\n"); |
| printf("--suspend <0|1> - Set audio suspend state.\n"); |
| printf("--swap_left_right <N>:<M>:<0|1> - Swap or unswap (1 or 0) the" |
| " left and right channel for the ionode with the given index M" |
| " on the device with index N\n"); |
| printf("--stream_type <N> - Specify the type of the stream.\n"); |
| printf("--syslog_mask <n> - Set the syslog mask to the given log level.\n"); |
| printf("--test_hotword_file <N>:<filename> - Use filename as a hotword buffer for device N\n"); |
| printf("--user_mute <0|1> - Set user mute state.\n"); |
| printf("--version - Print the git commit ID that was used to build the client.\n"); |
| printf("--volume <0-100> - Set system output volume.\n"); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct cras_client *client; |
| int c, option_index; |
| size_t block_size = NOT_ASSIGNED; |
| size_t rate = 48000; |
| size_t num_channels = 2; |
| float duration_seconds = 0; |
| const char *capture_file = NULL; |
| const char *playback_file = NULL; |
| const char *loopback_file = NULL; |
| enum CRAS_STREAM_TYPE stream_type = CRAS_STREAM_TYPE_DEFAULT; |
| int rc = 0; |
| |
| option_index = 0; |
| openlog("cras_test_client", LOG_PERROR, LOG_USER); |
| setlogmask(LOG_UPTO(LOG_INFO)); |
| |
| rc = cras_client_create(&client); |
| if (rc < 0) { |
| fprintf(stderr, "Couldn't create client.\n"); |
| return rc; |
| } |
| |
| rc = cras_client_connect_timeout(client, 1000); |
| if (rc) { |
| fprintf(stderr, "Couldn't connect to server.\n"); |
| goto destroy_exit; |
| } |
| |
| while (1) { |
| c = getopt_long(argc, argv, "o:s:", |
| long_options, &option_index); |
| if (c == -1) |
| break; |
| switch (c) { |
| case 'c': |
| capture_file = optarg; |
| break; |
| case 'p': |
| playback_file = optarg; |
| break; |
| case 'l': |
| loopback_file = optarg; |
| break; |
| case 'b': |
| block_size = atoi(optarg); |
| break; |
| case 'r': |
| rate = atoi(optarg); |
| break; |
| case 'n': |
| num_channels = atoi(optarg); |
| break; |
| case 'd': |
| duration_seconds = atof(optarg); |
| break; |
| case 'u': { |
| int mute = atoi(optarg); |
| rc = cras_client_set_system_mute(client, mute); |
| if (rc < 0) { |
| fprintf(stderr, "problem setting mute\n"); |
| goto destroy_exit; |
| } |
| break; |
| } |
| case 'q': { |
| int mute = atoi(optarg); |
| rc = cras_client_set_user_mute(client, mute); |
| if (rc < 0) { |
| fprintf(stderr, "problem setting mute\n"); |
| goto destroy_exit; |
| } |
| break; |
| } |
| case 'v': { |
| int volume = atoi(optarg); |
| volume = MIN(100, MAX(0, volume)); |
| rc = cras_client_set_system_volume(client, volume); |
| if (rc < 0) { |
| fprintf(stderr, "problem setting volume\n"); |
| goto destroy_exit; |
| } |
| break; |
| } |
| case 'g': { |
| long gain = atol(optarg); |
| rc = cras_client_set_system_capture_gain(client, gain); |
| if (rc < 0) { |
| fprintf(stderr, "problem setting capture\n"); |
| goto destroy_exit; |
| } |
| break; |
| } |
| case 'j': |
| check_output_plugged(client, optarg); |
| break; |
| case 's': |
| cras_client_reload_dsp(client); |
| break; |
| case 'f': |
| cras_client_dump_dsp_info(client); |
| break; |
| case 'i': |
| print_server_info(client); |
| break; |
| case 'h': |
| show_usage(); |
| break; |
| case 'x': { |
| int dev_index = atoi(strtok(optarg, ":")); |
| int node_index = atoi(strtok(NULL, ":")); |
| int value = atoi(strtok(NULL, ":")) ; |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| enum ionode_attr attr = IONODE_ATTR_PLUGGED; |
| cras_client_set_node_attr(client, id, attr, value); |
| break; |
| } |
| case 'y': |
| case 'a': { |
| int dev_index = atoi(strtok(optarg, ":")); |
| int node_index = atoi(strtok(NULL, ":")); |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| |
| enum CRAS_STREAM_DIRECTION direction = (c == 'y') ? |
| CRAS_STREAM_OUTPUT : CRAS_STREAM_INPUT; |
| cras_client_select_node(client, direction, id); |
| break; |
| } |
| case 'z': |
| pause_in_playback_reply = atoi(optarg); |
| break; |
| case 'k': |
| case 't': |
| case '1': |
| case '2':{ |
| int dev_index = atoi(strtok(optarg, ":")); |
| int node_index = atoi(strtok(NULL, ":")); |
| enum CRAS_STREAM_DIRECTION dir; |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| |
| if (c == 't' || c == '2') |
| dir = CRAS_STREAM_OUTPUT; |
| else |
| dir = CRAS_STREAM_INPUT; |
| |
| if (c == 'k' || c == 't') |
| cras_client_add_active_node(client, dir, id); |
| else |
| cras_client_rm_active_node(client, dir, id); |
| break; |
| } |
| case ':': |
| case 'w': { |
| const char *s; |
| int dev_index; |
| int node_index; |
| int value; |
| |
| s = strtok(optarg, ":"); |
| if (!s) { |
| show_usage(); |
| return -EINVAL; |
| } |
| dev_index = atoi(s); |
| |
| s = strtok(NULL, ":"); |
| if (!s) { |
| show_usage(); |
| return -EINVAL; |
| } |
| node_index = atoi(s); |
| |
| s = strtok(NULL, ":"); |
| if (!s) { |
| show_usage(); |
| return -EINVAL; |
| } |
| value = atoi(s) ; |
| |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| |
| if (c == 'w') |
| cras_client_set_node_volume(client, id, value); |
| else |
| cras_client_set_node_capture_gain( |
| client, id, value); |
| break; |
| } |
| case '0': { |
| int mute = atoi(optarg); |
| rc = cras_client_set_system_capture_mute(client, mute); |
| if (rc < 0) { |
| fprintf(stderr, "problem setting mute\n"); |
| goto destroy_exit; |
| } |
| break; |
| } |
| case 'm': |
| print_audio_debug_info(client); |
| break; |
| case 'o': |
| channel_layout = optarg; |
| break; |
| case '3': { |
| int dev_index = atoi(strtok(optarg, ":")); |
| int node_index = atoi(strtok(NULL, ":")); |
| int value = atoi(strtok(NULL, ":")) ; |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| cras_client_swap_node_left_right(client, id, value); |
| break; |
| } |
| case '4': |
| printf("%s\n", VCSID); |
| break; |
| case '5': { |
| cras_client_add_test_iodev(client, atoi(optarg)); |
| break; |
| } |
| case '6': { |
| int dev_index = atoi(strtok(optarg, ":")); |
| const char *file_name = strtok(NULL, ":"); |
| cras_client_test_iodev_command(client, dev_index, |
| TEST_IODEV_CMD_HOTWORD_TRIGGER, |
| strlen(file_name) + 1, |
| (uint8_t *)file_name); |
| break; |
| } |
| case '7': { |
| run_hotword(client, 4096, 16000); |
| break; |
| } |
| case '8': |
| pin_device_id = atoi(optarg); |
| break; |
| case '9': { |
| int suspend = atoi(optarg); |
| cras_client_set_suspend(client, suspend); |
| break; |
| } |
| case '!': { |
| play_short_sound = 1; |
| play_short_sound_periods = atoi(optarg); |
| break; |
| } |
| case ';': { |
| char *s; |
| int nch; |
| int size = 0; |
| float *coeff; |
| |
| s = strtok(optarg, ":"); |
| nch = atoi(s); |
| coeff = (float *)calloc(nch * nch, |
| sizeof(*coeff)); |
| for (size = 0; size < nch * nch; size++) { |
| s = strtok(NULL, ","); |
| if (NULL == s) |
| break; |
| coeff[size] = atof(s); |
| } |
| cras_client_config_global_remix(client, nch, coeff); |
| free(coeff); |
| break; |
| } |
| case '<': |
| case '>': { |
| char *s; |
| int dev_index; |
| int node_index; |
| |
| s = strtok(optarg, ":"); |
| if (!s) { |
| show_usage(); |
| return -EINVAL; |
| } |
| dev_index = atoi(s); |
| |
| s = strtok(NULL, ":"); |
| if (!s) { |
| show_usage(); |
| return -EINVAL; |
| } |
| node_index = atoi(s); |
| |
| s = strtok(NULL, ":"); |
| if (!s && c == ';') { |
| show_usage(); |
| return -EINVAL; |
| } |
| |
| cras_node_id_t id = cras_make_node_id(dev_index, |
| node_index); |
| if (c == '<') |
| cras_client_set_hotword_model(client, id, s); |
| else |
| print_hotword_models(client, id); |
| break; |
| } |
| case 'L': { |
| int log_level = atoi(optarg); |
| |
| setlogmask(LOG_UPTO(log_level)); |
| break; |
| } |
| case 'M': |
| mute_loop_test(client, atoi(optarg)); |
| break; |
| case 'T': |
| stream_type = atoi(optarg); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| duration_frames = duration_seconds * rate; |
| if (block_size == NOT_ASSIGNED) |
| block_size = get_block_size(PLAYBACK_BUFFERED_TIME_IN_US, rate); |
| |
| if (capture_file != NULL) { |
| if (strcmp(capture_file, "-") == 0) |
| rc = run_file_io_stream(client, 1, CRAS_STREAM_INPUT, |
| block_size, stream_type, rate, |
| num_channels, 0, 0); |
| else |
| rc = run_capture(client, capture_file, block_size, |
| stream_type, rate, num_channels, 0); |
| } else if (playback_file != NULL) { |
| if (strcmp(playback_file, "-") == 0) |
| rc = run_file_io_stream(client, 0, CRAS_STREAM_OUTPUT, |
| block_size, stream_type, rate, |
| num_channels, 0, 0); |
| else |
| rc = run_playback(client, playback_file, block_size, |
| stream_type, rate, num_channels); |
| } else if (loopback_file != NULL) { |
| rc = run_capture(client, loopback_file, block_size, |
| stream_type, rate, num_channels, 1); |
| } |
| |
| destroy_exit: |
| cras_client_destroy(client); |
| return rc; |
| } |