diff options
author | Joonas Kylmälä <joonas.kylmala@iki.fi> | 2020-07-07 18:37:17 -0400 |
---|---|---|
committer | Joonas Kylmälä <joonas.kylmala@iki.fi> | 2020-07-07 18:37:17 -0400 |
commit | 44661915484c0d423cbc80cce00852e5c4e57896 (patch) | |
tree | b728f2b1583e3c547f7834139b22b4a2e6681fcf /audio/audio_hw.c | |
parent | f8613997d92d4d200eaaf4859062f3f9bea7b138 (diff) | |
download | device_samsung_midas-common-44661915484c0d423cbc80cce00852e5c4e57896.tar.gz device_samsung_midas-common-44661915484c0d423cbc80cce00852e5c4e57896.tar.bz2 device_samsung_midas-common-44661915484c0d423cbc80cce00852e5c4e57896.zip |
Delete unused audio module
Signed-off-by: Joonas Kylmälä <joonas.kylmala@iki.fi>
Diffstat (limited to 'audio/audio_hw.c')
-rw-r--r-- | audio/audio_hw.c | 1674 |
1 files changed, 0 insertions, 1674 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c deleted file mode 100644 index 62a2daa..0000000 --- a/audio/audio_hw.c +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * Copyright (C) 2012 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 <assert.h> -#include <errno.h> -#include <inttypes.h> -#include <pthread.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/time.h> -#include <dlfcn.h> -#include <fcntl.h> -#include <unistd.h> - -#include <log/log.h> -#include <cutils/str_parms.h> - -#include <hardware/hardware.h> -#include <system/audio.h> -#include <hardware/audio.h> -#include <tinyalsa/asoundlib.h> - -#define PCM_CARD 0 -#define PCM_DEVICE 0 - - -#define OUT_PERIOD_MS 15 -#define OUT_PERIOD_COUNT 4 - -#define IN_PERIOD_MS 15 -#define IN_PERIOD_COUNT 4 - -struct generic_audio_device { - struct audio_hw_device device; // Constant after init - pthread_mutex_t lock; - bool mic_mute; // Proteced by this->lock - struct mixer* mixer; // Proteced by this->lock -}; - -/* If not NULL, this is a pointer to the fallback module. - * This really is the original default audio device /dev/eac which we will use - * if no alsa devices are detected. - */ -static struct audio_module* sFallback; -static pthread_once_t sFallbackOnce = PTHREAD_ONCE_INIT; -static void fallback_init(void); -static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state); -static int adev_get_microphones(const audio_hw_device_t *dev, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count); - - -typedef struct audio_vbuffer { - pthread_mutex_t lock; - uint8_t * data; - size_t frame_size; - size_t frame_count; - size_t head; - size_t tail; - size_t live; -} audio_vbuffer_t; - -static 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; -} - -static 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; -} - -static 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; -} - -#define MIN(a,b) (((a)<(b))?(a):(b)) -static 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 { - // Full - 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; -} - -static 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; -} - -struct generic_stream_out { - struct audio_stream_out stream; // Constant after init - pthread_mutex_t lock; - struct generic_audio_device *dev; // Constant after init - audio_devices_t device; // Protected by this->lock - struct audio_config req_config; // Constant after init - struct pcm_config pcm_config; // Constant after init - audio_vbuffer_t buffer; // Constant after init - - // Time & Position Keeping - bool standby; // Protected by this->lock - uint64_t underrun_position; // Protected by this->lock - struct timespec underrun_time; // Protected by this->lock - uint64_t last_write_time_us; // Protected by this->lock - uint64_t frames_total_buffered; // Protected by this->lock - uint64_t frames_written; // Protected by this->lock - uint64_t frames_rendered; // Protected by this->lock - - // Worker - pthread_t worker_thread; // Constant after init - pthread_cond_t worker_wake; // Protected by this->lock - bool worker_standby; // Protected by this->lock - bool worker_exit; // Protected by this->lock -}; - -struct generic_stream_in { - struct audio_stream_in stream; // Constant after init - pthread_mutex_t lock; - struct generic_audio_device *dev; // Constant after init - audio_devices_t device; // Protected by this->lock - struct audio_config req_config; // Constant after init - struct pcm *pcm; // Protected by this->lock - struct pcm_config pcm_config; // Constant after init - int16_t *stereo_to_mono_buf; // Protected by this->lock - size_t stereo_to_mono_buf_size; // Protected by this->lock - audio_vbuffer_t buffer; // Protected by this->lock - - // Time & Position Keeping - bool standby; // Protected by this->lock - int64_t standby_position; // Protected by this->lock - struct timespec standby_exit_time;// Protected by this->lock - int64_t standby_frames_read; // Protected by this->lock - - // Worker - pthread_t worker_thread; // Constant after init - pthread_cond_t worker_wake; // Protected by this->lock - bool worker_standby; // Protected by this->lock - bool worker_exit; // Protected by this->lock -}; - -static struct pcm_config pcm_config_out = { - .channels = 2, - .rate = 0, - .period_size = 0, - .period_count = OUT_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, -}; - -static struct pcm_config pcm_config_in = { - .channels = 2, - .rate = 0, - .period_size = 0, - .period_count = IN_PERIOD_COUNT, - .format = PCM_FORMAT_S16_LE, - .start_threshold = 0, - .stop_threshold = INT_MAX, -}; - -static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER; -static unsigned int audio_device_ref_count = 0; - -static uint32_t out_get_sample_rate(const struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return out->req_config.sample_rate; -} - -static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static size_t out_get_buffer_size(const struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - int size = out->pcm_config.period_size * - audio_stream_out_frame_size(&out->stream); - - return size; -} - -static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return out->req_config.channel_mask; -} - -static audio_format_t out_get_format(const struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - - return out->req_config.format; -} - -static int out_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int out_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - dprintf(fd, "\tout_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %zu\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice: %08x\n" - "\t\taudio dev: %p\n\n", - out_get_sample_rate(stream), - out_get_buffer_size(stream), - out_get_channels(stream), - out_get_format(stream), - out->device, - out->dev); - pthread_mutex_unlock(&out->lock); - return 0; -} - -static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct str_parms *parms; - char value[32]; - int ret = -ENOSYS; - int success; - long val; - char *end; - - if (kvpairs == NULL || kvpairs[0] == 0) { - return 0; - } - pthread_mutex_lock(&out->lock); - if (out->standby) { - parms = str_parms_create_str(kvpairs); - success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (success >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) { - out->device = (int)val; - ret = 0; - } - } - - // NO op for AUDIO_PARAMETER_DEVICE_CONNECT and AUDIO_PARAMETER_DEVICE_DISCONNECT - success = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, - value, sizeof(value)); - if (success >= 0) { - ret = 0; - } - success = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, - value, sizeof(value)); - if (success >= 0) { - ret = 0; - } - - if (ret != 0) { - ALOGD("%s Unsupported parameter %s", __FUNCTION__, kvpairs); - } - - str_parms_destroy(parms); - } - pthread_mutex_unlock(&out->lock); - return ret; -} - -static char * out_get_parameters(const struct audio_stream *stream, const char *keys) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str = NULL; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - bool get = false; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - pthread_mutex_lock(&out->lock); - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, out->device); - pthread_mutex_unlock(&out->lock); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_FORMAT, value); - get = true; - } - - if (get) { - str = strdup(str_parms_to_str(reply)); - } - else { - ALOGD("%s Unsupported paramter: %s", __FUNCTION__, keys); - } - - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} - -static uint32_t out_get_latency(const struct audio_stream_out *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return (out->pcm_config.period_size * 1000) / out->pcm_config.rate; -} - -static int out_set_volume(struct audio_stream_out *stream, float left, - float right) -{ - return -ENOSYS; -} - -static void *out_write_worker(void * args) -{ - struct generic_stream_out *out = (struct generic_stream_out *)args; - struct pcm *pcm = NULL; - uint8_t *buffer = NULL; - int buffer_frames; - int buffer_size; - bool restart = false; - bool shutdown = false; - while (true) { - pthread_mutex_lock(&out->lock); - while (out->worker_standby || restart) { - restart = false; - if (pcm) { - pcm_close(pcm); // Frees pcm - pcm = NULL; - free(buffer); - buffer=NULL; - } - if (out->worker_exit) { - break; - } - pthread_cond_wait(&out->worker_wake, &out->lock); - } - - if (out->worker_exit) { - if (!out->worker_standby) { - ALOGE("Out worker not in standby before exiting"); - } - shutdown = true; - } - - while (!shutdown && audio_vbuffer_live(&out->buffer) == 0) { - pthread_cond_wait(&out->worker_wake, &out->lock); - } - - if (shutdown) { - pthread_mutex_unlock(&out->lock); - break; - } - - if (!pcm) { - pcm = pcm_open(PCM_CARD, PCM_DEVICE, - PCM_OUT | PCM_MONOTONIC, &out->pcm_config); - if (!pcm_is_ready(pcm)) { - ALOGE("pcm_open(out) failed: %s: channels %d format %d rate %d", - pcm_get_error(pcm), - out->pcm_config.channels, - out->pcm_config.format, - out->pcm_config.rate - ); - pthread_mutex_unlock(&out->lock); - break; - } - buffer_frames = out->pcm_config.period_size; - buffer_size = pcm_frames_to_bytes(pcm, buffer_frames); - buffer = malloc(buffer_size); - if (!buffer) { - ALOGE("could not allocate write buffer"); - pthread_mutex_unlock(&out->lock); - break; - } - } - int frames = audio_vbuffer_read(&out->buffer, buffer, buffer_frames); - pthread_mutex_unlock(&out->lock); - int ret = pcm_write(pcm, buffer, pcm_frames_to_bytes(pcm, frames)); - if (ret != 0) { - ALOGE("pcm_write failed %s", pcm_get_error(pcm)); - restart = true; - } - } - if (buffer) { - free(buffer); - } - - return NULL; -} - -// Call with in->lock held -static void get_current_output_position(struct generic_stream_out *out, - uint64_t * position, - struct timespec * timestamp) { - struct timespec curtime = { .tv_sec = 0, .tv_nsec = 0 }; - clock_gettime(CLOCK_MONOTONIC, &curtime); - const int64_t now_us = (curtime.tv_sec * 1000000000LL + curtime.tv_nsec) / 1000; - if (timestamp) { - *timestamp = curtime; - } - int64_t position_since_underrun; - if (out->standby) { - position_since_underrun = 0; - } else { - const int64_t first_us = (out->underrun_time.tv_sec * 1000000000LL + - out->underrun_time.tv_nsec) / 1000; - position_since_underrun = (now_us - first_us) * - out_get_sample_rate(&out->stream.common) / - 1000000; - if (position_since_underrun < 0) { - position_since_underrun = 0; - } - } - *position = out->underrun_position + position_since_underrun; - - // The device will reuse the same output stream leading to periods of - // underrun. - if (*position > out->frames_written) { - ALOGW("Not supplying enough data to HAL, expected position %" PRIu64 " , only wrote " - "%" PRIu64, - *position, out->frames_written); - - *position = out->frames_written; - out->underrun_position = *position; - out->underrun_time = curtime; - out->frames_total_buffered = 0; - } -} - - -static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, - size_t bytes) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - const size_t frames = bytes / audio_stream_out_frame_size(stream); - - pthread_mutex_lock(&out->lock); - - if (out->worker_standby) { - out->worker_standby = false; - } - - uint64_t current_position; - struct timespec current_time; - - get_current_output_position(out, ¤t_position, ¤t_time); - const uint64_t now_us = (current_time.tv_sec * 1000000000LL + - current_time.tv_nsec) / 1000; - if (out->standby) { - out->standby = false; - out->underrun_time = current_time; - out->frames_rendered = 0; - out->frames_total_buffered = 0; - } - - size_t frames_written = audio_vbuffer_write(&out->buffer, buffer, frames); - pthread_cond_signal(&out->worker_wake); - - /* Implementation just consumes bytes if we start getting backed up */ - out->frames_written += frames; - out->frames_rendered += frames; - out->frames_total_buffered += frames; - - // We simulate the audio device blocking when it's write buffers become - // full. - - // At the beginning or after an underrun, try to fill up the vbuffer. - // This will be throttled by the PlaybackThread - int frames_sleep = out->frames_total_buffered < out->buffer.frame_count ? 0 : frames; - - uint64_t sleep_time_us = frames_sleep * 1000000LL / - out_get_sample_rate(&stream->common); - - // If the write calls are delayed, subtract time off of the sleep to - // compensate - uint64_t time_since_last_write_us = now_us - out->last_write_time_us; - if (time_since_last_write_us < sleep_time_us) { - sleep_time_us -= time_since_last_write_us; - } else { - sleep_time_us = 0; - } - out->last_write_time_us = now_us + sleep_time_us; - - pthread_mutex_unlock(&out->lock); - - if (sleep_time_us > 0) { - usleep(sleep_time_us); - } - - if (frames_written < frames) { - ALOGW("Hardware backing HAL too slow, could only write %zu of %zu frames", frames_written, frames); - } - - /* Always consume all bytes */ - return bytes; -} - -static int out_get_presentation_position(const struct audio_stream_out *stream, - uint64_t *frames, struct timespec *timestamp) - -{ - if (stream == NULL || frames == NULL || timestamp == NULL) { - return -EINVAL; - } - struct generic_stream_out *out = (struct generic_stream_out *)stream; - - pthread_mutex_lock(&out->lock); - get_current_output_position(out, frames, timestamp); - pthread_mutex_unlock(&out->lock); - - return 0; -} - -static int out_get_render_position(const struct audio_stream_out *stream, - uint32_t *dsp_frames) -{ - if (stream == NULL || dsp_frames == NULL) { - return -EINVAL; - } - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - *dsp_frames = out->frames_rendered; - pthread_mutex_unlock(&out->lock); - return 0; -} - -// Must be called with out->lock held -static void do_out_standby(struct generic_stream_out *out) -{ - int frames_sleep = 0; - uint64_t sleep_time_us = 0; - if (out->standby) { - return; - } - while (true) { - get_current_output_position(out, &out->underrun_position, NULL); - frames_sleep = out->frames_written - out->underrun_position; - - if (frames_sleep == 0) { - break; - } - - sleep_time_us = frames_sleep * 1000000LL / - out_get_sample_rate(&out->stream.common); - - pthread_mutex_unlock(&out->lock); - usleep(sleep_time_us); - pthread_mutex_lock(&out->lock); - } - out->worker_standby = true; - out->standby = true; -} - -static int out_standby(struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - do_out_standby(out); - pthread_mutex_unlock(&out->lock); - return 0; -} - -static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // out_add_audio_effect is a no op - return 0; -} - -static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // out_remove_audio_effect is a no op - return 0; -} - -static int out_get_next_write_timestamp(const struct audio_stream_out *stream, - int64_t *timestamp) -{ - return -ENOSYS; -} - -static uint32_t in_get_sample_rate(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.sample_rate; -} - -static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static int refine_output_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask) -{ - static const uint32_t sample_rates [] = {8000,11025,16000,22050,24000,32000, - 44100,48000}; - static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t); - bool inval = false; - if (*format != AUDIO_FORMAT_PCM_16_BIT) { - *format = AUDIO_FORMAT_PCM_16_BIT; - inval = true; - } - - int channel_count = popcount(*channel_mask); - if (channel_count != 1 && channel_count != 2) { - *channel_mask = AUDIO_CHANNEL_IN_STEREO; - inval = true; - } - - int i; - for (i = 0; i < sample_rates_count; i++) { - if (*sample_rate < sample_rates[i]) { - *sample_rate = sample_rates[i]; - inval=true; - break; - } - else if (*sample_rate == sample_rates[i]) { - break; - } - else if (i == sample_rates_count-1) { - // Cap it to the highest rate we support - *sample_rate = sample_rates[i]; - inval=true; - } - } - - if (inval) { - return -EINVAL; - } - return 0; -} - -static int refine_input_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask) -{ - static const uint32_t sample_rates [] = {8000, 11025, 16000, 22050, 44100, 48000}; - static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t); - bool inval = false; - // Only PCM_16_bit is supported. If this is changed, stereo to mono drop - // must be fixed in in_read - if (*format != AUDIO_FORMAT_PCM_16_BIT) { - *format = AUDIO_FORMAT_PCM_16_BIT; - inval = true; - } - - int channel_count = popcount(*channel_mask); - if (channel_count != 1 && channel_count != 2) { - *channel_mask = AUDIO_CHANNEL_IN_STEREO; - inval = true; - } - - int i; - for (i = 0; i < sample_rates_count; i++) { - if (*sample_rate < sample_rates[i]) { - *sample_rate = sample_rates[i]; - inval=true; - break; - } - else if (*sample_rate == sample_rates[i]) { - break; - } - else if (i == sample_rates_count-1) { - // Cap it to the highest rate we support - *sample_rate = sample_rates[i]; - inval=true; - } - } - - if (inval) { - return -EINVAL; - } - return 0; -} - -static int check_input_parameters(uint32_t sample_rate, audio_format_t format, - audio_channel_mask_t channel_mask) -{ - return refine_input_parameters(&sample_rate, &format, &channel_mask); -} - -static size_t get_input_buffer_size(uint32_t sample_rate, audio_format_t format, - audio_channel_mask_t channel_mask) -{ - size_t size; - int channel_count = popcount(channel_mask); - if (check_input_parameters(sample_rate, format, channel_mask) != 0) - return 0; - - size = sample_rate*IN_PERIOD_MS/1000; - // Audioflinger expects audio buffers to be multiple of 16 frames - size = ((size + 15) / 16) * 16; - size *= sizeof(short) * channel_count; - - return size; -} - - -static size_t in_get_buffer_size(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - int size = get_input_buffer_size(in->req_config.sample_rate, - in->req_config.format, - in->req_config.channel_mask); - - return size; -} - -static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.channel_mask; -} - -static audio_format_t in_get_format(const struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - return in->req_config.format; -} - -static int in_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int in_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - - pthread_mutex_lock(&in->lock); - dprintf(fd, "\tin_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %zu\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice: %08x\n" - "\t\taudio dev: %p\n\n", - in_get_sample_rate(stream), - in_get_buffer_size(stream), - in_get_channels(stream), - in_get_format(stream), - in->device, - in->dev); - pthread_mutex_unlock(&in->lock); - return 0; -} - -static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct str_parms *parms; - char value[32]; - int ret = -ENOSYS; - int success; - long val; - char *end; - - if (kvpairs == NULL || kvpairs[0] == 0) { - return 0; - } - pthread_mutex_lock(&in->lock); - if (in->standby) { - parms = str_parms_create_str(kvpairs); - - success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (success >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) { - in->device = (int)val; - ret = 0; - } - } - // NO op for AUDIO_PARAMETER_DEVICE_CONNECT and AUDIO_PARAMETER_DEVICE_DISCONNECT - success = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, - value, sizeof(value)); - if (success >= 0) { - ret = 0; - } - success = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, - value, sizeof(value)); - if (success >= 0) { - ret = 0; - } - - if (ret != 0) { - ALOGD("%s: Unsupported parameter %s", __FUNCTION__, kvpairs); - } - - str_parms_destroy(parms); - } - pthread_mutex_unlock(&in->lock); - return ret; -} - -static char * in_get_parameters(const struct audio_stream *stream, - const char *keys) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str = NULL; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - bool get = false; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, in->device); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value); - get = true; - } - - if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) { - value[0] = 0; - strcat(value, "AUDIO_FORMAT_PCM_16_BIT"); - str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_FORMAT, value); - get = true; - } - - if (get) { - str = strdup(str_parms_to_str(reply)); - } - else { - ALOGD("%s Unsupported paramter: %s", __FUNCTION__, keys); - } - - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} - -static int in_set_gain(struct audio_stream_in *stream, float gain) -{ - // in_set_gain is a no op - return 0; -} - -// Call with in->lock held -static void get_current_input_position(struct generic_stream_in *in, - int64_t * position, - struct timespec * timestamp) { - struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; - clock_gettime(CLOCK_MONOTONIC, &t); - const int64_t now_us = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000; - if (timestamp) { - *timestamp = t; - } - int64_t position_since_standby; - if (in->standby) { - position_since_standby = 0; - } else { - const int64_t first_us = (in->standby_exit_time.tv_sec * 1000000000LL + - in->standby_exit_time.tv_nsec) / 1000; - position_since_standby = (now_us - first_us) * - in_get_sample_rate(&in->stream.common) / - 1000000; - if (position_since_standby < 0) { - position_since_standby = 0; - } - } - *position = in->standby_position + position_since_standby; -} - -// Must be called with in->lock held -static void do_in_standby(struct generic_stream_in *in) -{ - if (in->standby) { - return; - } - in->worker_standby = true; - get_current_input_position(in, &in->standby_position, NULL); - in->standby = true; -} - -static int in_standby(struct audio_stream *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - do_in_standby(in); - pthread_mutex_unlock(&in->lock); - return 0; -} - -static void *in_read_worker(void * args) -{ - struct generic_stream_in *in = (struct generic_stream_in *)args; - struct pcm *pcm = NULL; - uint8_t *buffer = NULL; - size_t buffer_frames; - int buffer_size; - - bool restart = false; - bool shutdown = false; - while (true) { - pthread_mutex_lock(&in->lock); - while (in->worker_standby || restart) { - restart = false; - if (pcm) { - pcm_close(pcm); // Frees pcm - pcm = NULL; - free(buffer); - buffer=NULL; - } - if (in->worker_exit) { - break; - } - pthread_cond_wait(&in->worker_wake, &in->lock); - } - - if (in->worker_exit) { - if (!in->worker_standby) { - ALOGE("In worker not in standby before exiting"); - } - shutdown = true; - } - if (shutdown) { - pthread_mutex_unlock(&in->lock); - break; - } - if (!pcm) { - pcm = pcm_open(PCM_CARD, PCM_DEVICE, - PCM_IN | PCM_MONOTONIC, &in->pcm_config); - if (!pcm_is_ready(pcm)) { - ALOGE("pcm_open(in) failed: %s: channels %d format %d rate %d", - pcm_get_error(pcm), - in->pcm_config.channels, - in->pcm_config.format, - in->pcm_config.rate - ); - pthread_mutex_unlock(&in->lock); - break; - } - buffer_frames = in->pcm_config.period_size; - buffer_size = pcm_frames_to_bytes(pcm, buffer_frames); - buffer = malloc(buffer_size); - if (!buffer) { - ALOGE("could not allocate worker read buffer"); - pthread_mutex_unlock(&in->lock); - break; - } - } - pthread_mutex_unlock(&in->lock); - int ret = pcm_read(pcm, buffer, pcm_frames_to_bytes(pcm, buffer_frames)); - if (ret != 0) { - ALOGW("pcm_read failed %s", pcm_get_error(pcm)); - restart = true; - continue; - } - - pthread_mutex_lock(&in->lock); - size_t frames_written = audio_vbuffer_write(&in->buffer, buffer, buffer_frames); - pthread_mutex_unlock(&in->lock); - - if (frames_written != buffer_frames) { - ALOGW("in_read_worker only could write %zu / %zu frames", frames_written, buffer_frames); - } - } - if (buffer) { - free(buffer); - } - return NULL; -} - -static ssize_t in_read(struct audio_stream_in *stream, void* buffer, - size_t bytes) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct generic_audio_device *adev = in->dev; - const size_t frames = bytes / audio_stream_in_frame_size(stream); - bool mic_mute = false; - size_t read_bytes = 0; - - adev_get_mic_mute(&adev->device, &mic_mute); - pthread_mutex_lock(&in->lock); - - if (in->worker_standby) { - in->worker_standby = false; - } - pthread_cond_signal(&in->worker_wake); - - int64_t current_position; - struct timespec current_time; - - get_current_input_position(in, ¤t_position, ¤t_time); - if (in->standby) { - in->standby = false; - in->standby_exit_time = current_time; - in->standby_frames_read = 0; - } - - const int64_t frames_available = current_position - in->standby_position - in->standby_frames_read; - assert(frames_available >= 0); - - const size_t frames_wait = ((uint64_t)frames_available > frames) ? 0 : frames - frames_available; - - int64_t sleep_time_us = frames_wait * 1000000LL / - in_get_sample_rate(&stream->common); - - pthread_mutex_unlock(&in->lock); - - if (sleep_time_us > 0) { - usleep(sleep_time_us); - } - - pthread_mutex_lock(&in->lock); - int read_frames = 0; - if (in->standby) { - ALOGW("Input put to sleep while read in progress"); - goto exit; - } - in->standby_frames_read += frames; - - if (popcount(in->req_config.channel_mask) == 1 && - in->pcm_config.channels == 2) { - // Need to resample to mono - if (in->stereo_to_mono_buf_size < bytes*2) { - in->stereo_to_mono_buf = realloc(in->stereo_to_mono_buf, - bytes*2); - if (!in->stereo_to_mono_buf) { - ALOGE("Failed to allocate stereo_to_mono_buff"); - goto exit; - } - } - - read_frames = audio_vbuffer_read(&in->buffer, in->stereo_to_mono_buf, frames); - - // Currently only pcm 16 is supported. - uint16_t *src = (uint16_t *)in->stereo_to_mono_buf; - uint16_t *dst = (uint16_t *)buffer; - size_t i; - // Resample stereo 16 to mono 16 by dropping one channel. - // The stereo stream is interleaved L-R-L-R - for (i = 0; i < frames; i++) { - *dst = *src; - src += 2; - dst += 1; - } - } else { - read_frames = audio_vbuffer_read(&in->buffer, buffer, frames); - } - -exit: - read_bytes = read_frames*audio_stream_in_frame_size(stream); - - if (mic_mute) { - read_bytes = 0; - } - - if (read_bytes < bytes) { - memset (&((uint8_t *)buffer)[read_bytes], 0, bytes-read_bytes); - } - - pthread_mutex_unlock(&in->lock); - - return bytes; -} - -static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) -{ - return 0; -} - -static int in_get_capture_position(const struct audio_stream_in *stream, - int64_t *frames, int64_t *time) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - struct timespec current_time; - get_current_input_position(in, frames, ¤t_time); - *time = (current_time.tv_sec * 1000000000LL + current_time.tv_nsec); - pthread_mutex_unlock(&in->lock); - return 0; -} - -static int in_get_active_microphones(const struct audio_stream_in *stream, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count) -{ - return adev_get_microphones(NULL, mic_array, mic_count); -} - -static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // in_add_audio_effect is a no op - return 0; -} - -static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // in_add_audio_effect is a no op - return 0; -} - -static int adev_open_output_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - audio_output_flags_t flags, - struct audio_config *config, - struct audio_stream_out **stream_out, - const char *address __unused) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_out *out; - int ret = 0; - - if (refine_output_parameters(&config->sample_rate, &config->format, &config->channel_mask)) { - ALOGE("Error opening output stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - ret = -EINVAL; - goto error; - } - - out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out)); - - if (!out) - return -ENOMEM; - - out->stream.common.get_sample_rate = out_get_sample_rate; - out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; - out->stream.common.get_channels = out_get_channels; - out->stream.common.get_format = out_get_format; - out->stream.common.set_format = out_set_format; - out->stream.common.standby = out_standby; - out->stream.common.dump = out_dump; - out->stream.common.set_parameters = out_set_parameters; - out->stream.common.get_parameters = out_get_parameters; - out->stream.common.add_audio_effect = out_add_audio_effect; - out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; - out->stream.set_volume = out_set_volume; - out->stream.write = out_write; - out->stream.get_render_position = out_get_render_position; - out->stream.get_presentation_position = out_get_presentation_position; - out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - out->dev = adev; - out->device = devices; - memcpy(&out->req_config, config, sizeof(struct audio_config)); - memcpy(&out->pcm_config, &pcm_config_out, sizeof(struct pcm_config)); - out->pcm_config.rate = config->sample_rate; - out->pcm_config.period_size = out->pcm_config.rate*OUT_PERIOD_MS/1000; - - out->standby = true; - out->underrun_position = 0; - out->underrun_time.tv_sec = 0; - out->underrun_time.tv_nsec = 0; - out->last_write_time_us = 0; - out->frames_total_buffered = 0; - out->frames_written = 0; - out->frames_rendered = 0; - - ret = audio_vbuffer_init(&out->buffer, - out->pcm_config.period_size*out->pcm_config.period_count, - out->pcm_config.channels * - pcm_format_to_bits(out->pcm_config.format) >> 3); - if (ret == 0) { - pthread_cond_init(&out->worker_wake, NULL); - out->worker_standby = true; - out->worker_exit = false; - pthread_create(&out->worker_thread, NULL, out_write_worker, out); - - } - *stream_out = &out->stream; - - -error: - - return ret; -} - -static void adev_close_output_stream(struct audio_hw_device *dev, - struct audio_stream_out *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - pthread_mutex_lock(&out->lock); - do_out_standby(out); - - out->worker_exit = true; - pthread_cond_signal(&out->worker_wake); - pthread_mutex_unlock(&out->lock); - - pthread_join(out->worker_thread, NULL); - pthread_mutex_destroy(&out->lock); - audio_vbuffer_destroy(&out->buffer); - free(stream); -} - -static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) -{ - return 0; -} - -static char * adev_get_parameters(const struct audio_hw_device *dev, - const char *keys) -{ - return strdup(""); -} - -static int adev_init_check(const struct audio_hw_device *dev) -{ - return 0; -} - -static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) -{ - // adev_set_voice_volume is a no op (simulates phones) - return 0; -} - -static int adev_set_master_volume(struct audio_hw_device *dev, float volume) -{ - return -ENOSYS; -} - -static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) -{ - return -ENOSYS; -} - -static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) -{ - return -ENOSYS; -} - -static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) -{ - return -ENOSYS; -} - -static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) -{ - // adev_set_mode is a no op (simulates phones) - return 0; -} - -static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - pthread_mutex_lock(&adev->lock); - adev->mic_mute = state; - pthread_mutex_unlock(&adev->lock); - return 0; -} - -static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - pthread_mutex_lock(&adev->lock); - *state = adev->mic_mute; - pthread_mutex_unlock(&adev->lock); - return 0; -} - - -static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, - const struct audio_config *config) -{ - return get_input_buffer_size(config->sample_rate, config->format, config->channel_mask); -} - - -static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *stream) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - pthread_mutex_lock(&in->lock); - do_in_standby(in); - - in->worker_exit = true; - pthread_cond_signal(&in->worker_wake); - pthread_mutex_unlock(&in->lock); - pthread_join(in->worker_thread, NULL); - - if (in->stereo_to_mono_buf != NULL) { - free(in->stereo_to_mono_buf); - in->stereo_to_mono_buf_size = 0; - } - - pthread_mutex_destroy(&in->lock); - audio_vbuffer_destroy(&in->buffer); - free(stream); -} - - -static int adev_open_input_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - struct audio_config *config, - struct audio_stream_in **stream_in, - audio_input_flags_t flags __unused, - const char *address __unused, - audio_source_t source __unused) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_in *in; - int ret = 0; - if (refine_input_parameters(&config->sample_rate, &config->format, &config->channel_mask)) { - ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - ret = -EINVAL; - goto error; - } - - in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in)); - if (!in) { - ret = -ENOMEM; - goto error; - } - - in->stream.common.get_sample_rate = in_get_sample_rate; - in->stream.common.set_sample_rate = in_set_sample_rate; // no op - in->stream.common.get_buffer_size = in_get_buffer_size; - in->stream.common.get_channels = in_get_channels; - in->stream.common.get_format = in_get_format; - in->stream.common.set_format = in_set_format; // no op - in->stream.common.standby = in_standby; - in->stream.common.dump = in_dump; - in->stream.common.set_parameters = in_set_parameters; - in->stream.common.get_parameters = in_get_parameters; - in->stream.common.add_audio_effect = in_add_audio_effect; // no op - in->stream.common.remove_audio_effect = in_remove_audio_effect; // no op - in->stream.set_gain = in_set_gain; // no op - in->stream.read = in_read; - in->stream.get_input_frames_lost = in_get_input_frames_lost; // no op - in->stream.get_capture_position = in_get_capture_position; - in->stream.get_active_microphones = in_get_active_microphones; - - pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); - in->dev = adev; - in->device = devices; - memcpy(&in->req_config, config, sizeof(struct audio_config)); - memcpy(&in->pcm_config, &pcm_config_in, sizeof(struct pcm_config)); - in->pcm_config.rate = config->sample_rate; - in->pcm_config.period_size = in->pcm_config.rate*IN_PERIOD_MS/1000; - - in->stereo_to_mono_buf = NULL; - in->stereo_to_mono_buf_size = 0; - - in->standby = true; - in->standby_position = 0; - in->standby_exit_time.tv_sec = 0; - in->standby_exit_time.tv_nsec = 0; - in->standby_frames_read = 0; - - ret = audio_vbuffer_init(&in->buffer, - in->pcm_config.period_size*in->pcm_config.period_count, - in->pcm_config.channels * - pcm_format_to_bits(in->pcm_config.format) >> 3); - if (ret == 0) { - pthread_cond_init(&in->worker_wake, NULL); - in->worker_standby = true; - in->worker_exit = false; - pthread_create(&in->worker_thread, NULL, in_read_worker, in); - } - - *stream_in = &in->stream; - -error: - return ret; -} - - -static int adev_dump(const audio_hw_device_t *dev, int fd) -{ - return 0; -} - -static int adev_get_microphones(const audio_hw_device_t *dev, - struct audio_microphone_characteristic_t *mic_array, - size_t *mic_count) -{ - if (mic_count == NULL) { - return -ENOSYS; - } - - if (*mic_count == 0) { - *mic_count = 1; - return 0; - } - - if (mic_array == NULL) { - return -ENOSYS; - } - - strncpy(mic_array->device_id, "mic_default", AUDIO_MICROPHONE_ID_MAX_LEN - 1); - mic_array->device = AUDIO_DEVICE_IN_BUILTIN_MIC; - strncpy(mic_array->address, AUDIO_BOTTOM_MICROPHONE_ADDRESS, - AUDIO_DEVICE_MAX_ADDRESS_LEN - 1); - memset(mic_array->channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED, - sizeof(mic_array->channel_mapping)); - mic_array->location = AUDIO_MICROPHONE_LOCATION_UNKNOWN; - mic_array->group = 0; - mic_array->index_in_the_group = 0; - mic_array->sensitivity = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN; - mic_array->max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; - mic_array->min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN; - mic_array->directionality = AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN; - mic_array->num_frequency_responses = 0; - mic_array->geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - mic_array->orientation.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN; - - *mic_count = 1; - return 0; -} - -static int adev_close(hw_device_t *dev) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - int ret = 0; - if (!adev) - return 0; - - pthread_mutex_lock(&adev_init_lock); - - if (audio_device_ref_count == 0) { - ALOGE("adev_close called when ref_count 0"); - ret = -EINVAL; - goto error; - } - - if ((--audio_device_ref_count) == 0) { - if (adev->mixer) { - mixer_close(adev->mixer); - } - free(adev); - } - -error: - pthread_mutex_unlock(&adev_init_lock); - return ret; -} - -static int adev_open(const hw_module_t* module, const char* name, - hw_device_t** device) -{ - static struct generic_audio_device *adev; - - if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) - return -EINVAL; - - pthread_once(&sFallbackOnce, fallback_init); - if (sFallback != NULL) { - return sFallback->common.methods->open(&sFallback->common, name, device); - } - - pthread_mutex_lock(&adev_init_lock); - if (audio_device_ref_count != 0) { - *device = &adev->device.common; - audio_device_ref_count++; - ALOGV("%s: returning existing instance of adev", __func__); - ALOGV("%s: exit", __func__); - goto unlock; - } - adev = calloc(1, sizeof(struct generic_audio_device)); - - pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL); - - adev->device.common.tag = HARDWARE_DEVICE_TAG; - adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; - adev->device.common.module = (struct hw_module_t *) module; - adev->device.common.close = adev_close; - - adev->device.init_check = adev_init_check; // no op - adev->device.set_voice_volume = adev_set_voice_volume; // no op - adev->device.set_master_volume = adev_set_master_volume; // no op - adev->device.get_master_volume = adev_get_master_volume; // no op - adev->device.set_master_mute = adev_set_master_mute; // no op - adev->device.get_master_mute = adev_get_master_mute; // no op - adev->device.set_mode = adev_set_mode; // no op - adev->device.set_mic_mute = adev_set_mic_mute; - adev->device.get_mic_mute = adev_get_mic_mute; - adev->device.set_parameters = adev_set_parameters; // no op - adev->device.get_parameters = adev_get_parameters; // no op - adev->device.get_input_buffer_size = adev_get_input_buffer_size; - adev->device.open_output_stream = adev_open_output_stream; - adev->device.close_output_stream = adev_close_output_stream; - adev->device.open_input_stream = adev_open_input_stream; - adev->device.close_input_stream = adev_close_input_stream; - adev->device.dump = adev_dump; - adev->device.get_microphones = adev_get_microphones; - - *device = &adev->device.common; - - adev->mixer = mixer_open(PCM_CARD); - struct mixer_ctl *ctl; - - // Set default mixer ctls - // Enable channels and set volume - for (int i = 0; i < (int)mixer_get_num_ctls(adev->mixer); i++) { - ctl = mixer_get_ctl(adev->mixer, i); - ALOGD("mixer %d name %s", i, mixer_ctl_get_name(ctl)); - if (!strcmp(mixer_ctl_get_name(ctl), "Master Playback Volume") || - !strcmp(mixer_ctl_get_name(ctl), "Capture Volume")) { - for (int z = 0; z < (int)mixer_ctl_get_num_values(ctl); z++) { - ALOGD("set ctl %d to %d", z, 100); - mixer_ctl_set_percent(ctl, z, 100); - } - continue; - } - if (!strcmp(mixer_ctl_get_name(ctl), "Master Playback Switch") || - !strcmp(mixer_ctl_get_name(ctl), "Capture Switch")) { - for (int z = 0; z < (int)mixer_ctl_get_num_values(ctl); z++) { - ALOGD("set ctl %d to %d", z, 1); - mixer_ctl_set_value(ctl, z, 1); - } - continue; - } - } - - audio_device_ref_count++; - -unlock: - pthread_mutex_unlock(&adev_init_lock); - return 0; -} - -static struct hw_module_methods_t hal_module_methods = { - .open = adev_open, -}; - -struct audio_module HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = AUDIO_MODULE_API_VERSION_0_1, - .hal_api_version = HARDWARE_HAL_API_VERSION, - .id = AUDIO_HARDWARE_MODULE_ID, - .name = "Generic audio HW HAL", - .author = "The Android Open Source Project", - .methods = &hal_module_methods, - }, -}; - -/* This function detects whether or not we should be using an alsa audio device - * or fall back to the legacy default_audio driver. - */ -static void -fallback_init(void) -{ - void* module; - - FILE *fptr = fopen ("/proc/asound/pcm", "r"); - if (fptr != NULL) { - // asound/pcm is empty if there are no devices - int c = fgetc(fptr); - fclose(fptr); - if (c != EOF) { - ALOGD("Emulator host-side ALSA audio emulation detected."); - return; - } - } - - ALOGD("Emulator without host-side ALSA audio emulation detected."); -#if __LP64__ - module = dlopen("/vendor/lib64/hw/audio.primary.i9305_legacy.so", - RTLD_LAZY|RTLD_LOCAL); -#else - module = dlopen("/vendor/lib/hw/audio.primary.i9305_legacy.so", - RTLD_LAZY|RTLD_LOCAL); -#endif - if (module != NULL) { - sFallback = (struct audio_module *)(dlsym(module, HAL_MODULE_INFO_SYM_AS_STR)); - if (sFallback == NULL) { - dlclose(module); - } - } - if (sFallback == NULL) { - ALOGE("Could not find legacy fallback module!?"); - } -} |