diff options
-rw-r--r-- | audio/Android.mk | 58 | ||||
-rw-r--r-- | audio/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | audio/NOTICE | 190 | ||||
-rw-r--r-- | audio/audio_hw.c | 1674 | ||||
-rw-r--r-- | audio/audio_hw_legacy.c | 714 |
5 files changed, 0 insertions, 2636 deletions
diff --git a/audio/Android.mk b/audio/Android.mk deleted file mode 100644 index 7db7659..0000000 --- a/audio/Android.mk +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (C) 2011 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_VENDOR_MODULE := true -LOCAL_MODULE := audio.primary.i9305 -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_MODULE_TAGS := optional - -LOCAL_SHARED_LIBRARIES := libcutils liblog - -LOCAL_SRC_FILES := audio_hw.c - -LOCAL_C_INCLUDES += \ - external/tinyalsa/include \ - -LOCAL_SHARED_LIBRARIES += \ - libdl \ - libtinyalsa - -LOCAL_CFLAGS := -Wno-unused-parameter -LOCAL_HEADER_LIBRARIES := libhardware_headers - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_VENDOR_MODULE := true -LOCAL_MODULE := audio.primary.i9305_legacy -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_MODULE_TAGS := optional - -LOCAL_SHARED_LIBRARIES := libcutils liblog - -LOCAL_SRC_FILES := audio_hw_legacy.c - -LOCAL_SHARED_LIBRARIES += \ - libdl - -LOCAL_CFLAGS := -Wno-unused-parameter -LOCAL_HEADER_LIBRARIES := libhardware_headers - -include $(BUILD_SHARED_LIBRARY) diff --git a/audio/MODULE_LICENSE_APACHE2 b/audio/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/audio/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/audio/NOTICE b/audio/NOTICE deleted file mode 100644 index 3237da6..0000000 --- a/audio/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2008-2009, 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. - - 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. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - 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!?"); - } -} diff --git a/audio/audio_hw_legacy.c b/audio/audio_hw_legacy.c deleted file mode 100644 index 3d6a253..0000000 --- a/audio/audio_hw_legacy.c +++ /dev/null @@ -1,714 +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" -/*#define LOG_NDEBUG 0*/ - -#include <errno.h> -#include <pthread.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/time.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> - - -#define AUDIO_DEVICE_NAME "/dev/eac" -#define OUT_BUFFER_SIZE 4096 -#define OUT_LATENCY_MS 20 -#define IN_SAMPLING_RATE 8000 -#define IN_BUFFER_SIZE 320 - - -struct generic_audio_device { - struct audio_hw_device device; - pthread_mutex_t lock; - struct audio_stream_out *output; - struct audio_stream_in *input; - int fd; - bool mic_mute; -}; - - -struct generic_stream_out { - struct audio_stream_out stream; - struct generic_audio_device *dev; - audio_devices_t device; - uint32_t sample_rate; -}; - -struct generic_stream_in { - struct audio_stream_in stream; - struct generic_audio_device *dev; - audio_devices_t device; -}; - - -static uint32_t out_get_sample_rate(const struct audio_stream *stream) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - return out->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) -{ - return OUT_BUFFER_SIZE; -} - -static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) -{ - return AUDIO_CHANNEL_OUT_STEREO; -} - -static audio_format_t out_get_format(const struct audio_stream *stream) -{ - return AUDIO_FORMAT_PCM_16_BIT; -} - -static int out_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int out_standby(struct audio_stream *stream) -{ - // out_standby is a no op - return 0; -} - -static int out_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - - 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); - - 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; - long val; - char *end; - - parms = str_parms_create_str(kvpairs); - - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (ret >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) { - out->device = (int)val; - } else { - ret = -EINVAL; - } - } - - str_parms_destroy(parms); - 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; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - - 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, out->device); - str = strdup(str_parms_to_str(reply)); - } else { - str = strdup(keys); - } - - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} - -static uint32_t out_get_latency(const struct audio_stream_out *stream) -{ - return OUT_LATENCY_MS; -} - -static int out_set_volume(struct audio_stream_out *stream, float left, - float right) -{ - return -ENOSYS; -} - -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; - struct generic_audio_device *adev = out->dev; - - pthread_mutex_lock(&adev->lock); - if (adev->fd >= 0) - bytes = write(adev->fd, buffer, bytes); - pthread_mutex_unlock(&adev->lock); - - return bytes; -} - -static int out_get_render_position(const struct audio_stream_out *stream, - uint32_t *dsp_frames) -{ - return -ENOSYS; -} - -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; -} - -/** audio_stream_in implementation **/ -static uint32_t in_get_sample_rate(const struct audio_stream *stream) -{ - return IN_SAMPLING_RATE; -} - -static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static size_t in_get_buffer_size(const struct audio_stream *stream) -{ - return IN_BUFFER_SIZE; -} - -static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) -{ - return AUDIO_CHANNEL_IN_MONO; -} - -static audio_format_t in_get_format(const struct audio_stream *stream) -{ - return AUDIO_FORMAT_PCM_16_BIT; -} - -static int in_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int in_standby(struct audio_stream *stream) -{ - // in_standby is a no op - return 0; -} - -static int in_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - - 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); - - 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; - long val; - char *end; - - parms = str_parms_create_str(kvpairs); - - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (ret >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) { - in->device = (int)val; - } else { - ret = -EINVAL; - } - } - - str_parms_destroy(parms); - 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; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - - 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); - str = strdup(str_parms_to_str(reply)); - } else { - str = strdup(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; -} - -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; - - pthread_mutex_lock(&adev->lock); - if (adev->fd >= 0) - bytes = read(adev->fd, buffer, bytes); - if (adev->mic_mute && (bytes > 0)) { - memset(buffer, 0, bytes); - } - pthread_mutex_unlock(&adev->lock); - - return bytes; -} - -static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) -{ - return 0; -} - -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; - static const uint32_t sample_rates [] = { 44100, 48000 }; - static const int sample_rates_count = sizeof(sample_rates)/sizeof(sample_rates[0]); - int ret = 0; - - pthread_mutex_lock(&adev->lock); - if (adev->output != NULL) { - ret = -ENOSYS; - goto error; - } - - if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || - (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) ) { - ALOGE("Error opening output stream, format %d, channel_mask %04x", - config->format, config->channel_mask); - config->format = AUDIO_FORMAT_PCM_16_BIT; - config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; - ret = -EINVAL; - } - - for (int idx = 0; idx < sample_rates_count; idx++) { - if (config->sample_rate < sample_rates[idx]) { - config->sample_rate = sample_rates[idx]; - ALOGE("Error opening output stream, sample_rate %u", config->sample_rate); - ret = -EINVAL; - break; - } else if (config->sample_rate == sample_rates[idx]) { - break; - } else if (idx == sample_rates_count-1) { - // Cap it to the highest rate we support - config->sample_rate = sample_rates[idx]; - ALOGE("Error opening output stream, sample_rate %u", config->sample_rate); - ret = -EINVAL; - } - } - - if (ret != 0) goto error; - - out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out)); - - 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_next_write_timestamp = out_get_next_write_timestamp; - out->sample_rate = config->sample_rate; - - out->dev = adev; - out->device = devices; - adev->output = (struct audio_stream_out *)out; - *stream_out = &out->stream; - -error: - pthread_mutex_unlock(&adev->lock); - - return ret; -} - -static void adev_close_output_stream(struct audio_hw_device *dev, - struct audio_stream_out *stream) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - if (stream == adev->output) { - free(stream); - adev->output = NULL; - } - pthread_mutex_unlock(&adev->lock); -} - -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) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - if (adev->fd >= 0) - return 0; - - return -ENODEV; -} - -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 IN_BUFFER_SIZE; -} - -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; - - pthread_mutex_lock(&adev->lock); - if (adev->input != NULL) { - ret = -ENOSYS; - goto error; - } - - if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || - (config->channel_mask != AUDIO_CHANNEL_IN_MONO) || - (config->sample_rate != IN_SAMPLING_RATE)) { - ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - config->format = AUDIO_FORMAT_PCM_16_BIT; - config->channel_mask = AUDIO_CHANNEL_IN_MONO; - config->sample_rate = IN_SAMPLING_RATE; - ret = -EINVAL; - goto error; - } - - in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in)); - - in->stream.common.get_sample_rate = in_get_sample_rate; - in->stream.common.set_sample_rate = in_set_sample_rate; - 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; - 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; - in->stream.common.remove_audio_effect = in_remove_audio_effect; - in->stream.set_gain = in_set_gain; - in->stream.read = in_read; - in->stream.get_input_frames_lost = in_get_input_frames_lost; - - in->dev = adev; - in->device = devices; - adev->input = (struct audio_stream_in *)in; - *stream_in = &in->stream; - -error: - pthread_mutex_unlock(&adev->lock); - - return ret; -} - -static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *stream) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - if (stream == adev->input) { - free(stream); - adev->input = NULL; - } - pthread_mutex_unlock(&adev->lock); -} - -static int adev_dump(const audio_hw_device_t *dev, int fd) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - const size_t SIZE = 256; - char buffer[SIZE]; - - dprintf(fd, "\nadev_dump:\n" - "\tfd: %d\n" - "\tmic_mute: %s\n" - "\toutput: %p\n" - "\tinput: %p\n\n", - adev->fd, - adev->mic_mute ? "true": "false", - adev->output, - adev->input); - - if (adev->output != NULL) - out_dump((const struct audio_stream *)adev->output, fd); - if (adev->input != NULL) - in_dump((const struct audio_stream *)adev->input, fd); - - return 0; -} - -static int adev_close(hw_device_t *dev) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - adev_close_output_stream((struct audio_hw_device *)dev, adev->output); - adev_close_input_stream((struct audio_hw_device *)dev, adev->input); - - if (adev->fd >= 0) - close(adev->fd); - - free(dev); - return 0; -} - -static int adev_open(const hw_module_t* module, const char* name, - hw_device_t** device) -{ - struct generic_audio_device *adev; - int fd; - - if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) - return -EINVAL; - - fd = open(AUDIO_DEVICE_NAME, O_RDWR); - if (fd < 0) - return -ENOSYS; - - adev = calloc(1, sizeof(struct generic_audio_device)); - - adev->fd = fd; - - 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; - adev->device.set_voice_volume = adev_set_voice_volume; - adev->device.set_master_volume = adev_set_master_volume; - adev->device.get_master_volume = adev_get_master_volume; - adev->device.set_master_mute = adev_set_master_mute; - adev->device.get_master_mute = adev_get_master_mute; - adev->device.set_mode = adev_set_mode; - 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; - adev->device.get_parameters = adev_get_parameters; - 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; - - *device = &adev->device.common; - - 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, - }, -}; |