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