1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "audio_hw_generic" 18 19 #include <errno.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <log/log.h> 24 25 #include "audio_vbuffer.h" 26 27 #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 28 29 int audio_vbuffer_init(audio_vbuffer_t *audio_vbuffer, size_t frame_count, 30 size_t frame_size) { 31 if (!audio_vbuffer) { 32 return -EINVAL; 33 } 34 audio_vbuffer->frame_size = frame_size; 35 audio_vbuffer->frame_count = frame_count; 36 size_t bytes = frame_count * frame_size; 37 audio_vbuffer->data = calloc(bytes, 1); 38 if (!audio_vbuffer->data) { 39 return -ENOMEM; 40 } 41 audio_vbuffer->head = 0; 42 audio_vbuffer->tail = 0; 43 audio_vbuffer->live = 0; 44 pthread_mutex_init(&audio_vbuffer->lock, (const pthread_mutexattr_t *)NULL); 45 return 0; 46 } 47 48 int audio_vbuffer_destroy(audio_vbuffer_t *audio_vbuffer) { 49 if (!audio_vbuffer) { 50 return -EINVAL; 51 } 52 free(audio_vbuffer->data); 53 pthread_mutex_destroy(&audio_vbuffer->lock); 54 return 0; 55 } 56 57 int audio_vbuffer_live(audio_vbuffer_t *audio_vbuffer) { 58 if (!audio_vbuffer) { 59 return -EINVAL; 60 } 61 pthread_mutex_lock(&audio_vbuffer->lock); 62 int live = audio_vbuffer->live; 63 pthread_mutex_unlock(&audio_vbuffer->lock); 64 return live; 65 } 66 67 int audio_vbuffer_dead(audio_vbuffer_t *audio_vbuffer) { 68 if (!audio_vbuffer) { 69 return -EINVAL; 70 } 71 pthread_mutex_lock(&audio_vbuffer->lock); 72 int dead = audio_vbuffer->frame_count - audio_vbuffer->live; 73 pthread_mutex_unlock(&audio_vbuffer->lock); 74 return dead; 75 } 76 77 size_t audio_vbuffer_write(audio_vbuffer_t *audio_vbuffer, const void *buffer, 78 size_t frame_count) { 79 size_t frames_written = 0; 80 pthread_mutex_lock(&audio_vbuffer->lock); 81 82 while (frame_count != 0) { 83 int frames = 0; 84 if (audio_vbuffer->live == 0 || audio_vbuffer->head > audio_vbuffer->tail) { 85 frames = 86 MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->head); 87 } else if (audio_vbuffer->head < audio_vbuffer->tail) { 88 frames = MIN(frame_count, audio_vbuffer->tail - (audio_vbuffer->head)); 89 } else { 90 ALOGD("%s audio_vbuffer is full", __func__); 91 break; 92 } 93 memcpy( 94 &audio_vbuffer->data[audio_vbuffer->head * audio_vbuffer->frame_size], 95 &((uint8_t *)buffer)[frames_written * audio_vbuffer->frame_size], 96 frames * audio_vbuffer->frame_size); 97 audio_vbuffer->live += frames; 98 frames_written += frames; 99 frame_count -= frames; 100 audio_vbuffer->head = 101 (audio_vbuffer->head + frames) % audio_vbuffer->frame_count; 102 } 103 104 pthread_mutex_unlock(&audio_vbuffer->lock); 105 return frames_written; 106 } 107 108 size_t audio_vbuffer_read(audio_vbuffer_t *audio_vbuffer, void *buffer, 109 size_t frame_count) { 110 size_t frames_read = 0; 111 pthread_mutex_lock(&audio_vbuffer->lock); 112 113 while (frame_count != 0) { 114 int frames = 0; 115 if (audio_vbuffer->live == audio_vbuffer->frame_count || 116 audio_vbuffer->tail > audio_vbuffer->head) { 117 frames = 118 MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->tail); 119 } else if (audio_vbuffer->tail < audio_vbuffer->head) { 120 frames = MIN(frame_count, audio_vbuffer->head - audio_vbuffer->tail); 121 } else { 122 break; 123 } 124 memcpy( 125 &((uint8_t *)buffer)[frames_read * audio_vbuffer->frame_size], 126 &audio_vbuffer->data[audio_vbuffer->tail * audio_vbuffer->frame_size], 127 frames * audio_vbuffer->frame_size); 128 audio_vbuffer->live -= frames; 129 frames_read += frames; 130 frame_count -= frames; 131 audio_vbuffer->tail = 132 (audio_vbuffer->tail + frames) % audio_vbuffer->frame_count; 133 } 134 135 pthread_mutex_unlock(&audio_vbuffer->lock); 136 return frames_read; 137 } 138