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_caremu"
18 // #define LOG_NDEBUG 0
19 
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <log/log.h>
25 
26 #include "audio_vbuffer.h"
27 
28 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
29 
audio_vbuffer_init(audio_vbuffer_t * audio_vbuffer,size_t frame_count,size_t frame_size)30 int audio_vbuffer_init(audio_vbuffer_t *audio_vbuffer, size_t frame_count,
31                        size_t frame_size) {
32   if (!audio_vbuffer) {
33     return -EINVAL;
34   }
35   audio_vbuffer->frame_size = frame_size;
36   audio_vbuffer->frame_count = frame_count;
37   size_t bytes = frame_count * frame_size;
38   audio_vbuffer->data = calloc(bytes, 1);
39   if (!audio_vbuffer->data) {
40     return -ENOMEM;
41   }
42   audio_vbuffer->head = 0;
43   audio_vbuffer->tail = 0;
44   audio_vbuffer->live = 0;
45   pthread_mutex_init(&audio_vbuffer->lock, (const pthread_mutexattr_t *)NULL);
46   return 0;
47 }
48 
audio_vbuffer_destroy(audio_vbuffer_t * audio_vbuffer)49 int audio_vbuffer_destroy(audio_vbuffer_t *audio_vbuffer) {
50   if (!audio_vbuffer) {
51     return -EINVAL;
52   }
53   free(audio_vbuffer->data);
54   pthread_mutex_destroy(&audio_vbuffer->lock);
55   return 0;
56 }
57 
audio_vbuffer_live(audio_vbuffer_t * audio_vbuffer)58 int audio_vbuffer_live(audio_vbuffer_t *audio_vbuffer) {
59   if (!audio_vbuffer) {
60     return -EINVAL;
61   }
62   pthread_mutex_lock(&audio_vbuffer->lock);
63   int live = audio_vbuffer->live;
64   pthread_mutex_unlock(&audio_vbuffer->lock);
65   return live;
66 }
67 
audio_vbuffer_dead(audio_vbuffer_t * audio_vbuffer)68 int audio_vbuffer_dead(audio_vbuffer_t *audio_vbuffer) {
69   if (!audio_vbuffer) {
70     return -EINVAL;
71   }
72   pthread_mutex_lock(&audio_vbuffer->lock);
73   int dead = audio_vbuffer->frame_count - audio_vbuffer->live;
74   pthread_mutex_unlock(&audio_vbuffer->lock);
75   return dead;
76 }
77 
audio_vbuffer_write(audio_vbuffer_t * audio_vbuffer,const void * buffer,size_t frame_count)78 size_t audio_vbuffer_write(audio_vbuffer_t *audio_vbuffer, const void *buffer,
79                            size_t frame_count) {
80   size_t frames_written = 0;
81   pthread_mutex_lock(&audio_vbuffer->lock);
82 
83   while (frame_count != 0) {
84     int frames = 0;
85     if (audio_vbuffer->live == 0 || audio_vbuffer->head > audio_vbuffer->tail) {
86       frames =
87           MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->head);
88     } else if (audio_vbuffer->head < audio_vbuffer->tail) {
89       frames = MIN(frame_count, audio_vbuffer->tail - (audio_vbuffer->head));
90     } else {
91       ALOGV("%s audio_vbuffer is full", __func__);
92       break;
93     }
94     memcpy(
95         &audio_vbuffer->data[audio_vbuffer->head * audio_vbuffer->frame_size],
96         &((uint8_t *)buffer)[frames_written * audio_vbuffer->frame_size],
97         frames * audio_vbuffer->frame_size);
98     audio_vbuffer->live += frames;
99     frames_written += frames;
100     frame_count -= frames;
101     audio_vbuffer->head =
102         (audio_vbuffer->head + frames) % audio_vbuffer->frame_count;
103   }
104 
105   pthread_mutex_unlock(&audio_vbuffer->lock);
106   return frames_written;
107 }
108 
audio_vbuffer_read(audio_vbuffer_t * audio_vbuffer,void * buffer,size_t frame_count)109 size_t audio_vbuffer_read(audio_vbuffer_t *audio_vbuffer, void *buffer,
110                           size_t frame_count) {
111   size_t frames_read = 0;
112   pthread_mutex_lock(&audio_vbuffer->lock);
113 
114   while (frame_count != 0) {
115     int frames = 0;
116     if (audio_vbuffer->live == audio_vbuffer->frame_count ||
117         audio_vbuffer->tail > audio_vbuffer->head) {
118       frames =
119           MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->tail);
120     } else if (audio_vbuffer->tail < audio_vbuffer->head) {
121       frames = MIN(frame_count, audio_vbuffer->head - audio_vbuffer->tail);
122     } else {
123       break;
124     }
125     memcpy(
126         &((uint8_t *)buffer)[frames_read * audio_vbuffer->frame_size],
127         &audio_vbuffer->data[audio_vbuffer->tail * audio_vbuffer->frame_size],
128         frames * audio_vbuffer->frame_size);
129     audio_vbuffer->live -= frames;
130     frames_read += frames;
131     frame_count -= frames;
132     audio_vbuffer->tail =
133         (audio_vbuffer->tail + frames) % audio_vbuffer->frame_count;
134   }
135 
136   pthread_mutex_unlock(&audio_vbuffer->lock);
137   return frames_read;
138 }
139