summaryrefslogtreecommitdiff
path: root/emulator/audio/driver
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/audio/driver')
-rw-r--r--emulator/audio/driver/Android.bp21
-rw-r--r--emulator/audio/driver/audio_extn/audio_extn.h38
-rw-r--r--emulator/audio/driver/audio_extn/hfp.c143
-rw-r--r--emulator/audio/driver/audio_hw.c68
-rw-r--r--emulator/audio/driver/audio_hw.h1
-rw-r--r--emulator/audio/driver/audio_vbuffer.c3
-rw-r--r--emulator/audio/driver/ext_pcm.c54
-rw-r--r--emulator/audio/driver/ext_pcm.h1
8 files changed, 286 insertions, 43 deletions
diff --git a/emulator/audio/driver/Android.bp b/emulator/audio/driver/Android.bp
index 945c628..8b9f53e 100644
--- a/emulator/audio/driver/Android.bp
+++ b/emulator/audio/driver/Android.bp
@@ -24,13 +24,31 @@ package {
default_applicable_licenses: ["device_generic_car_license"],
}
+soong_config_module_type {
+ name: "audio_extn_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "audio_extn_config",
+ bool_variables: ["isHFPEnabled"],
+ properties: ["srcs", "cflags"],
+}
+
+audio_extn_cc_defaults {
+ name: "audio_extn_hfp",
+ soong_config_variables: {
+ isHFPEnabled: {
+ cflags: ["-DHFP_ENABLED"],
+ srcs: ["audio_extn/hfp.c"],
+ },
+ },
+}
+
cc_library_shared {
vendor: true,
vintf_fragments: ["android.hardware.audio@6.0-impl.xml"],
name: "audio.primary.caremu",
relative_install_path: "hw",
-
+ defaults: ["audio_extn_hfp"],
srcs: [
"audio_hw.c",
"audio_vbuffer.c",
@@ -38,6 +56,7 @@ cc_library_shared {
],
include_dirs: ["external/tinyalsa/include"],
+ local_include_dirs: ["audio_extn"],
export_include_dirs: [
"include"
],
diff --git a/emulator/audio/driver/audio_extn/audio_extn.h b/emulator/audio/driver/audio_extn/audio_extn.h
new file mode 100644
index 0000000..13050c6
--- /dev/null
+++ b/emulator/audio/driver/audio_extn/audio_extn.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "audio_hw.h"
+#include <cutils/str_parms.h>
+
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_set_parameters(adev, parms) (0)
+#else
+int audio_extn_hfp_set_parameters(struct generic_audio_device *adev,
+ struct str_parms *parms);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUDIO_EXTN_H */
diff --git a/emulator/audio/driver/audio_extn/hfp.c b/emulator/audio/driver/audio_extn/hfp.c
new file mode 100644
index 0000000..fbe4000
--- /dev/null
+++ b/emulator/audio/driver/audio_extn/hfp.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+#ifdef HFP_ENABLED
+
+#define LOG_TAG "audio_hw_hfp"
+#define LOG_NDDEBUG 0
+
+#include "audio_extn.h"
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
+#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
+#define AUDIO_PARAMETER_HFP_VOLUME "hfp_volume"
+#define AUDIO_PARAMETER_HFP_VALUE_MAX 128
+
+static int hfp_set_enable(struct generic_audio_device *adev, bool enable) {
+ struct mixer_ctl *ctl;
+ ALOGD("%s: enter enable : %d", __func__, enable);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_PARAMETER_HFP_ENABLE);
+ if (!ctl) {
+ ALOGE("%s: Could not get mixer ctl for - %s", __func__,
+ AUDIO_PARAMETER_HFP_ENABLE);
+ return -EINVAL;
+ }
+
+ if (mixer_ctl_set_value(ctl, 0, enable) < 0) {
+ ALOGE("%s: Couldn't set mixer ctrl for %s", __func__,
+ AUDIO_PARAMETER_HFP_ENABLE);
+ return -EINVAL;
+ }
+
+ adev->hfp_running = enable;
+ ALOGD("%s: exit: status success", __func__);
+ return 0;
+}
+
+static int hfp_set_sampling_rate(struct generic_audio_device *adev, int rate) {
+ struct mixer_ctl *ctl;
+ ALOGD("%s: enter rate = %d", __func__, rate);
+
+ ctl =
+ mixer_get_ctl_by_name(adev->mixer, AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE);
+ if (!ctl) {
+ ALOGE("%s: Could not get mixer ctl for - %s", __func__,
+ AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE);
+ return -EINVAL;
+ }
+
+ if (mixer_ctl_set_value(ctl, 0, rate) < 0) {
+ ALOGE("%s: Couldn't set mixer ctrl for %s", __func__,
+ AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE);
+ return -EINVAL;
+ }
+
+ ALOGD("%s: exit: status success", __func__);
+ return 0;
+}
+
+static int hfp_set_volume(struct generic_audio_device *adev, int vol) {
+ struct mixer_ctl *ctl;
+ ALOGD("%s: enter vol = %d", __func__, vol);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_PARAMETER_HFP_VOLUME);
+ if (!ctl) {
+ ALOGE("%s: Could not get mixer ctl for - %s", __func__,
+ AUDIO_PARAMETER_HFP_VOLUME);
+ return -EINVAL;
+ }
+
+ if (mixer_ctl_set_value(ctl, 0, vol) < 0) {
+ ALOGE("%s: Couldn't set mixer ctrl for %s", __func__,
+ AUDIO_PARAMETER_HFP_VOLUME);
+ return -EINVAL;
+ }
+
+ ALOGD("%s: exit: status success", __func__);
+ return 0;
+}
+
+int audio_extn_hfp_set_parameters(struct generic_audio_device *adev,
+ struct str_parms *parms) {
+ int ret = 0, rate, vol;
+ char value[AUDIO_PARAMETER_HFP_VALUE_MAX] = {0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (!strncmp(value, "true", sizeof(value))) {
+ if (!adev->hfp_running)
+ ret = hfp_set_enable(adev, true);
+ else
+ ALOGW("%s: HFP is already active.", __func__);
+ } else {
+ if (adev->hfp_running)
+ ret = hfp_set_enable(adev, false);
+ else
+ ALOGW("%s: ignore STOP, HFP not active", __func__);
+ }
+
+ if (ret < 0)
+ goto exit;
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ rate = strtol(value, NULL, 10);
+ ret = hfp_set_sampling_rate(adev, rate);
+ if (ret < 0)
+ goto exit;
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_VOLUME, value,
+ sizeof(value));
+ if (ret >= 0) {
+ vol = strtol(value, NULL, 10);
+ ret = hfp_set_volume(adev, vol);
+ }
+
+exit:
+ ALOGD("%s exit: status", __func__);
+ return ret;
+}
+#endif /*HFP_ENABLED*/
diff --git a/emulator/audio/driver/audio_hw.c b/emulator/audio/driver/audio_hw.c
index 36796c4..65cbb11 100644
--- a/emulator/audio/driver/audio_hw.c
+++ b/emulator/audio/driver/audio_hw.c
@@ -22,6 +22,7 @@
#define LOG_TAG "audio_hw_generic_caremu"
// #define LOG_NDEBUG 0
+#include "audio_extn.h"
#include "audio_hw.h"
#include "include/audio_hw_control.h"
@@ -87,6 +88,7 @@ static const char * const AUDIO_ZONE_KEYWORD = "_audio_zone_";
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
#define SIZE_OF_PARSE_BUFFER 32
+#define SIZE_OF_THREAD_NAME_BUFFER 16
static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state);
@@ -162,6 +164,11 @@ void set_device_address_is_muted(const char *device_address, bool is_muted){
pthread_mutex_unlock(&out->lock);
}
+static void set_shortened_thread_name(pthread_t thread, const char *name) {
+ char shortenedName[SIZE_OF_THREAD_NAME_BUFFER];
+ strncpy(shortenedName, name, SIZE_OF_THREAD_NAME_BUFFER);
+ pthread_setname_np(thread, shortenedName);
+}
static struct pcm_config pcm_config_out = {
.channels = 2,
@@ -505,6 +512,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, si
const size_t frame_size = audio_stream_out_frame_size(stream);
const size_t frames = bytes / frame_size;
+ set_shortened_thread_name(pthread_self(), __func__);
+
pthread_mutex_lock(&out->lock);
if (out->worker_standby) {
@@ -1002,6 +1011,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, size_t byte
bool mic_mute = false;
size_t read_bytes = 0;
+ set_shortened_thread_name(pthread_self(), __func__);
+
adev_get_mic_mute(&adev->device, &mic_mute);
pthread_mutex_lock(&in->lock);
@@ -1183,34 +1194,35 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->worker_standby = true;
out->worker_exit = false;
pthread_create(&out->worker_thread, NULL, out_write_worker, out);
- }
-
- out->enabled_channels = BOTH_CHANNELS;
- // For targets where output streams are closed regularly, currently ducked/muted addresses
- // should be tracked so that the address of new streams can be checked to determine the
- // default state
- out->is_ducked = 0;
- out->is_muted = 0;
- if (address) {
- out->bus_address = calloc(strlen(address) + 1, sizeof(char));
- strncpy(out->bus_address, address, strlen(address));
- hashmapPut(adev->out_bus_stream_map, out->bus_address, out);
- /* TODO: read struct audio_gain from audio_policy_configuration */
- out->gain_stage = (struct audio_gain) {
- .min_value = -3200,
- .max_value = 600,
- .step_value = 100,
- };
- out->amplitude_ratio = 1.0;
- if (property_get_bool(PROP_KEY_SIMULATE_MULTI_ZONE_AUDIO, false)) {
- out->enabled_channels = strstr(out->bus_address, AUDIO_ZONE_KEYWORD)
- ? RIGHT_CHANNEL: LEFT_CHANNEL;
- ALOGD("%s Routing %s to %s channel", __func__,
- out->bus_address, out->enabled_channels == RIGHT_CHANNEL ? "Right" : "Left");
+ set_shortened_thread_name(out->worker_thread, address);
+
+ out->enabled_channels = BOTH_CHANNELS;
+ // For targets where output streams are closed regularly, currently ducked/muted addresses
+ // should be tracked so that the address of new streams can be checked to determine the
+ // default state
+ out->is_ducked = 0;
+ out->is_muted = 0;
+ if (address) {
+ out->bus_address = calloc(strlen(address) + 1, sizeof(char));
+ strncpy(out->bus_address, address, strlen(address));
+ hashmapPut(adev->out_bus_stream_map, out->bus_address, out);
+ /* TODO: read struct audio_gain from audio_policy_configuration */
+ out->gain_stage = (struct audio_gain) {
+ .min_value = -3200,
+ .max_value = 600,
+ .step_value = 100,
+ };
+ out->amplitude_ratio = 1.0;
+ if (property_get_bool(PROP_KEY_SIMULATE_MULTI_ZONE_AUDIO, false)) {
+ out->enabled_channels = strstr(out->bus_address, AUDIO_ZONE_KEYWORD)
+ ? RIGHT_CHANNEL: LEFT_CHANNEL;
+ ALOGD("%s Routing %s to %s channel", __func__,
+ out->bus_address, out->enabled_channels == RIGHT_CHANNEL ? "Right" : "Left");
+ }
}
+ *stream_out = &out->stream;
+ ALOGD("%s bus: %s", __func__, out->bus_address);
}
- *stream_out = &out->stream;
- ALOGD("%s bus: %s", __func__, out->bus_address);
error:
return ret;
@@ -1250,6 +1262,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
results = 0;
ALOGD("%s Changed play zone id to %d", __func__, adev->last_zone_selected_to_play);
}
+ results = audio_extn_hfp_set_parameters(adev, parms);
str_parms_destroy(parms);
pthread_mutex_unlock(&adev->lock);
return results;
@@ -1428,6 +1441,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
in->worker_standby = true;
in->worker_exit = false;
pthread_create(&in->worker_thread, NULL, in_read_worker, in);
+ set_shortened_thread_name(in->worker_thread, address ? address : "mic");
}
if (address) {
@@ -1665,6 +1679,8 @@ static int adev_open(const hw_module_t *module,
adev->last_zone_selected_to_play = DEFAULT_ZONE_TO_LEFT_SPEAKER;
+ adev->hfp_running = false;
+
device_handle = adev;
audio_device_ref_count++;
diff --git a/emulator/audio/driver/audio_hw.h b/emulator/audio/driver/audio_hw.h
index 1f9aa51..c243222 100644
--- a/emulator/audio/driver/audio_hw.h
+++ b/emulator/audio/driver/audio_hw.h
@@ -37,6 +37,7 @@ struct generic_audio_device {
int next_tone_frequency_to_assign; // Protected by this->lock
// Play on Speaker zone selection
int last_zone_selected_to_play; // Protected by this->lock
+ bool hfp_running;
};
static struct generic_audio_device *device_handle;
diff --git a/emulator/audio/driver/audio_vbuffer.c b/emulator/audio/driver/audio_vbuffer.c
index 79be545..8377f5c 100644
--- a/emulator/audio/driver/audio_vbuffer.c
+++ b/emulator/audio/driver/audio_vbuffer.c
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "audio_hw_generic"
+#define LOG_TAG "audio_hw_generic_caremu"
+// #define LOG_NDEBUG 0
#include <errno.h>
#include <stdlib.h>
diff --git a/emulator/audio/driver/ext_pcm.c b/emulator/audio/driver/ext_pcm.c
index df3e1f1..2b0e825 100644
--- a/emulator/audio/driver/ext_pcm.c
+++ b/emulator/audio/driver/ext_pcm.c
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "audio_hw_generic"
+#define LOG_TAG "audio_hw_generic_caremu"
+// #define LOG_NDEBUG 0
#include <errno.h>
+#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -31,6 +33,8 @@ static struct ext_pcm *shared_ext_pcm = NULL;
// Sleep 10ms between each mixing, this interval value is arbitrary chosen
#define MIXER_INTERVAL_MS 10
+#define MS_TO_US 1000
+
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -70,7 +74,8 @@ static bool mixer_thread_mix(__unused void *key, void *value, void *context) {
}
static void *mixer_thread_loop(void *context) {
- ALOGD("%s: __enter__", __func__);
+ pthread_setname_np(pthread_self(), "car_mixer_loop");
+ ALOGD("%s: starting mixer loop", __func__);
struct ext_pcm *ext_pcm = (struct ext_pcm *)context;
do {
pthread_mutex_lock(&ext_pcm->mixer_lock);
@@ -79,14 +84,25 @@ static void *mixer_thread_loop(void *context) {
hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_thread_mix,
&ext_pcm->mixer_pipeline);
if (ext_pcm->mixer_pipeline.position > 0) {
- pcm_write(ext_pcm->pcm, (void *)ext_pcm->mixer_pipeline.buffer,
+ int ret = pcm_write(ext_pcm->pcm, (void *)ext_pcm->mixer_pipeline.buffer,
ext_pcm->mixer_pipeline.position * sizeof(int16_t));
+ if (ret != 0) {
+ ALOGE("%s error[%d] writing data to pcm");
+ }
}
memset(&ext_pcm->mixer_pipeline, 0, sizeof(struct ext_mixer_pipeline));
pthread_cond_broadcast(&ext_pcm->mixer_wake);
pthread_mutex_unlock(&ext_pcm->mixer_lock);
- usleep(MIXER_INTERVAL_MS * 1000);
+ pthread_mutex_lock(&ext_pcm_init_lock);
+ bool keep_running = ext_pcm->run_mixer;
+ pthread_mutex_unlock(&ext_pcm_init_lock);
+ if (!keep_running) {
+ break;
+ }
+ usleep(MIXER_INTERVAL_MS * MS_TO_US);
} while (1);
+ ALOGD("%s: exiting mixer loop", __func__);
+ return NULL;
}
static int mixer_pipeline_write(struct ext_pcm *ext_pcm, const char *bus_address,
@@ -130,12 +146,10 @@ struct ext_pcm *ext_pcm_open(unsigned int card, unsigned int device,
pthread_create(&shared_ext_pcm->mixer_thread, (const pthread_attr_t *)NULL,
mixer_thread_loop, shared_ext_pcm);
shared_ext_pcm->mixer_pipeline_map = hashmapCreate(8, str_hash_fn, str_eq);
+ shared_ext_pcm->run_mixer = true;
}
- pthread_mutex_unlock(&ext_pcm_init_lock);
-
- pthread_mutex_lock(&shared_ext_pcm->lock);
shared_ext_pcm->ref_count += 1;
- pthread_mutex_unlock(&shared_ext_pcm->lock);
+ pthread_mutex_unlock(&ext_pcm_init_lock);
return shared_ext_pcm;
}
@@ -147,27 +161,37 @@ static bool mixer_free_pipeline(__unused void *key, void *value, void *context)
}
int ext_pcm_close(struct ext_pcm *ext_pcm) {
+ ALOGD("%s closing pcm", __func__);
if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
return -EINVAL;
}
- pthread_mutex_lock(&ext_pcm->lock);
- ext_pcm->ref_count -= 1;
- pthread_mutex_unlock(&ext_pcm->lock);
-
pthread_mutex_lock(&ext_pcm_init_lock);
- if (ext_pcm->ref_count <= 0) {
+ int count = ext_pcm->ref_count -= 1;
+ if (count <= 0) {
+ ext_pcm->run_mixer = false;
+ // On pcm open new shared_ext_pcm will be created
+ shared_ext_pcm = NULL;
+ pthread_mutex_unlock(&ext_pcm_init_lock);
+ void* ret_val = NULL;
+ int ret = pthread_join(ext_pcm->mixer_thread, &ret_val);
+ if (ret != 0) {
+ ALOGE("%s error[%d] when joining thread",
+ __func__, ret);
+ // Try killing if timeout failed
+ pthread_kill(ext_pcm->mixer_thread, SIGINT);
+ }
+ pthread_mutex_lock(&ext_pcm_init_lock);
pthread_mutex_destroy(&ext_pcm->lock);
pcm_close(ext_pcm->pcm);
pthread_mutex_destroy(&ext_pcm->mixer_lock);
hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_free_pipeline,
(void *)NULL);
hashmapFree(ext_pcm->mixer_pipeline_map);
- pthread_kill(ext_pcm->mixer_thread, SIGINT);
free(ext_pcm);
- shared_ext_pcm = NULL;
}
pthread_mutex_unlock(&ext_pcm_init_lock);
+ ALOGD("%s finished closing pcm", __func__);
return 0;
}
diff --git a/emulator/audio/driver/ext_pcm.h b/emulator/audio/driver/ext_pcm.h
index c038b86..562b874 100644
--- a/emulator/audio/driver/ext_pcm.h
+++ b/emulator/audio/driver/ext_pcm.h
@@ -34,6 +34,7 @@ struct ext_pcm {
struct pcm *pcm;
pthread_mutex_t lock;
pthread_cond_t mixer_wake;
+ bool run_mixer;
unsigned int ref_count;
pthread_mutex_t mixer_lock;
struct ext_mixer_pipeline mixer_pipeline;