• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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