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