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
audio_vbuffer_init(audio_vbuffer_t * audio_vbuffer,size_t frame_count,size_t frame_size)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
audio_vbuffer_destroy(audio_vbuffer_t * audio_vbuffer)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
audio_vbuffer_live(audio_vbuffer_t * audio_vbuffer)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
audio_vbuffer_dead(audio_vbuffer_t * audio_vbuffer)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
audio_vbuffer_write(audio_vbuffer_t * audio_vbuffer,const void * buffer,size_t frame_count)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
audio_vbuffer_read(audio_vbuffer_t * audio_vbuffer,void * buffer,size_t frame_count)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