Coverage Report

Created: 2026-11-12 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}