• 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 
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