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
154 write_offset = cras_shm_check_write_offset(shm,
155 shm->area->write_offset[i]);
156 if (frames)
157 *frames = limit_frames - (write_offset / frame_bytes);
158
159 return cras_shm_buff_for_idx(shm, i) + write_offset;
160 }
161
162 /* Get a pointer to the current read buffer plus an offset. The offset might be
163 * in the next buffer. 'frames' is filled with the number of frames that can be
164 * copied from the returned buffer.
165 */
166 static inline
cras_shm_get_readable_frames(const struct cras_audio_shm * shm,size_t offset,size_t * frames)167 uint8_t *cras_shm_get_readable_frames(const struct cras_audio_shm *shm,
168 size_t offset,
169 size_t *frames)
170 {
171 unsigned buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
172 unsigned read_offset, write_offset, final_offset;
173
174 assert(frames != NULL);
175
176 read_offset =
177 cras_shm_check_read_offset(shm,
178 shm->area->read_offset[buf_idx]);
179 write_offset =
180 cras_shm_check_write_offset(shm,
181 shm->area->write_offset[buf_idx]);
182 final_offset = read_offset + offset * shm->config.frame_bytes;
183 if (final_offset >= write_offset) {
184 final_offset -= write_offset;
185 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
186 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
187 write_offset = cras_shm_check_write_offset(
188 shm, shm->area->write_offset[buf_idx]);
189 }
190 if (final_offset >= write_offset) {
191 /* Past end of samples. */
192 *frames = 0;
193 return NULL;
194 }
195 *frames = (write_offset - final_offset) / shm->config.frame_bytes;
196 return cras_shm_buff_for_idx(shm, buf_idx) + final_offset;
197 }
198
199 /* How many bytes are queued? */
cras_shm_get_bytes_queued(const struct cras_audio_shm * shm)200 static inline size_t cras_shm_get_bytes_queued(const struct cras_audio_shm *shm)
201 {
202 size_t total, i;
203 const unsigned used_size = shm->config.used_size;
204
205 total = 0;
206 for (i = 0; i < CRAS_NUM_SHM_BUFFERS; i++) {
207 unsigned read_offset, write_offset;
208
209 read_offset = MIN(shm->area->read_offset[i], used_size);
210 write_offset = MIN(shm->area->write_offset[i], used_size);
211
212 if (write_offset > read_offset)
213 total += write_offset - read_offset;
214 }
215 return total;
216 }
217
218 /* How many frames are queued? */
cras_shm_get_frames(const struct cras_audio_shm * shm)219 static inline int cras_shm_get_frames(const struct cras_audio_shm *shm)
220 {
221 size_t bytes;
222
223 bytes = cras_shm_get_bytes_queued(shm);
224 if (bytes % shm->config.frame_bytes != 0)
225 return -EIO;
226 return bytes / shm->config.frame_bytes;
227 }
228
229 /* How many frames in the current buffer? */
230 static inline
cras_shm_get_frames_in_curr_buffer(const struct cras_audio_shm * shm)231 size_t cras_shm_get_frames_in_curr_buffer(const struct cras_audio_shm *shm)
232 {
233 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
234 unsigned read_offset, write_offset;
235 const unsigned used_size = shm->config.used_size;
236
237 read_offset = MIN(shm->area->read_offset[buf_idx], used_size);
238 write_offset = MIN(shm->area->write_offset[buf_idx], used_size);
239
240 if (write_offset <= read_offset)
241 return 0;
242
243 return (write_offset - read_offset) / shm->config.frame_bytes;
244 }
245
246 /* Return 1 if there is an empty buffer in the list. */
cras_shm_is_buffer_available(const struct cras_audio_shm * shm)247 static inline int cras_shm_is_buffer_available(const struct cras_audio_shm *shm)
248 {
249 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
250
251 return (shm->area->write_offset[buf_idx] == 0);
252 }
253
254 /* How many are available to be written? */
255 static inline
cras_shm_get_num_writeable(const struct cras_audio_shm * shm)256 size_t cras_shm_get_num_writeable(const struct cras_audio_shm *shm)
257 {
258 /* Not allowed to write to a buffer twice. */
259 if (!cras_shm_is_buffer_available(shm))
260 return 0;
261
262 return shm->config.used_size / shm->config.frame_bytes;
263 }
264
265 /* Flags an overrun if writing would cause one and reset the write offset.
266 * Return 1 if overrun happens, otherwise return 0. */
cras_shm_check_write_overrun(struct cras_audio_shm * shm)267 static inline int cras_shm_check_write_overrun(struct cras_audio_shm *shm)
268 {
269 int ret = 0;
270 size_t write_buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
271
272 if (!shm->area->write_in_progress[write_buf_idx]) {
273 unsigned int used_size = shm->config.used_size;
274
275 if (shm->area->write_offset[write_buf_idx]) {
276 shm->area->num_overruns++; /* Will over-write unread */
277 ret = 1;
278 }
279
280 memset(cras_shm_buff_for_idx(shm, write_buf_idx), 0, used_size);
281
282 shm->area->write_in_progress[write_buf_idx] = 1;
283 shm->area->write_offset[write_buf_idx] = 0;
284 }
285 return ret;
286 }
287
288 /* Increment the write pointer for the current buffer. */
289 static inline
cras_shm_buffer_written(struct cras_audio_shm * shm,size_t frames)290 void cras_shm_buffer_written(struct cras_audio_shm *shm, size_t frames)
291 {
292 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
293
294 if (frames == 0)
295 return;
296
297 shm->area->write_offset[buf_idx] += frames * shm->config.frame_bytes;
298 shm->area->read_offset[buf_idx] = 0;
299 }
300
301 /* Returns the number of frames that have been written to the current buffer. */
302 static inline
cras_shm_frames_written(const struct cras_audio_shm * shm)303 unsigned int cras_shm_frames_written(const struct cras_audio_shm *shm)
304 {
305 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
306
307 return shm->area->write_offset[buf_idx] / shm->config.frame_bytes;
308 }
309
310 /* Signals the writing to this buffer is complete and moves to the next one. */
cras_shm_buffer_write_complete(struct cras_audio_shm * shm)311 static inline void cras_shm_buffer_write_complete(struct cras_audio_shm *shm)
312 {
313 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
314
315 shm->area->write_in_progress[buf_idx] = 0;
316
317 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
318 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
319 shm->area->write_buf_idx = buf_idx;
320 }
321
322 /* Set the write pointer for the current buffer and complete the write. */
323 static inline
cras_shm_buffer_written_start(struct cras_audio_shm * shm,size_t frames)324 void cras_shm_buffer_written_start(struct cras_audio_shm *shm, size_t frames)
325 {
326 size_t buf_idx = shm->area->write_buf_idx & CRAS_SHM_BUFFERS_MASK;
327
328 shm->area->write_offset[buf_idx] = frames * shm->config.frame_bytes;
329 shm->area->read_offset[buf_idx] = 0;
330 cras_shm_buffer_write_complete(shm);
331 }
332
333 /* Increment the read pointer. If it goes past the write pointer for this
334 * buffer, move to the next buffer. */
335 static inline
cras_shm_buffer_read(struct cras_audio_shm * shm,size_t frames)336 void cras_shm_buffer_read(struct cras_audio_shm *shm, size_t frames)
337 {
338 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
339 size_t remainder;
340 struct cras_audio_shm_area *area = shm->area;
341 struct cras_audio_shm_config *config = &shm->config;
342
343 if (frames == 0)
344 return;
345
346 area->read_offset[buf_idx] += frames * config->frame_bytes;
347 if (area->read_offset[buf_idx] >= area->write_offset[buf_idx]) {
348 remainder = area->read_offset[buf_idx] -
349 area->write_offset[buf_idx];
350 area->read_offset[buf_idx] = 0;
351 area->write_offset[buf_idx] = 0;
352 assert_on_compile_is_power_of_2(CRAS_NUM_SHM_BUFFERS);
353 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
354 if (remainder < area->write_offset[buf_idx]) {
355 area->read_offset[buf_idx] = remainder;
356 } else {
357 area->read_offset[buf_idx] = 0;
358 area->write_offset[buf_idx] = 0;
359 if (remainder) {
360 /* Read all of this buffer too. */
361 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
362 }
363 }
364 area->read_buf_idx = buf_idx;
365 }
366 }
367
368 /* Read from the current buffer. This is similar to cras_shm_buffer_read(), but
369 * it doesn't check for the case we may read from two buffers. */
370 static inline
cras_shm_buffer_read_current(struct cras_audio_shm * shm,size_t frames)371 void cras_shm_buffer_read_current(struct cras_audio_shm *shm, size_t frames)
372 {
373 size_t buf_idx = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
374 struct cras_audio_shm_area *area = shm->area;
375 struct cras_audio_shm_config *config = &shm->config;
376
377 area->read_offset[buf_idx] += frames * config->frame_bytes;
378 if (area->read_offset[buf_idx] >= area->write_offset[buf_idx]) {
379 area->read_offset[buf_idx] = 0;
380 area->write_offset[buf_idx] = 0;
381 buf_idx = (buf_idx + 1) & CRAS_SHM_BUFFERS_MASK;
382 area->read_buf_idx = buf_idx;
383 }
384 }
385
386 /* Sets the volume for the stream. The volume level is a scaling factor that
387 * will be applied to the stream before mixing. */
388 static inline
cras_shm_set_volume_scaler(struct cras_audio_shm * shm,float volume_scaler)389 void cras_shm_set_volume_scaler(struct cras_audio_shm *shm, float volume_scaler)
390 {
391 volume_scaler = MAX(volume_scaler, 0.0);
392 shm->area->volume_scaler = MIN(volume_scaler, 1.0);
393 }
394
395 /* Returns the volume of the stream(0.0-1.0). */
cras_shm_get_volume_scaler(const struct cras_audio_shm * shm)396 static inline float cras_shm_get_volume_scaler(const struct cras_audio_shm *shm)
397 {
398 return shm->area->volume_scaler;
399 }
400
401 /* Indicates that the stream should be muted/unmuted */
cras_shm_set_mute(struct cras_audio_shm * shm,size_t mute)402 static inline void cras_shm_set_mute(struct cras_audio_shm *shm, size_t mute)
403 {
404 shm->area->mute = !!mute;
405 }
406
407 /* 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)408 static inline size_t cras_shm_get_mute(const struct cras_audio_shm *shm)
409 {
410 return shm->area->mute;
411 }
412
413 /* Sets the size of a frame in bytes. */
cras_shm_set_frame_bytes(struct cras_audio_shm * shm,unsigned frame_bytes)414 static inline void cras_shm_set_frame_bytes(struct cras_audio_shm *shm,
415 unsigned frame_bytes)
416 {
417 shm->config.frame_bytes = frame_bytes;
418 if (shm->area)
419 shm->area->config.frame_bytes = frame_bytes;
420 }
421
422 /* Returns the size of a frame in bytes. */
cras_shm_frame_bytes(const struct cras_audio_shm * shm)423 static inline unsigned cras_shm_frame_bytes(const struct cras_audio_shm *shm)
424 {
425 return shm->config.frame_bytes;
426 }
427
428 /* Sets if a callback is pending with the client. */
429 static inline
cras_shm_set_callback_pending(struct cras_audio_shm * shm,int pending)430 void cras_shm_set_callback_pending(struct cras_audio_shm *shm, int pending)
431 {
432 shm->area->callback_pending = !!pending;
433 }
434
435 /* Returns non-zero if a callback is pending for this shm region. */
cras_shm_callback_pending(const struct cras_audio_shm * shm)436 static inline int cras_shm_callback_pending(const struct cras_audio_shm *shm)
437 {
438 return shm->area->callback_pending;
439 }
440
441 /* Sets the used_size of the shm region. This is the maximum number of bytes
442 * that is exchanged each time a buffer is passed from client to server.
443 */
444 static inline
cras_shm_set_used_size(struct cras_audio_shm * shm,unsigned used_size)445 void cras_shm_set_used_size(struct cras_audio_shm *shm, unsigned used_size)
446 {
447 shm->config.used_size = used_size;
448 if (shm->area)
449 shm->area->config.used_size = used_size;
450 }
451
452 /* Returns the used size of the shm region in bytes. */
cras_shm_used_size(const struct cras_audio_shm * shm)453 static inline unsigned cras_shm_used_size(const struct cras_audio_shm *shm)
454 {
455 return shm->config.used_size;
456 }
457
458 /* Returns the used size of the shm region in frames. */
cras_shm_used_frames(const struct cras_audio_shm * shm)459 static inline unsigned cras_shm_used_frames(const struct cras_audio_shm *shm)
460 {
461 return shm->config.used_size / shm->config.frame_bytes;
462 }
463
464 /* Returns the total size of the shared memory region. */
cras_shm_total_size(const struct cras_audio_shm * shm)465 static inline unsigned cras_shm_total_size(const struct cras_audio_shm *shm)
466 {
467 return cras_shm_used_size(shm) * CRAS_NUM_SHM_BUFFERS +
468 sizeof(*shm->area);
469 }
470
471 /* Gets the counter of over-runs. */
472 static inline
cras_shm_num_overruns(const struct cras_audio_shm * shm)473 unsigned cras_shm_num_overruns(const struct cras_audio_shm *shm)
474 {
475 return shm->area->num_overruns;
476 }
477
478 /* Copy the config from the shm region to the local config. Used by clients
479 * when initially setting up the region.
480 */
cras_shm_copy_shared_config(struct cras_audio_shm * shm)481 static inline void cras_shm_copy_shared_config(struct cras_audio_shm *shm)
482 {
483 memcpy(&shm->config, &shm->area->config, sizeof(shm->config));
484 }
485
486 /* Open a read/write shared memory area with the given name.
487 * Args:
488 * name - Name of the shared-memory area.
489 * size - Size of the shared-memory area.
490 * Returns:
491 * >= 0 file descriptor value, or negative errno value on error.
492 */
493 int cras_shm_open_rw (const char *name, size_t size);
494
495 /* Reopen an existing shared memory area read-only.
496 * Args:
497 * name - Name of the shared-memory area.
498 * fd - Existing file descriptor.
499 * Returns:
500 * >= 0 new file descriptor value, or negative errno value on error.
501 */
502 int cras_shm_reopen_ro (const char *name, int fd);
503
504 /* Close and delete a shared memory area.
505 * Args:
506 * name - Name of the shared-memory area.
507 * fd - Existing file descriptor.
508 * Returns:
509 * >= 0 new file descriptor value, or negative errno value on error.
510 */
511 void cras_shm_close_unlink (const char *name, int fd);
512
513 #endif /* CRAS_SHM_H_ */
514