From fc91e00f0a533419695084ae08cc2217c5711a3b Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Tue, 10 Apr 2018 14:14:32 -0700 Subject: Simulates hardware gain control in audio driver Change log - audio_vbuffer in its own source and header files - a pcm is shared via ext_pcm by multiple audio streams Known issue - Audio is distorted if multiple audio streams try to play simultaneously. This is due to lack of proper audio mixing and will be fixed in a future CL Bug: 79496296 Test: manually Change-Id: I14392e13ae49131a044efdda97ea23946287ad97 --- emulator/audio/driver/audio_vbuffer.c | 137 ++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 emulator/audio/driver/audio_vbuffer.c (limited to 'emulator/audio/driver/audio_vbuffer.c') 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 +#include +#include + +#include + +#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; +} -- cgit v1.2.3