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