1 /* Copyright (c) 2012 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 #ifndef CRAS_SHM_H_
7 #define CRAS_SHM_H_
8
9 #include <assert.h>
10 #include <stdint.h>
11 #include <sys/param.h>
12
13 #include "cras_types.h"
14 #include "cras_util.h"
15
16 #define CRAS_NUM_SHM_BUFFERS 2U /* double buffer */
17 #define CRAS_SHM_BUFFERS_MASK (CRAS_NUM_SHM_BUFFERS - 1)
18
19 /* Configuration of the shm area.
20 *
21 * used_size - The size in bytes of the sample area being actively used.
22 * frame_bytes - The size of each frame in bytes.
23 */
24 struct __attribute__ ((__packed__)) cras_audio_shm_config {
25 uint32_t used_size;
26 uint32_t frame_bytes;
27 };
28
29 /* Structure that is shared as shm between client and server.
30 *
31 * config - Size config data. A copy of the config shared with clients.
32 * read_buf_idx - index of the current buffer to read from (0 or 1 if double
33 * buffered).
34 * write_buf_idx - index of the current buffer to write to (0 or 1 if double
35 * buffered).
36 * read_offset - offset of the next sample to read (one per buffer).
37 * write_offset - offset of the next sample to write (one per buffer).
38 * write_in_progress - non-zero when a write is in progress.
39 * volume_scaler - volume scaling factor (0.0-1.0).
40 * muted - bool, true if stream should be muted.
41 * num_overruns - Starting at 0 this is incremented very time data is over
42 * written because too much accumulated before a read.
43 * ts - For capture, the time stamp of the next sample at read_index. For
44 * playback, this is the time that the next sample written will be played.
45 * This is only valid in audio callbacks.
46 * samples - Audio data - a double buffered area that is used to exchange
47 * audio samples.
48 */
49 struct __attribute__ ((__packed__)) cras_audio_shm_area {
50 struct cras_audio_shm_config config;
51 uint32_t read_buf_idx; /* use buffer A or B */
52 uint32_t write_buf_idx;
53 uint32_t read_offset[CRAS_NUM_SHM_BUFFERS];
54 uint32_t write_offset[CRAS_NUM_SHM_BUFFERS];
55 int32_t write_in_progress[CRAS_NUM_SHM_BUFFERS];
56 float volume_scaler;
57 int32_t mute;
58 int32_t callback_pending;
59 uint32_t num_overruns;
60 struct cras_timespec ts;
61 uint8_t samples[];
62 };
63
64 /* Structure that holds the config for and a pointer to the audio shm area.
65 *
66 * config - Size config data, kept separate so it can be checked.
67 * area - Acutal shm region that is shared.
68 */
69 struct cras_audio_shm {
70 struct cras_audio_shm_config config;
71 struct cras_audio_shm_area *area;
72 };
73
74 /* Get a pointer to the buffer at idx. */
cras_shm_buff_for_idx(const struct cras_audio_shm * shm,size_t idx)75 static inline uint8_t *cras_shm_buff_for_idx(const struct cras_audio_shm *shm,
76 size_t idx)
77 {
78 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
79 idx = idx & CRAS_SHM_BUFFERS_MASK;
80 return shm->area->samples + shm->config.used_size * idx;
81 }
82
83 /* Limit a read offset to within the buffer size. */
84 static inline
cras_shm_check_read_offset(const struct cras_audio_shm * shm,unsigned offset)85 unsigned cras_shm_check_read_offset(const struct cras_audio_shm *shm,
86 unsigned offset)
87 {
88 /* The offset is allowed to be the total size, indicating that the
89 * buffer is full. If read pointer is invalid assume it is at the
90 * beginning. */
91 if (offset > shm->config.used_size)
92 return 0;
93 return offset;
94 }
95
96 /* Limit a write offset to within the buffer size. */
97 static inline
cras_shm_check_write_offset(const struct cras_audio_shm * shm,unsigned offset)98 unsigned cras_shm_check_write_offset(const struct cras_audio_shm *shm,
99 unsigned offset)
100 {
101 /* The offset is allowed to be the total size, indicating that the
102 * buffer is full. If write pointer is invalid assume it is at the
103 * end. */
104 if (offset > shm->config.used_size)
105 return shm->config.used_size;
106 return offset;
107 }
108
109 /* Get the number of frames readable in current read buffer */
110 static inline
cras_shm_get_curr_read_frames(const struct cras_audio_shm * shm)111 unsigned cras_shm_get_curr_read_frames(const struct cras_audio_shm *shm)
112 {
113 unsigned i = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
114 unsigned read_offset, write_offset;
115
116 read_offset =
117 cras_shm_check_read_offset(shm, shm->area->read_offset[i]);
118 write_offset =
119 cras_shm_check_write_offset(shm, shm->area->write_offset[i]);
120
121 if (read_offset > write_offset)
122 return 0;
123 else
124 return (write_offset - read_offset) / shm->config.frame_bytes;
125 }
126
127 /* Get the base of the current read buffer. */
128 static inline
cras_shm_get_read_buffer_base(const struct cras_audio_shm * shm)129 uint8_t *cras_shm_get_read_buffer_base(const struct cras_audio_shm *shm)
130 {
131 unsigned i = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
132 return cras_shm_buff_for_idx(shm, i);
133 }
134
135 /* Get the base of the current write buffer. */
136 static inline
cras_shm_get_write_buffer_base(const struct cras_audio_shm * shm)137 uint8_t *cras_shm_get_write_buffer_base(const struct cras_audio_shm *shm)
138 {
139 unsigned i = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
140
141 return cras_shm_buff_for_idx(shm, i);
142 }
143
144 /* Get a pointer to the next buffer to write */
145 static inline
cras_shm_get_writeable_frames(const struct cras_audio_shm * shm,unsigned limit_frames,unsigned * frames)146 uint8_t *cras_shm_get_writeable_frames(const struct cras_audio_shm *shm,
147 unsigned limit_frames,
148 unsigned *frames)
149 {
150 unsigned i = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
151 unsigned write_offset;
152 const unsigned frame_bytes = shm->config.frame_bytes;
153 unsigned written;
154
155 write_offset = cras_shm_check_write_offset(shm,
156 shm->area->write_offset[i]);
157 written = write_offset / frame_bytes;
158 if (frames) {
159 if (limit_frames >= written)
160 *frames = limit_frames - written;
161 else
162 *frames = 0;
163 }
164
165 return cras_shm_buff_for_idx(shm, i) + write_offset;
166 }
167
168 /* Get a pointer to the current read buffer plus an offset. The offset might be
169 * in the next buffer. 'frames' is filled with the number of frames that can be
170 * copied from the returned buffer.
171 */
172 static inline
cras_shm_get_readable_frames(const struct cras_audio_shm * shm,size_t offset,size_t * frames)173 uint8_t *cras_shm_get_readable_frames(const struct cras_audio_shm *shm,
174 size_t offset,
175 size_t *frames)
176 {
177 unsigned buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
178 unsigned read_offset, write_offset, final_offset;
179
180 assert(frames != NULL);
181
182 read_offset =
183 cras_shm_check_read_offset(shm,
184 shm->area->read_offset[buf_idx]);
185 write_offset =
186 cras_shm_check_write_offset(shm,
187 shm->area->write_offset[buf_idx]);
188 final_offset = read_offset + offset * shm->config.frame_bytes;
189 if (final_offset >= write_offset) {
190 final_offset -= write_offset;
191 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
192 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
193 write_offset = cras_shm_check_write_offset(
194 shm, shm->area->write_offset[buf_idx]);
195 }
196 if (final_offset >= write_offset) {
197 /* Past end of samples. */
198 *frames = 0;
199 return NULL;
200 }
201 *frames = (write_offset - final_offset) / shm->config.frame_bytes;
202 return cras_shm_buff_for_idx(shm, buf_idx) + final_offset;
203 }
204
205 /* How many bytes are queued? */
cras_shm_get_bytes_queued(const struct cras_audio_shm * shm)206 static inline size_t cras_shm_get_bytes_queued(const struct cras_audio_shm *shm)
207 {
208 size_t total, i;
209 const unsigned used_size = shm->config.used_size;
210
211 total = 0;
212 for (i = 0; i < CRAS_NUM_SHM_BUFFERS; i++) {
213 unsigned read_offset, write_offset;
214
215 read_offset = MIN(shm->area->read_offset[i], used_size);
216 write_offset = MIN(shm->area->write_offset[i], used_size);
217
218 if (write_offset > read_offset)
219 total += write_offset - read_offset;
220 }
221 return total;
222 }
223
224 /* How many frames are queued? */
cras_shm_get_frames(const struct cras_audio_shm * shm)225 static inline int cras_shm_get_frames(const struct cras_audio_shm *shm)
226 {
227 size_t bytes;
228
229 bytes = cras_shm_get_bytes_queued(shm);
230 if (bytes % shm->config.frame_bytes != 0)
231 return -EIO;
232 return bytes / shm->config.frame_bytes;
233 }
234
235 /* How many frames in the current buffer? */
236 static inline
cras_shm_get_frames_in_curr_buffer(const struct cras_audio_shm * shm)237 size_t cras_shm_get_frames_in_curr_buffer(const struct cras_audio_shm *shm)
238 {
239 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
240 unsigned read_offset, write_offset;
241 const unsigned used_size = shm->config.used_size;
242
243 read_offset = MIN(shm->area->read_offset[buf_idx], used_size);
244 write_offset = MIN(shm->area->write_offset[buf_idx], used_size);
245
246 if (write_offset <= read_offset)
247 return 0;
248
249 return (write_offset - read_offset) / shm->config.frame_bytes;
250 }
251
252 /* Return 1 if there is an empty buffer in the list. */
cras_shm_is_buffer_available(const struct cras_audio_shm * shm)253 static inline int cras_shm_is_buffer_available(const struct cras_audio_shm *shm)
254 {
255 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
256
257 return (shm->area->write_offset[buf_idx] == 0);
258 }
259
260 /* How many are available to be written? */
261 static inline
cras_shm_get_num_writeable(const struct cras_audio_shm * shm)262 size_t cras_shm_get_num_writeable(const struct cras_audio_shm *shm)
263 {
264 /* Not allowed to write to a buffer twice. */
265 if (!cras_shm_is_buffer_available(shm))
266 return 0;
267
268 return shm->config.used_size / shm->config.frame_bytes;
269 }
270
271 /* Flags an overrun if writing would cause one and reset the write offset.
272 * Return 1 if overrun happens, otherwise return 0. */
cras_shm_check_write_overrun(struct cras_audio_shm * shm)273 static inline int cras_shm_check_write_overrun(struct cras_audio_shm *shm)
274 {
275 int ret = 0;
276 size_t write_buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
277
278 if (!shm->area->write_in_progress[write_buf_idx]) {
279 unsigned int used_size = shm->config.used_size;
280
281 if (shm->area->write_offset[write_buf_idx]) {
282 shm->area->num_overruns++; /* Will over-write unread */
283 ret = 1;
284 }
285
286 memset(cras_shm_buff_for_idx(shm, write_buf_idx), 0, used_size);
287
288 shm->area->write_in_progress[write_buf_idx] = 1;
289 shm->area->write_offset[write_buf_idx] = 0;
290 }
291 return ret;
292 }
293
294 /* Increment the write pointer for the current buffer. */
295 static inline
cras_shm_buffer_written(struct cras_audio_shm * shm,size_t frames)296 void cras_shm_buffer_written(struct cras_audio_shm *shm, size_t frames)
297 {
298 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
299
300 if (frames == 0)
301 return;
302
303 shm->area->write_offset[buf_idx] += frames * shm->config.frame_bytes;
304 shm->area->read_offset[buf_idx] = 0;
305 }
306
307 /* Returns the number of frames that have been written to the current buffer. */
308 static inline
cras_shm_frames_written(const struct cras_audio_shm * shm)309 unsigned int cras_shm_frames_written(const struct cras_audio_shm *shm)
310 {
311 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
312
313 return shm->area->write_offset[buf_idx] / shm->config.frame_bytes;
314 }
315
316 /* Signals the writing to this buffer is complete and moves to the next one. */
cras_shm_buffer_write_complete(struct cras_audio_shm * shm)317 static inline void cras_shm_buffer_write_complete(struct cras_audio_shm *shm)
318 {
319 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
320
321 shm->area->write_in_progress[buf_idx] = 0;
322
323 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
324 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
325 shm->area->write_buf_idx = buf_idx;
326 }
327
328 /* Set the write pointer for the current buffer and complete the write. */
329 static inline
cras_shm_buffer_written_start(struct cras_audio_shm * shm,size_t frames)330 void cras_shm_buffer_written_start(struct cras_audio_shm *shm, size_t frames)
331 {
332 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
333
334 shm->area->write_offset[buf_idx] = frames * shm->config.frame_bytes;
335 shm->area->read_offset[buf_idx] = 0;
336 cras_shm_buffer_write_complete(shm);
337 }
338
339 /* Increment the read pointer. If it goes past the write pointer for this
340 * buffer, move to the next buffer. */
341 static inline
cras_shm_buffer_read(struct cras_audio_shm * shm,size_t frames)342 void cras_shm_buffer_read(struct cras_audio_shm *shm, size_t frames)
343 {
344 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
345 size_t remainder;
346 struct cras_audio_shm_area *area = shm->area;
347 struct cras_audio_shm_config *config = &shm->config;
348
349 if (frames == 0)
350 return;
351
352 area->read_offset[buf_idx] += frames * config->frame_bytes;
353 if (area->read_offset[buf_idx] >= area->write_offset[buf_idx]) {
354 remainder = area->read_offset[buf_idx] -
355 area->write_offset[buf_idx];
356 area->read_offset[buf_idx] = 0;
357 area->write_offset[buf_idx] = 0;
358 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
359 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
360 if (remainder < area->write_offset[buf_idx]) {
361 area->read_offset[buf_idx] = remainder;
362 } else if (remainder) {
363 /* Read all of this buffer too. */
364 area->write_offset[buf_idx] = 0;
365 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
366 }
367 area->read_buf_idx = buf_idx;
368 }
369 }
370
371 /* Read from the current buffer. This is similar to cras_shm_buffer_read(), but
372 * it doesn't check for the case we may read from two buffers. */
373 static inline
cras_shm_buffer_read_current(struct cras_audio_shm * shm,size_t frames)374 void cras_shm_buffer_read_current(struct cras_audio_shm *shm, size_t frames)
375 {
376 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
377 struct cras_audio_shm_area *area = shm->area;
378 struct cras_audio_shm_config *config = &shm->config;
379
380 area->read_offset[buf_idx] += frames * config->frame_bytes;
381 if (area->read_offset[buf_idx] >= area->write_offset[buf_idx]) {
382 area->read_offset[buf_idx] = 0;
383 area->write_offset[buf_idx] = 0;
384 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
385 area->read_buf_idx = buf_idx;
386 }
387 }
388
389 /* Sets the volume for the stream. The volume level is a scaling factor that
390 * will be applied to the stream before mixing. */
391 static inline
cras_shm_set_volume_scaler(struct cras_audio_shm * shm,float volume_scaler)392 void cras_shm_set_volume_scaler(struct cras_audio_shm *shm, float volume_scaler)
393 {
394 volume_scaler = MAX(volume_scaler, 0.0);
395 shm->area->volume_scaler = MIN(volume_scaler, 1.0);
396 }
397
398 /* Returns the volume of the stream(0.0-1.0). */
cras_shm_get_volume_scaler(const struct cras_audio_shm * shm)399 static inline float cras_shm_get_volume_scaler(const struct cras_audio_shm *shm)
400 {
401 return shm->area->volume_scaler;
402 }
403
404 /* Indicates that the stream should be muted/unmuted */
cras_shm_set_mute(struct cras_audio_shm * shm,size_t mute)405 static inline void cras_shm_set_mute(struct cras_audio_shm *shm, size_t mute)
406 {
407 shm->area->mute = !!mute;
408 }
409
410 /* Returns the mute state of the stream. 0 if not muted, non-zero if muted. */
cras_shm_get_mute(const struct cras_audio_shm * shm)411 static inline size_t cras_shm_get_mute(const struct cras_audio_shm *shm)
412 {
413 return shm->area->mute;
414 }
415
416 /* Sets the size of a frame in bytes. */
cras_shm_set_frame_bytes(struct cras_audio_shm * shm,unsigned frame_bytes)417 static inline void cras_shm_set_frame_bytes(struct cras_audio_shm *shm,
418 unsigned frame_bytes)
419 {
420 shm->config.frame_bytes = frame_bytes;
421 if (shm->area)
422 shm->area->config.frame_bytes = frame_bytes;
423 }
424
425 /* Returns the size of a frame in bytes. */
cras_shm_frame_bytes(const struct cras_audio_shm * shm)426 static inline unsigned cras_shm_frame_bytes(const struct cras_audio_shm *shm)
427 {
428 return shm->config.frame_bytes;
429 }
430
431 /* Sets if a callback is pending with the client. */
432 static inline
cras_shm_set_callback_pending(struct cras_audio_shm * shm,int pending)433 void cras_shm_set_callback_pending(struct cras_audio_shm *shm, int pending)
434 {
435 shm->area->callback_pending = !!pending;
436 }
437
438 /* Returns non-zero if a callback is pending for this shm region. */
cras_shm_callback_pending(const struct cras_audio_shm * shm)439 static inline int cras_shm_callback_pending(const struct cras_audio_shm *shm)
440 {
441 return shm->area->callback_pending;
442 }
443
444 /* Sets the used_size of the shm region. This is the maximum number of bytes
445 * that is exchanged each time a buffer is passed from client to server.
446 */
447 static inline
cras_shm_set_used_size(struct cras_audio_shm * shm,unsigned used_size)448 void cras_shm_set_used_size(struct cras_audio_shm *shm, unsigned used_size)
449 {
450 shm->config.used_size = used_size;
451 if (shm->area)
452 shm->area->config.used_size = used_size;
453 }
454
455 /* Returns the used size of the shm region in bytes. */
cras_shm_used_size(const struct cras_audio_shm * shm)456 static inline unsigned cras_shm_used_size(const struct cras_audio_shm *shm)
457 {
458 return shm->config.used_size;
459 }
460
461 /* Returns the used size of the shm region in frames. */
cras_shm_used_frames(const struct cras_audio_shm * shm)462 static inline unsigned cras_shm_used_frames(const struct cras_audio_shm *shm)
463 {
464 return shm->config.used_size / shm->config.frame_bytes;
465 }
466
467 /* Returns the total size of the shared memory region. */
cras_shm_total_size(const struct cras_audio_shm * shm)468 static inline unsigned cras_shm_total_size(const struct cras_audio_shm *shm)
469 {
470 return cras_shm_used_size(shm) * CRAS_NUM_SHM_BUFFERS +
471 sizeof(*shm->area);
472 }
473
474 /* Gets the counter of over-runs. */
475 static inline
cras_shm_num_overruns(const struct cras_audio_shm * shm)476 unsigned cras_shm_num_overruns(const struct cras_audio_shm *shm)
477 {
478 return shm->area->num_overruns;
479 }
480
481 /* Copy the config from the shm region to the local config. Used by clients
482 * when initially setting up the region.
483 */
cras_shm_copy_shared_config(struct cras_audio_shm * shm)484 static inline void cras_shm_copy_shared_config(struct cras_audio_shm *shm)
485 {
486 memcpy(&shm->config, &shm->area->config, sizeof(shm->config));
487 }
488
489 /* Open a read/write shared memory area with the given name.
490 * Args:
491 * name - Name of the shared-memory area.
492 * size - Size of the shared-memory area.
493 * Returns:
494 * >= 0 file descriptor value, or negative errno value on error.
495 */
496 int cras_shm_open_rw (const char *name, size_t size);
497
498 /* Reopen an existing shared memory area read-only.
499 * Args:
500 * name - Name of the shared-memory area.
501 * fd - Existing file descriptor.
502 * Returns:
503 * >= 0 new file descriptor value, or negative errno value on error.
504 */
505 int cras_shm_reopen_ro (const char *name, int fd);
506
507 /* Close and delete a shared memory area.
508 * Args:
509 * name - Name of the shared-memory area.
510 * fd - Existing file descriptor.
511 * Returns:
512 * >= 0 new file descriptor value, or negative errno value on error.
513 */
514 void cras_shm_close_unlink (const char *name, int fd);
515
516 /*
517 * Configure shared memory for the system state.
518 * Args:
519 * name - Name of the shared-memory area.
520 * mmap_size - Amount of shared memor to map.
521 * rw_fd_out - Filled with the RW fd for the shm region.
522 * ro_fd_out - Filled with the RO fd for the shm region.
523 * Returns a pointer to the new shared memory region. Or NULL on error.
524 */
525 void *cras_shm_setup(const char *name,
526 size_t mmap_size,
527 int *rw_fd_out,
528 int *ro_fd_out);
529
530 #ifdef CRAS_SELINUX
531 /*
532 * Wrapper around selinux_restorecon(). This is helpful in unit tests because
533 * we can mock out the selinux_restorecon() behaviour there. That is required
534 * because selinux_restorecon() would fail in the unit tests, since there
535 * is no file_contexts file.
536 * Args:
537 * pathname - Name of the file on which to run restorecon
538 * Returns 0 on success, otherwise -1 and errno is set appropriately.
539 */
540 int cras_selinux_restorecon(const char *pathname);
541 #endif
542
543 #endif /* CRAS_SHM_H_ */
544