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