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 
    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
    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? */
    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? */
    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
    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. */
    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
    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. */
    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
    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
    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. */
    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
    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
    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
    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
    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). */
    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 */
    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. */
    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. */
    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. */
    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
    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. */
    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
    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. */
    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. */
    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. */
    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
    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  */
    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