diff options
Diffstat (limited to 'emulator/audio/driver/audio_vbuffer.c')
-rw-r--r-- | emulator/audio/driver/audio_vbuffer.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/emulator/audio/driver/audio_vbuffer.c b/emulator/audio/driver/audio_vbuffer.c new file mode 100644 index 0000000..79be545 --- /dev/null +++ b/emulator/audio/driver/audio_vbuffer.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "audio_hw_generic" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <log/log.h> + +#include "audio_vbuffer.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +int audio_vbuffer_init(audio_vbuffer_t *audio_vbuffer, size_t frame_count, + size_t frame_size) { + if (!audio_vbuffer) { + return -EINVAL; + } + audio_vbuffer->frame_size = frame_size; + audio_vbuffer->frame_count = frame_count; + size_t bytes = frame_count * frame_size; + audio_vbuffer->data = calloc(bytes, 1); + if (!audio_vbuffer->data) { + return -ENOMEM; + } + audio_vbuffer->head = 0; + audio_vbuffer->tail = 0; + audio_vbuffer->live = 0; + pthread_mutex_init(&audio_vbuffer->lock, (const pthread_mutexattr_t *)NULL); + return 0; +} + +int audio_vbuffer_destroy(audio_vbuffer_t *audio_vbuffer) { + if (!audio_vbuffer) { + return -EINVAL; + } + free(audio_vbuffer->data); + pthread_mutex_destroy(&audio_vbuffer->lock); + return 0; +} + +int audio_vbuffer_live(audio_vbuffer_t *audio_vbuffer) { + if (!audio_vbuffer) { + return -EINVAL; + } + pthread_mutex_lock(&audio_vbuffer->lock); + int live = audio_vbuffer->live; + pthread_mutex_unlock(&audio_vbuffer->lock); + return live; +} + +int audio_vbuffer_dead(audio_vbuffer_t *audio_vbuffer) { + if (!audio_vbuffer) { + return -EINVAL; + } + pthread_mutex_lock(&audio_vbuffer->lock); + int dead = audio_vbuffer->frame_count - audio_vbuffer->live; + pthread_mutex_unlock(&audio_vbuffer->lock); + return dead; +} + +size_t audio_vbuffer_write(audio_vbuffer_t *audio_vbuffer, const void *buffer, + size_t frame_count) { + size_t frames_written = 0; + pthread_mutex_lock(&audio_vbuffer->lock); + + while (frame_count != 0) { + int frames = 0; + if (audio_vbuffer->live == 0 || audio_vbuffer->head > audio_vbuffer->tail) { + frames = + MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->head); + } else if (audio_vbuffer->head < audio_vbuffer->tail) { + frames = MIN(frame_count, audio_vbuffer->tail - (audio_vbuffer->head)); + } else { + ALOGD("%s audio_vbuffer is full", __func__); + break; + } + memcpy( + &audio_vbuffer->data[audio_vbuffer->head * audio_vbuffer->frame_size], + &((uint8_t *)buffer)[frames_written * audio_vbuffer->frame_size], + frames * audio_vbuffer->frame_size); + audio_vbuffer->live += frames; + frames_written += frames; + frame_count -= frames; + audio_vbuffer->head = + (audio_vbuffer->head + frames) % audio_vbuffer->frame_count; + } + + pthread_mutex_unlock(&audio_vbuffer->lock); + return frames_written; +} + +size_t audio_vbuffer_read(audio_vbuffer_t *audio_vbuffer, void *buffer, + size_t frame_count) { + size_t frames_read = 0; + pthread_mutex_lock(&audio_vbuffer->lock); + + while (frame_count != 0) { + int frames = 0; + if (audio_vbuffer->live == audio_vbuffer->frame_count || + audio_vbuffer->tail > audio_vbuffer->head) { + frames = + MIN(frame_count, audio_vbuffer->frame_count - audio_vbuffer->tail); + } else if (audio_vbuffer->tail < audio_vbuffer->head) { + frames = MIN(frame_count, audio_vbuffer->head - audio_vbuffer->tail); + } else { + break; + } + memcpy( + &((uint8_t *)buffer)[frames_read * audio_vbuffer->frame_size], + &audio_vbuffer->data[audio_vbuffer->tail * audio_vbuffer->frame_size], + frames * audio_vbuffer->frame_size); + audio_vbuffer->live -= frames; + frames_read += frames; + frame_count -= frames; + audio_vbuffer->tail = + (audio_vbuffer->tail + frames) % audio_vbuffer->frame_count; + } + + pthread_mutex_unlock(&audio_vbuffer->lock); + return frames_read; +} |