Home | History | Annotate | Download | only in common
      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. */
     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
     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
     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
    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
    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
    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
    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
    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? */
    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? */
    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
    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. */
    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
    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. */
    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
    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
    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. */
    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
    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
    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
    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
    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). */
    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 */
    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. */
    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. */
    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. */
    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
    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. */
    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
    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. */
    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. */
    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. */
    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
    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  */
    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