diff options
-rw-r--r-- | hal/Android.mk | 5 | ||||
-rw-r--r-- | hal/audio_extn/a2dp.c | 2 | ||||
-rw-r--r-- | hal/audio_extn/audiozoom.c | 260 | ||||
-rw-r--r-- | hal/audio_extn/audiozoom.h | 31 | ||||
-rw-r--r-- | hal/audio_hw.c | 86 | ||||
-rw-r--r-- | hal/audio_hw.h | 2 | ||||
-rw-r--r-- | hal/msm8974/platform.c | 9 |
7 files changed, 372 insertions, 23 deletions
diff --git a/hal/Android.mk b/hal/Android.mk index 3bdcf127..e6be0a61 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -207,6 +207,11 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MAXX_AUDIO)), true) LOCAL_SRC_FILES += audio_extn/maxxaudio.c endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUDIO_ZOOM)), true) + LOCAL_CFLAGS += -DAUDIOZOOM_QDSP_ENABLED + LOCAL_SRC_FILES += audio_extn/audiozoom.c +endif + ifeq ($(strip $(AUDIO_FEATURE_ENABLED_24BITS_CAMCORDER)), true) LOCAL_CFLAGS += -DENABLED_24BITS_CAMCORDER endif diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c index 6ebbfc69..d7e2e2a9 100644 --- a/hal/audio_extn/a2dp.c +++ b/hal/audio_extn/a2dp.c @@ -79,7 +79,7 @@ // System properties used for A2DP Offload #define SYSPROP_A2DP_OFFLOAD_SUPPORTED "ro.bluetooth.a2dp_offload.supported" #define SYSPROP_A2DP_OFFLOAD_DISABLED "persist.bluetooth.a2dp_offload.disabled" -#define SYSPROP_BLUETOOTH_AUDIO_HAL_DISABLED "persist.vendor.bluetooth.bluetooth_audio_hal.disabled" +#define SYSPROP_BLUETOOTH_AUDIO_HAL_DISABLED "persist.bluetooth.bluetooth_audio_hal.disabled" #define SYSPROP_A2DP_CODEC_LATENCIES "vendor.audio.a2dp.codec.latency" // Default encoder bit width diff --git a/hal/audio_extn/audiozoom.c b/hal/audio_extn/audiozoom.c new file mode 100644 index 00000000..86d53b41 --- /dev/null +++ b/hal/audio_extn/audiozoom.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2019 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_audiozoom" +/*#define LOG_NDEBUG 0*/ + +#include <errno.h> +#include <log/log.h> +#include <stdlib.h> +#include <expat.h> +#include <audio_hw.h> +#include <system/audio.h> +#include <platform_api.h> +#include "audio_extn.h" + +#include "audiozoom.h" + +#include <resolv.h> + +#define AUDIOZOOM_PRESET_FILE "/vendor/etc/audiozoom.xml" +#define MIN_BUFSIZE 8 + +typedef struct qdsp_audiozoom_cfg { + uint32_t topo_id; + uint32_t module_id; + uint32_t instance_id; + uint32_t zoom_param_id; + uint32_t wide_param_id; + uint32_t dir_param_id; + uint32_t app_type; +} qdsp_audiozoom_cfg_t; + +static qdsp_audiozoom_cfg_t qdsp_audiozoom; + +static void start_tag(void *userdata __unused, const XML_Char *tag_name, + const XML_Char **attr) +{ + uint32_t index = 0; + + if (!attr) { + ALOGE("%s: NULL platform/tag_name/attr", __func__); + return; + } + + if (strcmp(tag_name, "topo") == 0) { + if (strcmp(attr[0], "id") == 0) { + if (attr[1]) + qdsp_audiozoom.topo_id = atoi(attr[1]); + } + } else if (strcmp(tag_name, "module") == 0) { + if (strcmp(attr[0], "id") == 0) { + if (attr[1]) + qdsp_audiozoom.module_id = atoi(attr[1]); + } + } else if (strcmp(tag_name, "param") == 0) { + while (attr[index] != NULL) { + if (strcmp(attr[index], "zoom_id") == 0) { + index++; + if (attr[index]) + qdsp_audiozoom.zoom_param_id = atoi(attr[index]); + else + break; + } else if (strcmp(attr[index], "wide_id") == 0) { + index++; + if (attr[index]) + qdsp_audiozoom.wide_param_id = atoi(attr[index]); + else + break; + } else if (strcmp(attr[index], "dir_id") == 0) { + index++; + if (attr[index]) + qdsp_audiozoom.dir_param_id = atoi(attr[index]); + else + break; + } + index++; + } + } else if (strcmp(tag_name, "app_type") == 0) { + if (strcmp(attr[0], "id") == 0) { + if (attr[1]) + qdsp_audiozoom.app_type = atoi(attr[1]); + } + } else if (strcmp(tag_name, "instance") == 0) { + if (strcmp(attr[0], "id") == 0) { + if (attr[1]) + qdsp_audiozoom.instance_id = atoi(attr[1]); + } + } else { + ALOGE("%s: %s is not a supported tag", __func__, tag_name); + } + + return; +} + +static void end_tag(void *userdata __unused, const XML_Char *tag_name) +{ + if (strcmp(tag_name, "topo") == 0) { + } else if (strcmp(tag_name, "module") == 0) { + } else if (strcmp(tag_name, "param") == 0) { + } else if (strcmp(tag_name, "app_type") == 0) { + } else if (strcmp(tag_name, "instance") == 0) { + } else { + ALOGE("%s: %s is not a supported tag", __func__, tag_name); + } +} + +static int audio_extn_audiozoom_parse_info(const char *filename) +{ + XML_Parser parser; + FILE *file; + int ret = 0; + int bytes_read; + void *buf; + static const uint32_t kBufSize = 1024; + + file = fopen(filename, "r"); + if (!file) { + ALOGE("%s: Failed to open %s", __func__, filename); + ret = -ENODEV; + goto done; + } + + parser = XML_ParserCreate(NULL); + if (!parser) { + ALOGE("%s: Failed to create XML parser!", __func__); + ret = -ENODEV; + goto err_close_file; + } + + XML_SetElementHandler(parser, start_tag, end_tag); + + while (1) { + buf = XML_GetBuffer(parser, kBufSize); + if (buf == NULL) { + ALOGE("%s: XML_GetBuffer failed", __func__); + ret = -ENOMEM; + goto err_free_parser; + } + + bytes_read = fread(buf, 1, kBufSize, file); + if (bytes_read < 0) { + ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read); + ret = bytes_read; + goto err_free_parser; + } + + if (XML_ParseBuffer(parser, bytes_read, + bytes_read == 0) == XML_STATUS_ERROR) { + ALOGE("%s: XML_ParseBuffer failed, for %s", + __func__, filename); + ret = -EINVAL; + goto err_free_parser; + } + + if (bytes_read == 0) + break; + } + +err_free_parser: + XML_ParserFree(parser); +err_close_file: + fclose(file); +done: + return ret; +} + +int audio_extn_audiozoom_set_microphone_direction( + struct stream_in *in, audio_microphone_direction_t dir) +{ + (void)in; + (void)dir; + return 0; +} + +static int audio_extn_audiozoom_set_microphone_field_dimension_zoom( + struct stream_in *in, float zoom) +{ + struct audio_device *adev = in->dev; + struct str_parms *parms = str_parms_create(); + uint8_t value[MIN_BUFSIZE] = {0}; + char data[MIN_BUFSIZE * 2] = {0}; + int32_t ret; + + if (zoom > 1.0 || zoom < 0) + return -EINVAL; + + if (qdsp_audiozoom.topo_id == 0 || qdsp_audiozoom.module_id == 0 || + qdsp_audiozoom.zoom_param_id == 0) + return -ENOSYS; + + str_parms_add_int(parms, "cal_devid", in->device); + str_parms_add_int(parms, "cal_apptype", in->app_type_cfg.app_type); + str_parms_add_int(parms, "cal_topoid", qdsp_audiozoom.topo_id); + str_parms_add_int(parms, "cal_moduleid", qdsp_audiozoom.module_id); + str_parms_add_int(parms, "cal_instanceid", qdsp_audiozoom.instance_id); + str_parms_add_int(parms, "cal_paramid", qdsp_audiozoom.zoom_param_id); + + zoom *= 255; + value[0] = (uint8_t) zoom; /* Valid value is 0 to 255 */ + + ret = b64_ntop(value, sizeof(value), data, sizeof(data)); + if (ret > 0) { + str_parms_add_str(parms, "cal_data", data); + + platform_set_parameters(adev->platform, parms); + } else { + ALOGE("%s: failed to convert data to string, ret %d", __func__, ret); + } + + str_parms_destroy(parms); + + return 0; +} + +static int audio_extn_audiozoom_set_microphone_field_dimension_wide_angle( + struct stream_in *in, float zoom) +{ + (void)in; + (void)zoom; + return 0; +} + +int audio_extn_audiozoom_set_microphone_field_dimension( + struct stream_in *in, float zoom) +{ + if (zoom > 1.0 || zoom < -1.0) + return -EINVAL; + + if (zoom >= 0 && zoom <= 1.0) + return audio_extn_audiozoom_set_microphone_field_dimension_zoom(in, zoom); + + if (zoom >= -1.0 && zoom <= 0) + return audio_extn_audiozoom_set_microphone_field_dimension_wide_angle(in, zoom); + + return 0; +} + +int audio_extn_audiozoom_init() +{ + audio_extn_audiozoom_parse_info(AUDIOZOOM_PRESET_FILE); + + ALOGV("%s: topo_id=%d, module_id=%d, instance_id=%d, zoom__id=%d, dir_id=%d, app_type=%d", + __func__, qdsp_audiozoom.topo_id, qdsp_audiozoom.module_id, qdsp_audiozoom.instance_id, + qdsp_audiozoom.zoom_param_id, qdsp_audiozoom.dir_param_id,qdsp_audiozoom.app_type); + + return 0; +} diff --git a/hal/audio_extn/audiozoom.h b/hal/audio_extn/audiozoom.h new file mode 100644 index 00000000..2c0ad716 --- /dev/null +++ b/hal/audio_extn/audiozoom.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef AUDIOZOOM_H_ +#define AUDIOZOOM_H_ + +#ifndef AUDIOZOOM_QDSP_ENABLED +#define audio_extn_audiozoom_init() (0) +#define audio_extn_audiozoom_set_microphone_direction(stream, dir) (-ENOSYS) +#define audio_extn_audiozoom_set_microphone_field_dimension(stream, zoom) (-ENOSYS) +#else +int audio_extn_audiozoom_init(); +int audio_extn_audiozoom_set_microphone_direction(struct stream_in *stream, + audio_microphone_direction_t dir); +int audio_extn_audiozoom_set_microphone_field_dimension(struct stream_in *stream, float zoom); +#endif + +#endif /* AUDIOZOOM_H_ */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index bb62dfd8..2807bcc9 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -60,6 +60,7 @@ #include "sound/compress_params.h" #include "audio_extn/tfa_98xx.h" #include "audio_extn/maxxaudio.h" +#include "audio_extn/audiozoom.h" /* COMPRESS_OFFLOAD_FRAGMENT_SIZE must be more than 8KB and a multiple of 32KB if more than 32KB. * COMPRESS_OFFLOAD_FRAGMENT_SIZE * COMPRESS_OFFLOAD_NUM_FRAGMENTS must be less than 8MB. */ @@ -353,6 +354,11 @@ static int last_known_cal_step = -1 ; static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore); static int set_compr_volume(struct audio_stream_out *stream, float left, float right); +static int in_set_microphone_direction(const struct audio_stream_in *stream, + audio_microphone_direction_t dir); +static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom); + + static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id, int flags __unused) { @@ -1492,8 +1498,9 @@ struct stream_in *get_voice_communication_input(const struct audio_device *adev) return NULL; } -int select_devices(struct audio_device *adev, - audio_usecase_t uc_id) +int select_devices_with_force_switch(struct audio_device *adev, + audio_usecase_t uc_id, + bool force_switch) { snd_device_t out_snd_device = SND_DEVICE_NONE; snd_device_t in_snd_device = SND_DEVICE_NONE; @@ -1598,7 +1605,7 @@ int select_devices(struct audio_device *adev, if (out_snd_device == usecase->out_snd_device && in_snd_device == usecase->in_snd_device) { - if (!force_device_switch(usecase)) + if (!force_device_switch(usecase) && !force_switch) return 0; } @@ -1742,6 +1749,12 @@ int select_devices(struct audio_device *adev, return status; } +int select_devices(struct audio_device *adev, + audio_usecase_t uc_id) +{ + return select_devices_with_force_switch(adev, uc_id, false); +} + static int stop_input_stream(struct stream_in *in) { int i, ret = 0; @@ -1886,6 +1899,8 @@ int start_input_stream(struct stream_in *in) } register_in_stream(in); check_and_enable_effect(adev); + audio_extn_audiozoom_set_microphone_direction(in, in->zoom); + audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction); audio_streaming_hint_end(); audio_extn_perf_lock_release(); ALOGV("%s: exit", __func__); @@ -4441,17 +4456,13 @@ static int in_start(const struct audio_stream_in* stream) return ret; } -// Read offset for the input positional timestamp from a property. -// This is to workaround apparent inaccuracies in the timing info that -// are causing glitches. +// Read offset for the positional timestamp from a persistent vendor property. +// This is to workaround apparent inaccuracies in the timing information that +// is used by the AAudio timing model. The inaccuracies can cause glitches. static int64_t in_get_mmap_time_offset() { - // Roughly 100 usec is needed on some devices to cover inaccuracy in DSP. - // This should be set in a property. But I cannot read the property! - // So I am setting the offset here to 101 as a test. - const int32_t kDefaultOffsetMicros = 101; // should be zero if no bug - // FIXME - why is the property not being read?! The default is used. + const int32_t kDefaultOffsetMicros = 0; int32_t mmap_time_offset_micros = property_get_int32( - "persist.audio.in_mmap_delay_micros", kDefaultOffsetMicros); + "persist.audio.in_mmap_delay_micros", kDefaultOffsetMicros); ALOGI("in_get_mmap_time_offset set to %d micros", mmap_time_offset_micros); return mmap_time_offset_micros * (int64_t)1000; } @@ -4580,8 +4591,8 @@ static int in_get_mmap_position(const struct audio_stream_in *stream, ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); goto exit; } - position->time_nanoseconds = audio_utils_ns_from_timespec(&ts); - position->time_nanoseconds += in->mmap_time_offset_nanos; + position->time_nanoseconds = audio_utils_ns_from_timespec(&ts) + + in->mmap_time_offset_nanos; exit: pthread_mutex_unlock(&in->lock); @@ -4621,17 +4632,32 @@ static int adev_get_microphones(const struct audio_hw_device *dev, static int in_set_microphone_direction(const struct audio_stream_in *stream, audio_microphone_direction_t dir) { - (void)stream; - (void)dir; - ALOGVV("%s", __func__); - return -ENOSYS; + struct stream_in *in = (struct stream_in *)stream; + + ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir); + + in->direction = dir; + + if (in->standby) + return 0; + + return audio_extn_audiozoom_set_microphone_direction(in, dir); } static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) { - (void)stream; - (void)zoom; - ALOGVV("%s", __func__); - return -ENOSYS; + struct stream_in *in = (struct stream_in *)stream; + + ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom); + + if (zoom > 1.0 || zoom < -1.0) + return -EINVAL; + + in->zoom = zoom; + + if (in->standby) + return 0; + + return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom); } static void in_update_sink_metadata(struct audio_stream_in *stream, @@ -5493,6 +5519,19 @@ static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) voice_is_in_call(adev)) { voice_stop_call(adev); adev->current_call_output = NULL; + + /* + * After stopping the call, it must check if any active capture + * activity device needs to be re-selected. + */ + struct audio_usecase *usecase; + struct listnode *node; + list_for_each(node, &adev->usecase_list) { + usecase = node_to_item(node, struct audio_usecase, list); + if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL) { + select_devices_with_force_switch(adev, usecase->id, true); + } + } } } pthread_mutex_unlock(&adev->lock); @@ -5657,6 +5696,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->standby = 1; in->capture_handle = handle; in->flags = flags; + in->direction = MIC_DIRECTION_UNSPECIFIED; + in->zoom = 0; ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask); if (source == AUDIO_SOURCE_VOICE_UPLINK || @@ -6339,6 +6380,7 @@ static int adev_open(const hw_module_t *module, const char *name, audio_extn_tfa_98xx_init(adev); audio_extn_ma_init(adev->platform); + audio_extn_audiozoom_init(); pthread_mutex_unlock(&adev_init_lock); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 6fd46f78..09926501 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -299,6 +299,8 @@ struct stream_in { audio_format_t format; card_status_t card_status; int capture_started; + float zoom; + audio_microphone_direction_t direction; struct stream_app_type_cfg app_type_cfg; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index eb4bb4a1..21f7cf57 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -961,6 +961,15 @@ static int parse_audiocal_cfg(struct str_parms *parms, acdb_audio_cal_cfg_t *cal cal->param_id = (uint32_t)strtoul(value, NULL, 0); ret = ret | 0x100; } +#ifdef PLATFORM_SM8150 + err = str_parms_get_str(parms, "cal_instanceid", value, sizeof(value)); + if (err >= 0) { + str_parms_del(parms, "cal_instanceid"); + cal->instance_id = (uint32_t)strtoul(value, NULL, 0); + ret = ret | 0x200; + } +#endif + return ret; } |