/src/adhd/cras/src/server/cras_loopback_iodev.c
Line | Count | Source |
1 | | /* Copyright 2013 The ChromiumOS Authors |
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 "cras/src/server/cras_loopback_iodev.h" |
7 | | |
8 | | #include <sched.h> |
9 | | #include <stdbool.h> |
10 | | #include <stdint.h> |
11 | | #include <stdio.h> |
12 | | #include <stdlib.h> |
13 | | #include <string.h> |
14 | | #include <sys/param.h> |
15 | | #include <time.h> |
16 | | |
17 | | #include "cras/src/common/byte_buffer.h" |
18 | | #include "cras/src/server/audio_thread_log.h" |
19 | | #include "cras/src/server/cras_audio_area.h" |
20 | | #include "cras/src/server/cras_iodev.h" |
21 | | #include "cras/src/server/cras_iodev_list.h" |
22 | | #include "cras_audio_format.h" |
23 | | #include "cras_types.h" |
24 | | #include "cras_util.h" |
25 | | #include "third_party/strlcpy/strlcpy.h" |
26 | | #include "third_party/superfasthash/sfh.h" |
27 | | |
28 | 36 | #define LOOPBACK_BUFFER_SIZE 8192 |
29 | | |
30 | | static const char* loopdev_names[LOOPBACK_NUM_TYPES] = { |
31 | | "Post Mix Pre DSP Loopback", |
32 | | "Post DSP Loopback", |
33 | | "Post DSP Delayed Loopback", |
34 | | }; |
35 | | |
36 | | static size_t loopback_supported_rates[] = {48000, 0}; |
37 | | |
38 | | static size_t loopback_supported_channel_counts[] = {2, 0}; |
39 | | |
40 | | static snd_pcm_format_t loopback_supported_formats[] = { |
41 | | SND_PCM_FORMAT_S16_LE, |
42 | | 0, |
43 | | }; |
44 | | |
45 | | // loopack iodev. Keep state of a loopback device. |
46 | | struct loopback_iodev { |
47 | | struct cras_iodev base; |
48 | | // Pre-dsp or post-dsp. |
49 | | enum CRAS_LOOPBACK_TYPE loopback_type; |
50 | | // Frames of audio data read since last dev start. |
51 | | uint64_t read_frames; |
52 | | // True to indicate the target device is running, otherwise false. |
53 | | bool started; |
54 | | // The timestamp of the last call to configure_dev. |
55 | | struct timespec dev_start_time; |
56 | | // Pointer to sample buffer. |
57 | | struct byte_buffer* sample_buffer; |
58 | | // Index of the output device to read loopback audio. |
59 | | unsigned int sender_idx; |
60 | | }; |
61 | | |
62 | 0 | static int sample_hook_start(bool start, void* cb_data) { |
63 | 0 | struct loopback_iodev* loopdev = (struct loopback_iodev*)cb_data; |
64 | 0 | loopdev->started = start; |
65 | 0 | return 0; |
66 | 0 | } |
67 | | |
68 | | /* |
69 | | * Called in the put buffer function of the sender that hooked to. |
70 | | * |
71 | | * Returns: |
72 | | * Number of frames copied to the sample buffer in the hook. |
73 | | */ |
74 | | static int sample_hook(const uint8_t* frames, |
75 | | unsigned int nframes, |
76 | | const struct cras_audio_format* fmt, |
77 | 0 | void* cb_data) { |
78 | 0 | struct loopback_iodev* loopdev = (struct loopback_iodev*)cb_data; |
79 | 0 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
80 | 0 | unsigned int frame_bytes = cras_get_format_bytes(fmt); |
81 | 0 | unsigned int frames_to_copy, bytes_to_copy, frames_copied = 0; |
82 | 0 | int i; |
83 | |
|
84 | 0 | for (i = 0; i < 2; i++) { |
85 | 0 | frames_to_copy = MIN(buf_writable(sbuf) / frame_bytes, nframes); |
86 | 0 | if (!frames_to_copy) { |
87 | 0 | break; |
88 | 0 | } |
89 | | |
90 | 0 | bytes_to_copy = frames_to_copy * frame_bytes; |
91 | 0 | memcpy(buf_write_pointer(sbuf), frames, bytes_to_copy); |
92 | 0 | buf_increment_write(sbuf, bytes_to_copy); |
93 | 0 | frames += bytes_to_copy; |
94 | 0 | nframes -= frames_to_copy; |
95 | 0 | frames_copied += frames_to_copy; |
96 | 0 | } |
97 | |
|
98 | 0 | ATLOG(atlog, AUDIO_THREAD_LOOPBACK_SAMPLE_HOOK, nframes + frames_copied, |
99 | 0 | frames_copied, 0); |
100 | |
|
101 | 0 | return frames_copied; |
102 | 0 | } |
103 | | |
104 | 0 | static void update_first_output_to_loopback(struct loopback_iodev* loopdev) { |
105 | 0 | struct cras_iodev* edev; |
106 | | |
107 | | // Register loopback hook onto first enabled iodev. |
108 | 0 | edev = cras_iodev_list_get_first_enabled_iodev(CRAS_STREAM_OUTPUT); |
109 | 0 | if (edev) { |
110 | 0 | loopdev->sender_idx = edev->info.idx; |
111 | 0 | cras_iodev_list_register_loopback( |
112 | 0 | loopdev->loopback_type, loopdev->sender_idx, sample_hook, |
113 | 0 | sample_hook_start, loopdev->base.info.idx); |
114 | 0 | } else { |
115 | 0 | loopdev->started = false; |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | 0 | static void device_enabled_hook(struct cras_iodev* iodev, void* cb_data) { |
120 | 0 | struct loopback_iodev* loopdev = (struct loopback_iodev*)cb_data; |
121 | |
|
122 | 0 | if (iodev->direction != CRAS_STREAM_OUTPUT) { |
123 | 0 | return; |
124 | 0 | } |
125 | | |
126 | 0 | update_first_output_to_loopback(loopdev); |
127 | 0 | } |
128 | | |
129 | 0 | static void device_disabled_hook(struct cras_iodev* iodev, void* cb_data) { |
130 | 0 | struct loopback_iodev* loopdev = (struct loopback_iodev*)cb_data; |
131 | |
|
132 | 0 | if (loopdev->sender_idx != iodev->info.idx) { |
133 | 0 | return; |
134 | 0 | } |
135 | | |
136 | | // Unregister loopback hook from disabled iodev. |
137 | 0 | cras_iodev_list_unregister_loopback( |
138 | 0 | loopdev->loopback_type, loopdev->sender_idx, loopdev->base.info.idx); |
139 | 0 | update_first_output_to_loopback(loopdev); |
140 | 0 | } |
141 | | |
142 | | /* |
143 | | * iodev callbacks. |
144 | | */ |
145 | | |
146 | | static int frames_queued(const struct cras_iodev* iodev, |
147 | 2.90k | struct timespec* hw_tstamp) { |
148 | 2.90k | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
149 | 2.90k | struct byte_buffer* sbuf = loopdev->sample_buffer; |
150 | 2.90k | unsigned int frame_bytes = cras_get_format_bytes(iodev->format); |
151 | | |
152 | | /* Do nothing in the transient period after iodev is open but |
153 | | * loopback stream not yet connected. Otherwise if we report |
154 | | * some frames are queued, audio thread will go ahead consume |
155 | | * them all and that deletes the initial delay created for |
156 | | * post DSP delayed version of loopback. */ |
157 | 2.90k | if (!iodev->streams) { |
158 | 894 | hw_tstamp->tv_nsec = 0; |
159 | 894 | hw_tstamp->tv_sec = 0; |
160 | 894 | return 0; |
161 | 894 | } |
162 | | |
163 | 2.00k | if (!loopdev->started) { |
164 | 2.00k | unsigned int frames_since_start, frames_to_fill, bytes_to_fill; |
165 | | |
166 | 2.00k | frames_since_start = cras_frames_since_time(&loopdev->dev_start_time, |
167 | 2.00k | iodev->format->frame_rate); |
168 | 2.00k | frames_to_fill = frames_since_start > loopdev->read_frames |
169 | 2.00k | ? frames_since_start - loopdev->read_frames |
170 | 2.00k | : 0; |
171 | 2.00k | frames_to_fill = MIN(buf_writable(sbuf) / frame_bytes, frames_to_fill); |
172 | 2.00k | if (frames_to_fill > 0) { |
173 | 596 | bytes_to_fill = frames_to_fill * frame_bytes; |
174 | 596 | memset(buf_write_pointer(sbuf), 0, bytes_to_fill); |
175 | 596 | buf_increment_write(sbuf, bytes_to_fill); |
176 | 596 | } |
177 | 2.00k | } |
178 | 2.00k | clock_gettime(CLOCK_MONOTONIC_RAW, hw_tstamp); |
179 | 2.00k | return buf_queued(sbuf) / frame_bytes; |
180 | 2.90k | } |
181 | | |
182 | 1.07k | static int delay_frames(const struct cras_iodev* iodev) { |
183 | 1.07k | struct timespec tstamp; |
184 | | |
185 | 1.07k | return frames_queued(iodev, &tstamp); |
186 | 1.07k | } |
187 | | |
188 | 115 | static int close_record_dev(struct cras_iodev* iodev) { |
189 | 115 | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
190 | 115 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
191 | | |
192 | 115 | cras_iodev_free_format(iodev); |
193 | 115 | cras_iodev_free_audio_area(iodev); |
194 | 115 | buf_reset(sbuf); |
195 | | |
196 | 115 | cras_iodev_list_unregister_loopback( |
197 | 115 | loopdev->loopback_type, loopdev->sender_idx, loopdev->base.info.idx); |
198 | 115 | loopdev->sender_idx = NO_DEVICE; |
199 | 115 | cras_iodev_list_set_device_enabled_callback(NULL, NULL, NULL, (void*)iodev); |
200 | | |
201 | 115 | return 0; |
202 | 115 | } |
203 | | |
204 | 115 | static int configure_record_dev(struct cras_iodev* iodev) { |
205 | 115 | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
206 | 115 | struct cras_iodev* edev; |
207 | 115 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
208 | | |
209 | 115 | cras_iodev_init_audio_area(iodev); |
210 | 115 | clock_gettime(CLOCK_MONOTONIC_RAW, &loopdev->dev_start_time); |
211 | 115 | loopdev->read_frames = 0; |
212 | 115 | loopdev->started = 0; |
213 | | |
214 | 115 | edev = cras_iodev_list_get_first_enabled_iodev(CRAS_STREAM_OUTPUT); |
215 | 115 | if (edev) { |
216 | 115 | loopdev->sender_idx = edev->info.idx; |
217 | 115 | cras_iodev_list_register_loopback(loopdev->loopback_type, |
218 | 115 | loopdev->sender_idx, sample_hook, |
219 | 115 | sample_hook_start, iodev->info.idx); |
220 | 115 | } |
221 | 115 | cras_iodev_list_set_device_enabled_callback( |
222 | 115 | device_enabled_hook, device_disabled_hook, NULL, (void*)iodev); |
223 | | |
224 | | /* Fills the sample_buffer by zeros to simulate the delay caused |
225 | | * by real hardware. */ |
226 | 115 | if (loopdev->loopback_type == LOOPBACK_POST_DSP_DELAYED) { |
227 | 29 | memset(buf_write_pointer(sbuf), 0, buf_writable(sbuf)); |
228 | 29 | buf_increment_write(sbuf, buf_writable(sbuf)); |
229 | 29 | } |
230 | | |
231 | 115 | return 0; |
232 | 115 | } |
233 | | |
234 | | static int get_record_buffer(struct cras_iodev* iodev, |
235 | | struct cras_audio_area** area, |
236 | 267 | unsigned* frames) { |
237 | 267 | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
238 | 267 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
239 | 267 | unsigned int frame_bytes = cras_get_format_bytes(iodev->format); |
240 | 267 | unsigned int avail_frames = buf_readable(sbuf) / frame_bytes; |
241 | | |
242 | 267 | ATLOG(atlog, AUDIO_THREAD_LOOPBACK_GET, *frames, avail_frames, 0); |
243 | | |
244 | 267 | *frames = MIN(avail_frames, *frames); |
245 | 267 | iodev->area->frames = *frames; |
246 | 267 | cras_audio_area_config_buf_pointers(iodev->area, iodev->format, |
247 | 267 | buf_read_pointer(sbuf)); |
248 | 267 | *area = iodev->area; |
249 | | |
250 | 267 | return 0; |
251 | 267 | } |
252 | | |
253 | 267 | static int put_record_buffer(struct cras_iodev* iodev, unsigned nframes) { |
254 | 267 | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
255 | 267 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
256 | 267 | unsigned int frame_bytes = cras_get_format_bytes(iodev->format); |
257 | | |
258 | 267 | buf_increment_read(sbuf, (size_t)nframes * (size_t)frame_bytes); |
259 | 267 | loopdev->read_frames += nframes; |
260 | 267 | ATLOG(atlog, AUDIO_THREAD_LOOPBACK_PUT, nframes, 0, 0); |
261 | 267 | return 0; |
262 | 267 | } |
263 | | |
264 | 112 | static int flush_record_buffer(struct cras_iodev* iodev) { |
265 | | /* |
266 | | * Flush buffer is used in multiple inputs use case to align |
267 | | * the buffer level when the first stream connects to iodev. |
268 | | * Loopback device is not intended to be used in the multiple |
269 | | * inputs manner and we want to keep the initial delay for |
270 | | * the post DSP delayed version of loopback. |
271 | | */ |
272 | 112 | return 0; |
273 | 112 | } |
274 | | |
275 | | static void update_active_node(struct cras_iodev* iodev, |
276 | | unsigned node_idx, |
277 | 515 | unsigned dev_enabled) {} |
278 | | |
279 | | /* |
280 | | * Loopback devices are forced to be stereo. However, the channel |
281 | | * layout is not created to match the force assignment. This |
282 | | * function should set the channel layout as default, that is |
283 | | * FL, FR in this case. |
284 | | */ |
285 | 115 | static int loopback_update_channel_layout(struct cras_iodev* iodev) { |
286 | 115 | cras_audio_format_set_default_channel_layout(iodev->format); |
287 | | |
288 | 115 | return 0; |
289 | 115 | } |
290 | | |
291 | 18 | static struct cras_iodev* create_loopback_iodev(enum CRAS_LOOPBACK_TYPE type) { |
292 | 18 | struct loopback_iodev* loopback_iodev; |
293 | 18 | struct cras_iodev* iodev; |
294 | | |
295 | 18 | loopback_iodev = calloc(1, sizeof(*loopback_iodev)); |
296 | 18 | if (loopback_iodev == NULL) { |
297 | 0 | return NULL; |
298 | 0 | } |
299 | | |
300 | 18 | loopback_iodev->sample_buffer = byte_buffer_create(LOOPBACK_BUFFER_SIZE * 4); |
301 | 18 | if (loopback_iodev->sample_buffer == NULL) { |
302 | 0 | free(loopback_iodev); |
303 | 0 | return NULL; |
304 | 0 | } |
305 | | |
306 | 18 | loopback_iodev->loopback_type = type; |
307 | | |
308 | 18 | iodev = &loopback_iodev->base; |
309 | 18 | iodev->direction = CRAS_STREAM_INPUT; |
310 | 18 | snprintf(iodev->info.name, ARRAY_SIZE(iodev->info.name), "%s", |
311 | 18 | loopdev_names[type]); |
312 | 18 | iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0'; |
313 | 18 | iodev->info.stable_id = SuperFastHash( |
314 | 18 | iodev->info.name, strlen(iodev->info.name), strlen(iodev->info.name)); |
315 | | |
316 | 18 | iodev->supported_rates = loopback_supported_rates; |
317 | 18 | iodev->supported_channel_counts = loopback_supported_channel_counts; |
318 | 18 | iodev->supported_formats = loopback_supported_formats; |
319 | 18 | iodev->buffer_size = LOOPBACK_BUFFER_SIZE; |
320 | 18 | iodev->is_utility_device = true; |
321 | 18 | iodev->ignore_capture_mute = true; |
322 | | |
323 | 18 | iodev->frames_queued = frames_queued; |
324 | 18 | iodev->delay_frames = delay_frames; |
325 | 18 | iodev->update_active_node = update_active_node; |
326 | 18 | iodev->configure_dev = configure_record_dev; |
327 | 18 | iodev->close_dev = close_record_dev; |
328 | 18 | iodev->get_buffer = get_record_buffer; |
329 | 18 | iodev->put_buffer = put_record_buffer; |
330 | 18 | iodev->flush_buffer = flush_record_buffer; |
331 | 18 | iodev->update_channel_layout = loopback_update_channel_layout; |
332 | | |
333 | | /* |
334 | | * Record max supported channels into cras_iodev_info. |
335 | | * The value is the max of loopback_supported_channel_counts. |
336 | | */ |
337 | 18 | iodev->info.max_supported_channels = 2; |
338 | | |
339 | 18 | return iodev; |
340 | 18 | } |
341 | | |
342 | | /* |
343 | | * Exported Interface. |
344 | | */ |
345 | | |
346 | 18 | struct cras_iodev* loopback_iodev_create(enum CRAS_LOOPBACK_TYPE type) { |
347 | 18 | struct cras_iodev* iodev; |
348 | 18 | struct cras_ionode* node; |
349 | 18 | enum CRAS_NODE_TYPE node_type; |
350 | | |
351 | 18 | switch (type) { |
352 | 6 | case LOOPBACK_POST_MIX_PRE_DSP: |
353 | 6 | node_type = CRAS_NODE_TYPE_POST_MIX_PRE_DSP; |
354 | 6 | break; |
355 | 6 | case LOOPBACK_POST_DSP: |
356 | 6 | node_type = CRAS_NODE_TYPE_POST_DSP; |
357 | 6 | break; |
358 | 6 | case LOOPBACK_POST_DSP_DELAYED: |
359 | 6 | node_type = CRAS_NODE_TYPE_POST_DSP_DELAYED; |
360 | 6 | break; |
361 | 0 | default: |
362 | 0 | return NULL; |
363 | 18 | } |
364 | | |
365 | 18 | iodev = create_loopback_iodev(type); |
366 | 18 | if (iodev == NULL) { |
367 | 0 | return NULL; |
368 | 0 | } |
369 | | |
370 | | // Create an empty ionode |
371 | 18 | node = (struct cras_ionode*)calloc(1, sizeof(*node)); |
372 | 18 | node->dev = iodev; |
373 | 18 | node->type = node_type; |
374 | 18 | node->plugged = 1; |
375 | 18 | node->volume = 100; |
376 | 18 | node->ui_gain_scaler = 1.0f; |
377 | 18 | node->stable_id = iodev->info.stable_id; |
378 | 18 | node->software_volume_needed = 0; |
379 | 18 | strlcpy(node->name, loopdev_names[type], sizeof(node->name)); |
380 | 18 | cras_iodev_add_node(iodev, node); |
381 | 18 | cras_iodev_set_active_node(iodev, node); |
382 | | |
383 | 18 | cras_iodev_list_add(iodev); |
384 | | |
385 | 18 | return iodev; |
386 | 18 | } |
387 | | |
388 | 0 | void loopback_iodev_destroy(struct cras_iodev* iodev) { |
389 | 0 | struct loopback_iodev* loopdev = (struct loopback_iodev*)iodev; |
390 | 0 | struct byte_buffer* sbuf = loopdev->sample_buffer; |
391 | |
|
392 | 0 | cras_iodev_list_rm(iodev); |
393 | 0 | free(iodev->nodes); |
394 | 0 | cras_iodev_free_resources(iodev); |
395 | |
|
396 | 0 | byte_buffer_destroy(&sbuf); |
397 | 0 | free(loopdev); |
398 | 0 | } |