Merge "A2DP Offload HAL v2.0 support"
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 657a627..24d726f 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -131,6 +131,26 @@
.avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};
+struct pcm_config pcm_config_haptics_audio = {
+ .channels = 1,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+ .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+struct pcm_config pcm_config_haptics = {
+ .channels = 1,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
static int af_period_multiplier = 4;
struct pcm_config pcm_config_rt = {
.channels = DEFAULT_CHANNEL_COUNT,
@@ -256,6 +276,7 @@
const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
+ [USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = "audio-with-haptics-playback",
[USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
[USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
@@ -1510,7 +1531,8 @@
get_voice_usecase_id_from_list(adev));
if ((vc_usecase != NULL) &&
((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
- (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
+ (vc_usecase->devices == AUDIO_DEVICE_OUT_HEARING_AID) ||
+ (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
@@ -1556,8 +1578,13 @@
out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
} else if (voip_usecase) {
out_device = voip_usecase->stream.out->devices;
- } else if (adev->primary_output) {
+ } else if (adev->primary_output &&
+ !adev->primary_output->standby) {
out_device = adev->primary_output->devices;
+ } else {
+ /* forcing speaker o/p device to get matching i/p pair
+ in case o/p is not routed from same primary HAL */
+ out_device = AUDIO_DEVICE_OUT_SPEAKER;
}
}
in_snd_device = platform_get_input_snd_device(adev->platform,
@@ -2213,14 +2240,19 @@
}
ret = 0;
}
-
+ /* 1) media + voip output routing to handset must route media back to
+ speaker when voip stops.
+ 2) trigger voip input to reroute when voip output changes to
+ hearing aid. */
if (has_voip_usecase ||
out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
struct listnode *node;
struct audio_usecase *usecase;
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type == PCM_CAPTURE || usecase == uc_info)
+ if ((usecase->type == PCM_CAPTURE &&
+ usecase->id != USECASE_AUDIO_RECORD_VOIP)
+ || usecase == uc_info)
continue;
ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
@@ -2235,6 +2267,41 @@
return ret;
}
+struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
+ unsigned int flags, unsigned int pcm_open_retry_count,
+ struct pcm_config *config)
+{
+ struct pcm* pcm = NULL;
+
+ while (1) {
+ pcm = pcm_open(snd_card, pcm_device_id, flags, config);
+ if (pcm == NULL || !pcm_is_ready(pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(pcm));
+ if (pcm != NULL) {
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0)
+ return NULL;
+
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
+ }
+
+ if (pcm_is_ready(pcm)) {
+ int ret = pcm_prepare(pcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+ pcm_close(pcm);
+ pcm = NULL;
+ }
+ }
+
+ return pcm;
+}
+
int start_output_stream(struct stream_out *out)
{
int ret = 0;
@@ -2242,8 +2309,10 @@
struct audio_device *adev = out->dev;
bool a2dp_combo = false;
- ALOGV("%s: enter: usecase(%d: %s) devices(%#x)",
- __func__, out->usecase, use_case_table[out->usecase], out->devices);
+ ALOGV("%s: enter: usecase(%d: %s) %s devices(%#x)",
+ __func__, out->usecase, use_case_table[out->usecase],
+ out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS ? "(with haptics)" : "",
+ out->devices);
if (out->card_status == CARD_STATUS_OFFLINE ||
adev->card_status == CARD_STATUS_OFFLINE) {
@@ -2363,34 +2432,27 @@
flags |= PCM_MMAP | PCM_NOIRQ;
}
- while (1) {
- out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
- flags, &out->config);
- if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
- if (out->pcm != NULL) {
- pcm_close(out->pcm);
- out->pcm = NULL;
- }
- if (pcm_open_retry_count-- == 0) {
- ret = -EIO;
- goto error_open;
- }
- usleep(PROXY_OPEN_WAIT_TIME * 1000);
- continue;
- }
- break;
+ out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
+ flags, pcm_open_retry_count,
+ &(out->config));
+ if (out->pcm == NULL) {
+ ret = -EIO;
+ goto error_open;
}
- ALOGV("%s: pcm_prepare", __func__);
- if (pcm_is_ready(out->pcm)) {
- ret = pcm_prepare(out->pcm);
- if (ret < 0) {
- ALOGE("%s: pcm_prepare returned %d", __func__, ret);
- pcm_close(out->pcm);
- out->pcm = NULL;
- goto error_open;
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
+ if (adev->haptic_pcm != NULL) {
+ pcm_close(adev->haptic_pcm);
+ adev->haptic_pcm = NULL;
}
+ adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
+ adev->haptic_pcm_device_id,
+ flags, pcm_open_retry_count,
+ &(adev->haptics_config));
+ // failure to open haptics pcm shouldnt stop audio,
+ // so do not close audio pcm in case of error
}
+
if (out->realtime) {
ret = pcm_start(out->pcm);
if (ret < 0) {
@@ -2401,6 +2463,7 @@
}
}
}
+
register_out_stream(out);
audio_streaming_hint_end();
audio_extn_perf_lock_release();
@@ -2414,13 +2477,17 @@
// consider a scenario where on pause lower layers are tear down.
// so on resume, swap mixer control need to be sent only when
// backend is active, hence rather than sending from enable device
- // sending it from start of streamtream
+ // sending it from start of stream
platform_set_swap_channels(adev, true);
ALOGV("%s: exit", __func__);
return 0;
error_open:
+ if (adev->haptic_pcm) {
+ pcm_close(adev->haptic_pcm);
+ adev->haptic_pcm = NULL;
+ }
audio_streaming_hint_end();
audio_extn_perf_lock_release();
stop_output_stream(out);
@@ -2594,6 +2661,19 @@
if (out->pcm) {
pcm_close(out->pcm);
out->pcm = NULL;
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
+ if (adev->haptic_pcm) {
+ pcm_close(adev->haptic_pcm);
+ adev->haptic_pcm = NULL;
+ }
+
+ if (adev->haptic_buffer != NULL) {
+ free(adev->haptic_buffer);
+ adev->haptic_buffer = NULL;
+ adev->haptic_buffer_size = 0;
+ }
+ }
}
if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
do_stop = out->playback_started;
@@ -3294,11 +3374,77 @@
request_out_focus(out, ns);
bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
- if (use_mmap)
+ if (use_mmap) {
ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
- else
- ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
+ } else {
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
+ size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
+ size_t bytes_per_sample = audio_bytes_per_sample(out->format);
+ size_t frame_size = channel_count * bytes_per_sample;
+ size_t frame_count = bytes_to_write / frame_size;
+ bool force_haptic_path =
+ property_get_bool("vendor.audio.test_haptic", false);
+
+ // extract Haptics data from Audio buffer
+ bool alloc_haptic_buffer = false;
+ int haptic_channel_count = adev->haptics_config.channels;
+ size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
+ size_t audio_frame_size = frame_size - haptic_frame_size;
+ size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
+
+ if (adev->haptic_buffer == NULL) {
+ alloc_haptic_buffer = true;
+ } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
+ free(adev->haptic_buffer);
+ adev->haptic_buffer_size = 0;
+ alloc_haptic_buffer = true;
+ }
+
+ if (alloc_haptic_buffer) {
+ adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
+ adev->haptic_buffer_size = total_haptic_buffer_size;
+ }
+
+ size_t src_index = 0, aud_index = 0, hap_index = 0;
+ uint8_t *audio_buffer = (uint8_t *)buffer;
+ uint8_t *haptic_buffer = adev->haptic_buffer;
+
+ // This is required for testing only. This works for stereo data only.
+ // One channel is fed to audio stream and other to haptic stream for testing.
+ if (force_haptic_path) {
+ audio_frame_size = haptic_frame_size = bytes_per_sample;
+ }
+
+ for (size_t i = 0; i < frame_count; i++) {
+ for (size_t j = 0; j < audio_frame_size; j++)
+ audio_buffer[aud_index++] = audio_buffer[src_index++];
+
+ for (size_t j = 0; j < haptic_frame_size; j++)
+ haptic_buffer[hap_index++] = audio_buffer[src_index++];
+ }
+
+ // This is required for testing only.
+ // Discard haptic channel data.
+ if (force_haptic_path) {
+ src_index += haptic_frame_size;
+ }
+
+ // write to audio pipeline
+ ret = pcm_write(out->pcm,
+ (void *)audio_buffer,
+ frame_count * audio_frame_size);
+
+ // write to haptics pipeline
+ if (adev->haptic_pcm)
+ ret = pcm_write(adev->haptic_pcm,
+ (void *)adev->haptic_buffer,
+ frame_count * haptic_frame_size);
+
+ } else {
+ ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
+ }
+ }
release_out_focus(out, ns);
} else {
LOG_ALWAYS_FATAL("out->pcm is NULL after starting output stream");
@@ -4377,6 +4523,52 @@
return -ENOSYS;
}
+static void in_update_sink_metadata(struct audio_stream_in *stream,
+ const struct sink_metadata *sink_metadata) {
+
+ if (stream == NULL
+ || sink_metadata == NULL
+ || sink_metadata->tracks == NULL) {
+ return;
+ }
+
+ int error = 0;
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+
+ if (sink_metadata->track_count != 0)
+ device = sink_metadata->tracks->dest_device;
+
+ lock_input_stream(in);
+ pthread_mutex_lock(&adev->lock);
+ ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, device);
+
+ if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY
+ && device != AUDIO_DEVICE_NONE
+ && adev->voice_tx_output != NULL) {
+ /* Use the rx device from afe-proxy record to route voice call because
+ there is no routing if tx device is on primary hal and rx device
+ is on other hal during voice call. */
+ adev->voice_tx_output->devices = device;
+
+ if (!voice_is_call_state_active(adev)) {
+ if (adev->mode == AUDIO_MODE_IN_CALL) {
+ adev->current_call_output = adev->voice_tx_output;
+ error = voice_start_call(adev);
+ if (error != 0)
+ ALOGE("%s: start voice call failed %d", __func__, error);
+ }
+ } else {
+ adev->current_call_output = adev->voice_tx_output;
+ voice_update_devices_for_all_voice_usecases(adev);
+ }
+ }
+
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&in->lock);
+}
+
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
@@ -4391,6 +4583,8 @@
bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
bool is_usb_dev = audio_is_usb_out_device(devices) &&
(devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
+ bool force_haptic_path =
+ property_get_bool("vendor.audio.test_haptic", false);
if (is_usb_dev && !is_usb_ready(adev, true /* is_playback */)) {
return -ENOSYS;
@@ -4398,6 +4592,7 @@
ALOGV("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
__func__, config->format, config->sample_rate, config->channel_mask, devices, flags);
+
*stream_out = NULL;
out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
@@ -4728,8 +4923,24 @@
out->stream.create_mmap_buffer = out_create_mmap_buffer;
out->stream.get_mmap_position = out_get_mmap_position;
} else {
- out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
- out->config = pcm_config_low_latency;
+ if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
+ adev->haptic_pcm_device_id = platform_get_haptics_pcm_device_id();
+ if (adev->haptic_pcm_device_id < 0) {
+ ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
+ __func__, adev->haptic_pcm_device_id, out->usecase);
+ ret = -ENOSYS;
+ goto error_open;
+ }
+ out->config = pcm_config_haptics_audio;
+ if (force_haptic_path)
+ adev->haptics_config = pcm_config_haptics_audio;
+ else
+ adev->haptics_config = pcm_config_haptics;
+ } else {
+ out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+ out->config = pcm_config_low_latency;
+ }
}
if (config->sample_rate == 0) {
@@ -4737,11 +4948,13 @@
} else {
out->sample_rate = config->sample_rate;
}
+
if (config->channel_mask == AUDIO_CHANNEL_NONE) {
out->channel_mask = audio_channel_out_mask_from_count(out->config.channels);
} else {
out->channel_mask = config->channel_mask;
}
+
if (config->format == AUDIO_FORMAT_DEFAULT)
out->format = audio_format_from_pcm_format(out->config.format);
else if (!audio_is_linear_pcm(config->format)) {
@@ -4753,8 +4966,25 @@
}
out->config.rate = out->sample_rate;
- out->config.channels =
- audio_channel_count_from_out_mask(out->channel_mask);
+
+ if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
+ out->config.channels =
+ audio_channel_count_from_out_mask(out->channel_mask &
+ ~AUDIO_CHANNEL_HAPTIC_ALL);
+
+ if (force_haptic_path) {
+ out->config.channels = 1;
+ adev->haptics_config.channels = 1;
+ } else {
+ adev->haptics_config.channels =
+ audio_channel_count_from_out_mask(out->channel_mask &
+ AUDIO_CHANNEL_HAPTIC_ALL);
+ }
+ } else {
+ out->config.channels =
+ audio_channel_count_from_out_mask(out->channel_mask);
+ }
+
if (out->format != audio_format_from_pcm_format(out->config.format)) {
out->config.format = pcm_format_from_audio_format(out->format);
}
@@ -5306,6 +5536,7 @@
in->stream.get_active_microphones = in_get_active_microphones;
in->stream.set_microphone_direction = in_set_microphone_direction;
in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
+ in->stream.update_sink_metadata = in_update_sink_metadata;
in->device = devices;
in->source = source;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index cc24c45..f28505d 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -82,6 +82,7 @@
USECASE_AUDIO_PLAYBACK_TTS,
USECASE_AUDIO_PLAYBACK_ULL,
USECASE_AUDIO_PLAYBACK_MMAP,
+ USECASE_AUDIO_PLAYBACK_WITH_HAPTICS,
/* HFP Use case*/
USECASE_AUDIO_HFP_SCO,
@@ -381,6 +382,13 @@
void *adm_data;
void *adm_lib;
+
+ struct pcm_config haptics_config;
+ struct pcm *haptic_pcm;
+ int haptic_pcm_device_id;
+ uint8_t *haptic_buffer;
+ size_t haptic_buffer_size;
+
adm_init_t adm_init;
adm_deinit_t adm_deinit;
adm_register_input_stream_t adm_register_input_stream;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 7d35ff5..533cf6a 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1401,6 +1401,11 @@
return device_id;
}
+int platform_get_haptics_pcm_device_id()
+{
+ return -1;
+}
+
static int find_index(struct name_to_index * table, int32_t len, const char * name)
{
int ret = 0;
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index be2b95e..6791ad6 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -424,6 +424,11 @@
return device_id;
}
+int platform_get_haptics_pcm_device_id()
+{
+ return -1;
+}
+
int platform_get_snd_device_index(char *snd_device_index_name __unused)
{
return -ENODEV;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f03356b..ecb3db7 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -184,6 +184,8 @@
static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
DEEP_BUFFER_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = {AUDIO_HAPTICS_PCM_DEVICE,
+ AUDIO_HAPTICS_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
@@ -293,6 +295,7 @@
[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO] = "speaker-safe-and-bt-sco",
[SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB] = "speaker-and-bt-sco-wb",
[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_WB] = "speaker-safe-and-bt-sco-wb",
+ [SND_DEVICE_OUT_VOICE_HEARING_AID] = "hearing-aid",
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -372,6 +375,7 @@
[SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = "camcorder-mic",
[SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
[SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
+ [SND_DEVICE_IN_VOICE_HEARING_AID] = "hearing-aid-mic",
};
static struct audio_effect_config \
@@ -444,6 +448,7 @@
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
[SND_DEVICE_OUT_VOICE_SPEAKER_HFP] = ACDB_ID_VOICE_SPEAKER,
+ [SND_DEVICE_OUT_VOICE_HEARING_AID] = 45,
[SND_DEVICE_IN_HANDSET_MIC] = 4,
[SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
@@ -521,6 +526,7 @@
[SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = 61,
[SND_DEVICE_IN_SPEAKER_QMIC_NS] = 129,
[SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
+ [SND_DEVICE_IN_VOICE_HEARING_AID] = 44,
};
// Platform specific backend bit width table
@@ -579,6 +585,7 @@
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
{TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET_SPEC)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEARING_AID)},
/* in */
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
@@ -655,6 +662,8 @@
{TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE)},
{TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE)},
{TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEARING_AID)},
+
/* For legacy xml file parsing */
{TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
@@ -667,6 +676,7 @@
static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_HIFI)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)},
@@ -1285,6 +1295,7 @@
backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
backend_tag_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = strdup("speaker-safe-and-bt-a2dp");
backend_tag_table[SND_DEVICE_OUT_USB_HEADSET_SPEC] = strdup("usb-headset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_HEARING_AID] = strdup("hearing-aid");
hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
@@ -1333,6 +1344,11 @@
hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB] = strdup("SLIMBUS_0_RX-and-SEC_AUX_PCM_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO] = strdup("QUAT_TDM_RX_0-and-SLIMBUS_7_RX"),
hw_interface_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_WB] = strdup("QUAT_TDM_RX_0-and-SLIMBUS_7_RX"),
+ /* So far, primary hal doesn't support hearing aid device.
+ Need snd_device to route voice call and use specific acdb tuning.
+ Also, BT_RX is a virtual port to indicate bluetooth hearing aid. */
+ hw_interface_table[SND_DEVICE_OUT_VOICE_HEARING_AID] = strdup("BT_RX"),
+
hw_interface_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
hw_interface_table[SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
hw_interface_table[SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = strdup("USB_AUDIO_TX");
@@ -1400,6 +1416,8 @@
hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = strdup("SLIMBUS_0_TX");
hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = strdup("SLIMBUS_0_TX");
hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = strdup("SLIMBUS_0_TX");
+ hw_interface_table[SND_DEVICE_IN_VOICE_HEARING_AID] = strdup("SLIMBUS_0_TX");
+
my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
}
@@ -2060,6 +2078,11 @@
return device_id;
}
+int platform_get_haptics_pcm_device_id()
+{
+ return HAPTICS_PCM_DEVICE;
+}
+
static int find_index(const struct name_to_index * table, int32_t len,
const char * name)
{
@@ -2893,8 +2916,11 @@
snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS;
else
snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
- } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+ } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
snd_device = SND_DEVICE_OUT_VOICE_TX;
+ } else if (devices & AUDIO_DEVICE_OUT_HEARING_AID) {
+ snd_device = SND_DEVICE_OUT_VOICE_HEARING_AID;
+ }
if (snd_device != SND_DEVICE_NONE) {
goto exit;
@@ -3186,6 +3212,8 @@
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
}
}
+ } else if (out_device & AUDIO_DEVICE_OUT_HEARING_AID) {
+ snd_device = SND_DEVICE_IN_VOICE_HEARING_AID;
}
} else if (source == AUDIO_SOURCE_CAMCORDER) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
@@ -3702,6 +3730,7 @@
case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
return DEEP_BUFFER_PLATFORM_DELAY;
case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+ case USECASE_AUDIO_PLAYBACK_WITH_HAPTICS:
return LOW_LATENCY_PLATFORM_DELAY;
case USECASE_AUDIO_PLAYBACK_ULL:
return ULL_PLATFORM_DELAY;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index a885f27..c2beec9 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -106,6 +106,7 @@
SND_DEVICE_OUT_VOICE_USB_HEADSET,
/* Specific snd_devices */
SND_DEVICE_OUT_USB_HEADSET_SPEC,
+ SND_DEVICE_OUT_VOICE_HEARING_AID,
SND_DEVICE_OUT_END,
/*
@@ -192,6 +193,7 @@
SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT,
SND_DEVICE_IN_SPEAKER_QMIC_NS,
SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
+ SND_DEVICE_IN_VOICE_HEARING_AID,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -289,6 +291,9 @@
#define LOWLATENCY_PCM_DEVICE 15
#define VOICE_VSID 0x10C01000
+#define AUDIO_HAPTICS_PCM_DEVICE 43
+#define HAPTICS_PCM_DEVICE 44
+
//needs verification
#define AUDIO_PLAYBACK_VOIP_PCM_DEVICE 5
#define AUDIO_RECORD_VOIP_PCM_DEVICE 6
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 5e5b662..46ceceb 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -204,6 +204,7 @@
int platform_get_usb_service_interval(void *platform,
bool playback,
unsigned long *service_interval);
+int platform_get_haptics_pcm_device_id();
/* callback functions from platform to common audio HAL */
struct stream_in *adev_get_active_input(const struct audio_device *adev);