Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <sys/ioctl.h>
      7 #include <pthread.h>
      8 #include <sys/param.h>
      9 #include <syslog.h>
     10 
     11 #include "audio_thread.h"
     12 #include "byte_buffer.h"
     13 #include "cras_audio_area.h"
     14 #include "cras_config.h"
     15 #include "cras_iodev.h"
     16 #include "cras_iodev_list.h"
     17 #include "cras_types.h"
     18 #include "cras_util.h"
     19 #include "test_iodev.h"
     20 #include "utlist.h"
     21 
     22 #define TEST_BUFFER_SIZE (16 * 1024)
     23 
     24 static size_t test_supported_rates[] = {
     25 	16000, 0
     26 };
     27 
     28 static size_t test_supported_channel_counts[] = {
     29 	1, 0
     30 };
     31 
     32 static snd_pcm_format_t test_supported_formats[] = {
     33 	SND_PCM_FORMAT_S16_LE,
     34 	0
     35 };
     36 
     37 struct test_iodev {
     38 	struct cras_iodev base;
     39 	int fd;
     40 	struct byte_buffer *audbuff;
     41 	unsigned int fmt_bytes;
     42 };
     43 
     44 /*
     45  * iodev callbacks.
     46  */
     47 
     48 static int frames_queued(const struct cras_iodev *iodev,
     49 			 struct timespec *tstamp)
     50 {
     51 	struct test_iodev *testio = (struct test_iodev *)iodev;
     52 	int available;
     53 
     54 	if (testio->fd < 0)
     55 		return 0;
     56 	ioctl(testio->fd, FIONREAD, &available);
     57 	clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
     58 	return available / testio->fmt_bytes;
     59 }
     60 
     61 static int delay_frames(const struct cras_iodev *iodev)
     62 {
     63 	return 0;
     64 }
     65 
     66 static int close_dev(struct cras_iodev *iodev)
     67 {
     68 	struct test_iodev *testio = (struct test_iodev *)iodev;
     69 
     70 	byte_buffer_destroy(testio->audbuff);
     71 	testio->audbuff = NULL;
     72 	cras_iodev_free_audio_area(iodev);
     73 	return 0;
     74 }
     75 
     76 static int open_dev(struct cras_iodev *iodev)
     77 {
     78 	struct test_iodev *testio = (struct test_iodev *)iodev;
     79 
     80 	if (iodev->format == NULL)
     81 		return -EINVAL;
     82 
     83 	cras_iodev_init_audio_area(iodev, iodev->format->num_channels);
     84 	testio->fmt_bytes = cras_get_format_bytes(iodev->format);
     85 	testio->audbuff = byte_buffer_create(TEST_BUFFER_SIZE *
     86 						testio->fmt_bytes);
     87 
     88 	return 0;
     89 }
     90 
     91 static int get_buffer(struct cras_iodev *iodev,
     92 		      struct cras_audio_area **area,
     93 		      unsigned *frames)
     94 {
     95 	struct test_iodev *testio = (struct test_iodev *)iodev;
     96 	unsigned int readable;
     97 	uint8_t *buff;
     98 
     99 	buff = buf_read_pointer_size(testio->audbuff, &readable);
    100 	*frames = MIN(*frames, readable);
    101 
    102 	iodev->area->frames = *frames;
    103 	cras_audio_area_config_buf_pointers(iodev->area, iodev->format, buff);
    104 	*area = iodev->area;
    105 	return 0;
    106 }
    107 
    108 static int put_buffer(struct cras_iodev *iodev, unsigned frames)
    109 {
    110 	struct test_iodev *testio = (struct test_iodev *)iodev;
    111 
    112 	/* Input */
    113 	buf_increment_read(testio->audbuff, frames * testio->fmt_bytes);
    114 
    115 	return 0;
    116 }
    117 
    118 static int get_buffer_fd_read(struct cras_iodev *iodev,
    119 			      struct cras_audio_area **area,
    120 			      unsigned *frames)
    121 {
    122 	struct test_iodev *testio = (struct test_iodev *)iodev;
    123 	int nread;
    124 	uint8_t *write_ptr;
    125 	unsigned int avail;
    126 
    127 	if (testio->fd < 0) {
    128 		*frames = 0;
    129 		return 0;
    130 	}
    131 
    132 	write_ptr = buf_write_pointer_size(testio->audbuff, &avail);
    133 	avail = MIN(avail, *frames * testio->fmt_bytes);
    134 	nread = read(testio->fd, write_ptr, avail);
    135 	if (nread <= 0) {
    136 		*frames = 0;
    137 		audio_thread_rm_callback(testio->fd);
    138 		close(testio->fd);
    139 		testio->fd = -1;
    140 		return 0;
    141 	}
    142 	buf_increment_write(testio->audbuff, nread);
    143 	*frames = nread / testio->fmt_bytes;
    144 	iodev->area->frames = *frames;
    145 	cras_audio_area_config_buf_pointers(iodev->area, iodev->format,
    146 					    write_ptr);
    147 	*area = iodev->area;
    148 	return nread;
    149 }
    150 
    151 static void update_active_node(struct cras_iodev *iodev, unsigned node_idx,
    152 			       unsigned dev_enabled)
    153 {
    154 }
    155 
    156 static void play_file_as_hotword(struct test_iodev *testio, const char *path)
    157 {
    158 	if (testio->fd >= 0) {
    159 		/* Remove audio thread callback from main thread. */
    160 		audio_thread_rm_callback_sync(
    161 				cras_iodev_list_get_audio_thread(),
    162 				testio->fd);
    163 		close(testio->fd);
    164 	}
    165 
    166 	testio->fd = open(path, O_RDONLY);
    167 	buf_reset(testio->audbuff);
    168 }
    169 
    170 /*
    171  * Exported Interface.
    172  */
    173 
    174 struct cras_iodev *test_iodev_create(enum CRAS_STREAM_DIRECTION direction,
    175 				     enum TEST_IODEV_TYPE type)
    176 {
    177 	struct test_iodev *testio;
    178 	struct cras_iodev *iodev;
    179 	struct cras_ionode *node;
    180 
    181 	if (direction != CRAS_STREAM_INPUT || type != TEST_IODEV_HOTWORD)
    182 		return NULL;
    183 
    184 	testio = calloc(1, sizeof(*testio));
    185 	if (testio == NULL)
    186 		return NULL;
    187 	iodev = &testio->base;
    188 	iodev->direction = direction;
    189 	testio->fd = -1;
    190 
    191 	iodev->supported_rates = test_supported_rates;
    192 	iodev->supported_channel_counts = test_supported_channel_counts;
    193 	iodev->supported_formats = test_supported_formats;
    194 	iodev->buffer_size = TEST_BUFFER_SIZE;
    195 
    196 	iodev->open_dev = open_dev;
    197 	iodev->close_dev = close_dev;
    198 	iodev->frames_queued = frames_queued;
    199 	iodev->delay_frames = delay_frames;
    200 	if (type == TEST_IODEV_HOTWORD)
    201 		iodev->get_buffer = get_buffer_fd_read;
    202 	else
    203 		iodev->get_buffer = get_buffer;
    204 	iodev->put_buffer = put_buffer;
    205 	iodev->update_active_node = update_active_node;
    206 
    207 	/* Create a dummy ionode */
    208 	node = (struct cras_ionode *)calloc(1, sizeof(*node));
    209 	node->dev = iodev;
    210 	node->plugged = 1;
    211 	if (type == TEST_IODEV_HOTWORD)
    212 		node->type = CRAS_NODE_TYPE_HOTWORD;
    213 	else
    214 		node->type = CRAS_NODE_TYPE_UNKNOWN;
    215 	node->volume = 100;
    216 	node->software_volume_needed = 0;
    217 	node->max_software_gain = 0;
    218 	strcpy(node->name, "(default)");
    219 	cras_iodev_add_node(iodev, node);
    220 	cras_iodev_set_active_node(iodev, node);
    221 
    222 	/* Finally add it to the appropriate iodev list. */
    223 	snprintf(iodev->info.name, ARRAY_SIZE(iodev->info.name), "Tester");
    224 	iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
    225 	cras_iodev_list_add_input(iodev);
    226 
    227 	return iodev;
    228 }
    229 
    230 void test_iodev_destroy(struct cras_iodev *iodev)
    231 {
    232 	struct test_iodev *testio = (struct test_iodev *)iodev;
    233 
    234 	cras_iodev_list_rm_input(iodev);
    235 	free(iodev->active_node);
    236 	cras_iodev_free_resources(iodev);
    237 	free(testio);
    238 }
    239 
    240 unsigned int test_iodev_add_samples(struct test_iodev *testio,
    241 				    uint8_t *samples,
    242 				    unsigned int count)
    243 {
    244 	unsigned int avail;
    245 	uint8_t *write_ptr;
    246 
    247 	write_ptr = buf_write_pointer_size(testio->audbuff, &avail);
    248 	count = MIN(count, avail);
    249 	memcpy(write_ptr, samples, count * testio->fmt_bytes);
    250 	buf_increment_write(testio->audbuff, count * testio->fmt_bytes);
    251 	return count;
    252 }
    253 
    254 void test_iodev_command(struct cras_iodev *iodev,
    255 			enum CRAS_TEST_IODEV_CMD command,
    256 			unsigned int data_len,
    257 			const uint8_t *data)
    258 {
    259 	struct test_iodev *testio = (struct test_iodev *)iodev;
    260 
    261 	if (!cras_iodev_is_open(iodev))
    262 		return;
    263 
    264 	switch (command) {
    265 	case TEST_IODEV_CMD_HOTWORD_TRIGGER:
    266 		play_file_as_hotword(testio, (char *)data);
    267 		break;
    268 	default:
    269 		break;
    270 	}
    271 }
    272