Home | History | Annotate | Download | only in driver
      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