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