audio: Dedicated usecase for voip call (uplink and downlink)
Add dedicated usecases for voip call.
coauthored-by: Vikram Panduranga <vpandura@codeaurora.org>
Bug: 62393776
Test: hangout call
Change-Id: Iff8911aa8d4f072923e2f2649098a44a4bc4485c
Signed-off-by: David Lin <dtwlin@google.com>
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index eb0f9f6..2fc424c 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -34,14 +34,17 @@
#define MAX_LENGTH_MIXER_CONTROL_IN_INT 128
-static int set_mixer_ctrl(struct audio_device *adev,
- int pcm_device_id, int app_type,
- int acdb_dev_id, int sample_rate, int stream_type)
+static int set_stream_app_type_mixer_ctrl(struct audio_device *adev,
+ int pcm_device_id, int app_type,
+ int acdb_dev_id, int sample_rate,
+ int stream_type,
+ snd_device_t snd_device)
{
char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
struct mixer_ctl *ctl;
int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc = 0;
+ int snd_device_be_idx = -1;
if (stream_type == PCM_PLAYBACK) {
snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
@@ -61,8 +64,14 @@
app_type_cfg[len++] = app_type;
app_type_cfg[len++] = acdb_dev_id;
app_type_cfg[len++] = sample_rate;
- ALOGV("%s: stream type %d app_type %d, acdb_dev_id %d sample rate %d",
- __func__, stream_type, app_type, acdb_dev_id, sample_rate);
+
+ snd_device_be_idx = platform_get_snd_device_backend_index(snd_device);
+ if (snd_device_be_idx > 0)
+ app_type_cfg[len++] = snd_device_be_idx;
+ ALOGV("%s: stream type %d app_type %d, acdb_dev_id %d "
+ "sample rate %d, snd_device_be_idx %d",
+ __func__, stream_type, app_type, acdb_dev_id, sample_rate,
+ snd_device_be_idx);
mixer_ctl_set_array(ctl, app_type_cfg, len);
exit:
@@ -92,6 +101,20 @@
return;
}
+static const char *flags_to_mode(int dir, uint32_t flags)
+{
+ if (dir == 0) {
+ if (flags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
+ return "voip";
+ }
+ } else if (dir == 1) {
+ if (flags & AUDIO_INPUT_FLAG_VOIP_TX) {
+ return "voip";
+ }
+ }
+ return "default";
+}
+
static int audio_extn_utils_send_app_type_cfg_hfp(struct audio_device *adev,
struct audio_usecase *usecase)
{
@@ -134,16 +157,20 @@
goto exit_send_app_type_cfg;
sample_rate= CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
- rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
- acdb_dev_id, sample_rate, PCM_PLAYBACK);
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate,
+ PCM_PLAYBACK,
+ SND_DEVICE_NONE); // use legacy behavior
if (rc < 0)
goto exit_send_app_type_cfg;
/* config HFP session:1 capture path */
rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
if (rc == 0) {
- rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
- acdb_dev_id, sample_rate, PCM_CAPTURE);
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate,
+ PCM_CAPTURE,
+ SND_DEVICE_NONE);
if (rc < 0)
goto exit_send_app_type_cfg;
}
@@ -158,8 +185,9 @@
}
rc = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE, &app_type);
if (rc == 0) {
- rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
- acdb_dev_id, sample_rate, PCM_CAPTURE);
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate, PCM_CAPTURE,
+ SND_DEVICE_NONE);
if (rc < 0)
goto exit_send_app_type_cfg;
}
@@ -167,8 +195,9 @@
/* config HFP session:2 playback path */
rc = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK, &app_type);
if (rc == 0) {
- rc = set_mixer_ctrl(adev, pcm_device_id, app_type,
- acdb_dev_id, sample_rate, PCM_PLAYBACK);
+ rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
+ acdb_dev_id, sample_rate,
+ PCM_PLAYBACK, SND_DEVICE_NONE);
if (rc < 0)
goto exit_send_app_type_cfg;
}
@@ -179,93 +208,185 @@
return rc;
}
-int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
- struct audio_usecase *usecase)
+
+static int derive_capture_app_type_cfg(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ int *app_type,
+ int *sample_rate)
{
- int len = 0;
- if (usecase->type == PCM_HFP_CALL) {
- return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
+ struct stream_in *in = usecase->stream.in;
+ struct stream_app_type_cfg *app_type_cfg = &in->app_type_cfg;
+
+ *sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
+ if (in->device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ platform_check_and_update_copp_sample_rate(adev->platform,
+ usecase->in_snd_device,
+ in->sample_rate,
+ sample_rate);
}
- if (usecase->type != PCM_PLAYBACK || !platform_supports_app_type_cfg())
- return -1;
-
- size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
- int pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
-
- char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
- snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
- "Audio Stream %d App Type Cfg", pcm_device_id);
- struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
- mixer_ctl_name);
- return -EINVAL;
- }
-
- snd_device_t snd_device = usecase->out_snd_device; // add speaker prot changes if needed
- int acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
- if (acdb_dev_id <= 0) {
- ALOGE("%s: Couldn't get the acdb dev id", __func__);
- return -1;
- }
-
- if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
- usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
- } else if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||
- snd_device == SND_DEVICE_OUT_USB_HEADPHONES) {
- platform_check_and_update_copp_sample_rate(adev->platform, snd_device,
- usecase->stream.out->sample_rate,
- &usecase->stream.out->app_type_cfg.sample_rate);
- }
-
- int32_t sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
- int app_type;
- if (!audio_is_linear_pcm(usecase->stream.out->format)) {
- platform_get_default_app_type_v2(adev->platform,
- PCM_PLAYBACK,
- &app_type);
- } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_16_BIT) {
+ app_type_cfg->mode = flags_to_mode(1 /*capture*/, in->flags);
+ ALOGV("%s mode %s", __func__, app_type_cfg->mode);
+ if (in->format == AUDIO_FORMAT_PCM_16_BIT) {
platform_get_app_type_v2(adev->platform,
+ PCM_CAPTURE,
+ app_type_cfg->mode,
16,
- sample_rate,
- PCM_PLAYBACK,
- &app_type);
- } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
- usecase->stream.out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ app_type_cfg->sample_rate,
+ app_type);
+ } else if (in->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+ in->format == AUDIO_FORMAT_PCM_8_24_BIT) {
platform_get_app_type_v2(adev->platform,
+ PCM_CAPTURE,
+ app_type_cfg->mode,
24,
- sample_rate,
- PCM_PLAYBACK,
- &app_type);
- } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_32_BIT) {
+ app_type_cfg->sample_rate,
+ app_type);
+ } else if (in->format == AUDIO_FORMAT_PCM_32_BIT) {
platform_get_app_type_v2(adev->platform,
+ PCM_CAPTURE,
+ app_type_cfg->mode,
32,
- sample_rate,
- PCM_PLAYBACK,
- &app_type);
+ app_type_cfg->sample_rate,
+ app_type);
} else {
ALOGE("%s bad format\n", __func__);
return -1;
}
- //XXX this would be set somewhere else
- usecase->stream.out->app_type_cfg.app_type = app_type;
- app_type_cfg[len++] = app_type;
- app_type_cfg[len++] = acdb_dev_id;
- app_type_cfg[len++] = sample_rate;
-
- // add be_idx once available
- // if (snd_device_be_idx > 0)
- // app_type_cfg[len++] = snd_device_be_idx;
-
- ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
- __func__, app_type, acdb_dev_id, sample_rate);
-
- mixer_ctl_set_array(ctl, app_type_cfg, len);
+ app_type_cfg->app_type = *app_type;
+ app_type_cfg->sample_rate = *sample_rate;
return 0;
}
+static int derive_playback_app_type_cfg(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ int *app_type,
+ int *sample_rate)
+{
+ struct stream_out *out = usecase->stream.out;
+ struct stream_app_type_cfg *app_type_cfg = &out->app_type_cfg;
+
+ *sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+
+ // add speaker prot changes if needed
+ // and use that to check for device
+ if (out->devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
+ platform_check_and_update_copp_sample_rate(adev->platform,
+ usecase->out_snd_device,
+ out->sample_rate,
+ sample_rate);
+ }
+
+ app_type_cfg->mode = flags_to_mode(0 /*playback*/, out->flags);
+ if (!audio_is_linear_pcm(out->format)) {
+ platform_get_default_app_type_v2(adev->platform,
+ PCM_PLAYBACK,
+ app_type);
+ } else if (out->format == AUDIO_FORMAT_PCM_16_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ PCM_PLAYBACK,
+ app_type_cfg->mode,
+ 16,
+ *sample_rate,
+ app_type);
+ } else if (out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+ out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ PCM_PLAYBACK,
+ app_type_cfg->mode,
+ 24,
+ *sample_rate,
+ app_type);
+ } else if (out->format == AUDIO_FORMAT_PCM_32_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ PCM_PLAYBACK,
+ app_type_cfg->mode,
+ 32,
+ *sample_rate,
+ app_type);
+ } else {
+ ALOGE("%s bad format\n", __func__);
+ return -1;
+ }
+
+ app_type_cfg->app_type = *app_type;
+ app_type_cfg->sample_rate = *sample_rate;
+ return 0;
+}
+
+static int derive_acdb_dev_id(struct audio_device *adev __unused,
+ struct audio_usecase *usecase)
+{
+ struct stream_out *out;
+ struct stream_in *in;
+
+ if (usecase->type == PCM_PLAYBACK) {
+ return platform_get_snd_device_acdb_id(usecase->out_snd_device);
+ } else if(usecase->type == PCM_CAPTURE) {
+ return platform_get_snd_device_acdb_id(usecase->in_snd_device);
+ }
+ return -1;
+}
+
+int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+ struct audio_usecase *usecase)
+{
+ int len = 0;
+ int sample_rate;
+ int app_type;
+ int acdb_dev_id;
+ size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int pcm_device_id;
+ struct mixer_ctl *ctl;
+ int ret;
+
+ if (usecase->type == PCM_HFP_CALL) {
+ return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
+ }
+
+ if (!platform_supports_app_type_cfg())
+ return -1;
+
+ if (usecase->type == PCM_PLAYBACK) {
+ ret = derive_playback_app_type_cfg(adev,
+ usecase,
+ &app_type,
+ &sample_rate);
+ } else if (usecase->type == PCM_CAPTURE) {
+ ret = derive_capture_app_type_cfg(adev,
+ usecase,
+ &app_type,
+ &sample_rate);
+ } else {
+ ALOGE("%s: Invalid uc type : 0x%x", __func__, usecase->type);
+ return -1;
+ }
+
+ if (ret < 0) {
+ ALOGE("%s: Failed to derive app_type for uc type : 0x%x", __func__,
+ usecase->type);
+ return -1;
+ }
+
+ acdb_dev_id = derive_acdb_dev_id(adev, usecase);
+ if (acdb_dev_id <= 0) {
+ ALOGE("%s: Couldn't get the acdb dev id", __func__);
+ return -1;
+ }
+
+ pcm_device_id = platform_get_pcm_device_id(usecase->id, usecase->type);
+ set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type, acdb_dev_id,
+ sample_rate,
+ usecase->type,
+ usecase->type == PCM_PLAYBACK ? usecase->out_snd_device :
+ usecase->in_snd_device);
+ return 0;
+}
+
+// this assumes correct app_type and sample_rate fields
+// have been set for the stream using audio_extn_utils_send_app_type_cfg
void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
struct audio_usecase *usecase)
{
@@ -274,24 +395,25 @@
if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
struct stream_out *out = usecase->stream.out;
- ALOGV("%s send cal for app_type %d, rate %d", __func__, out->app_type_cfg.app_type,
- usecase->stream.out->app_type_cfg.sample_rate);
+ ALOGV("%s send cal for app_type %d, rate %d", __func__,
+ out->app_type_cfg.app_type,
+ out->app_type_cfg.sample_rate);
platform_send_audio_calibration_v2(adev->platform, usecase,
- out->app_type_cfg.app_type,
- usecase->stream.out->app_type_cfg.sample_rate);
+ out->app_type_cfg.app_type,
+ out->app_type_cfg.sample_rate);
} else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
- // TBD
- // platform_send_audio_calibration_v2(adev->platform, usecase,
- // usecase->stream.in->app_type_cfg.app_type,
- // usecase->stream.in->app_type_cfg.sample_rate);
- // uncomment these once send_app_type_cfg and the config entries for
- // non-16 bit capture are figured out.
- platform_get_default_app_type_v2(adev->platform, type, &app_type);
- platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+ struct stream_in *in = usecase->stream.in;
+ ALOGV("%s send cal for capture app_type %d, rate %d", __func__,
+ in->app_type_cfg.app_type,
+ in->app_type_cfg.sample_rate);
+ platform_send_audio_calibration_v2(adev->platform, usecase,
+ in->app_type_cfg.app_type,
+ in->app_type_cfg.sample_rate);
} else {
/* when app type is default. the sample rate is not used to send cal */
platform_get_default_app_type_v2(adev->platform, type, &app_type);
- platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+ platform_send_audio_calibration_v2(adev->platform, usecase, app_type,
+ 48000);
}
}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index cca56ec..44a0216 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -67,6 +67,7 @@
/* ToDo: Check and update a proper value in msec */
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define VOIP_PLAYBACK_VOLUME_MAX 0x2000
#define PROXY_OPEN_RETRY_COUNT 100
#define PROXY_OPEN_WAIT_TIME 20
@@ -204,6 +205,14 @@
.avail_min = MMAP_PERIOD_SIZE, //1 ms
};
+struct pcm_config pcm_config_voip = {
+ .channels = 1,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
#define AFE_PROXY_CHANNEL_COUNT 2
#define AFE_PROXY_SAMPLING_RATE 48000
@@ -270,6 +279,8 @@
[USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
[USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+ [USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
+ [USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
};
@@ -1440,7 +1451,6 @@
error_config:
adev->active_input = NULL;
ALOGW("%s: exit: status(%d)", __func__, ret);
-
return ret;
}
@@ -1896,17 +1906,18 @@
return 0;
}
-static size_t get_input_buffer_size(uint32_t sample_rate,
- audio_format_t format,
- int channel_count,
- bool is_low_latency)
+static size_t get_stream_buffer_size(size_t duration_ms,
+ uint32_t sample_rate,
+ audio_format_t format,
+ int channel_count,
+ bool is_low_latency)
{
size_t size = 0;
if (check_input_parameters(sample_rate, format, channel_count) != 0)
return 0;
- size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+ size = (sample_rate * duration_ms) / 1000;
if (is_low_latency)
size = configured_low_latency_capture_period_size;
@@ -2366,6 +2377,23 @@
volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
return 0;
+ } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
+ int gain_cfg[4];
+ const char *mixer_ctl_name = "App Type Gain";
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get volume ctl mixer %s", __func__,
+ mixer_ctl_name);
+ return -EINVAL;
+ }
+ gain_cfg[0] = 0;
+ gain_cfg[1] = out->app_type_cfg.app_type;
+ gain_cfg[2] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
+ gain_cfg[3] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
+ mixer_ctl_set_array(ctl, gain_cfg, sizeof(gain_cfg)/sizeof(gain_cfg[0]));
+ return 0;
}
return -ENOSYS;
@@ -2900,7 +2928,6 @@
static size_t in_get_buffer_size(const struct audio_stream *stream)
{
struct stream_in *in = (struct stream_in *)stream;
-
return in->config.period_size * in->af_period_multiplier *
audio_stream_in_frame_size((const struct audio_stream_in *)stream);
}
@@ -3572,6 +3599,27 @@
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
out->config = pcm_config_afe_proxy_playback;
adev->voice_tx_output = out;
+ } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT |
+ AUDIO_OUTPUT_FLAG_VOIP_RX))) {
+ uint32_t buffer_size, frame_size;
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+ out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
+ out->config = pcm_config_voip;
+ out->config.format = pcm_format_from_audio_format(config->format);
+ out->config.rate = config->sample_rate;
+ out->config.channels =
+ audio_channel_count_from_out_mask(config->channel_mask);
+ buffer_size = get_stream_buffer_size(VOIP_PLAYBACK_PERIOD_DURATION_MSEC,
+ config->sample_rate,
+ config->format,
+ out->config.channels,
+ false /*is_low_latency*/);
+ frame_size = audio_bytes_per_sample(config->format) * out->config.channels;
+ out->config.period_size = buffer_size / frame_size;
+ out->config.period_count = VOIP_PLAYBACK_PERIOD_COUNT;
+ out->af_period_multiplier = 1;
} else {
if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
@@ -3983,8 +4031,10 @@
{
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
- return get_input_buffer_size(config->sample_rate, config->format, channel_count,
- false /* is_low_latency: since we don't know, be conservative */);
+ return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
+ config->sample_rate, config->format,
+ channel_count,
+ false /* is_low_latency: since we don't know, be conservative */);
}
static bool adev_input_allow_hifi_record(struct audio_device *adev,
@@ -4161,10 +4211,11 @@
in->usecase = USECASE_AUDIO_RECORD_HIFI;
in->config = pcm_config_audio_capture;
frame_size = audio_stream_in_frame_size(&in->stream);
- buffer_size = get_input_buffer_size(config->sample_rate,
- config->format,
- channel_count,
- false /*is_low_latency*/);
+ buffer_size = get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
+ config->sample_rate,
+ config->format,
+ channel_count,
+ false /*is_low_latency*/);
in->config.period_size = buffer_size / frame_size;
in->config.rate = config->sample_rate;
in->af_period_multiplier = 1;
@@ -4181,10 +4232,11 @@
if (!in->realtime) {
in->config = pcm_config_audio_capture;
frame_size = audio_stream_in_frame_size(&in->stream);
- buffer_size = get_input_buffer_size(config->sample_rate,
- config->format,
- channel_count,
- is_low_latency);
+ buffer_size = get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
+ config->sample_rate,
+ config->format,
+ channel_count,
+ is_low_latency);
in->config.period_size = buffer_size / frame_size;
in->config.rate = config->sample_rate;
in->af_period_multiplier = 1;
@@ -4204,13 +4256,33 @@
in->stream.get_mmap_position = in_get_mmap_position;
in->af_period_multiplier = 1;
ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
+ } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
+ in->dev->mode == AUDIO_MODE_IN_COMMUNICATION &&
+ (config->sample_rate == 8000 ||
+ config->sample_rate == 16000 ||
+ config->sample_rate == 32000 ||
+ config->sample_rate == 48000) &&
+ channel_count == 1) {
+ in->usecase = USECASE_AUDIO_RECORD_VOIP;
+ in->config = pcm_config_audio_capture;
+ frame_size = audio_stream_in_frame_size(&in->stream);
+ buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
+ config->sample_rate,
+ config->format,
+ channel_count, false /*is_low_latency*/);
+ in->config.period_size = buffer_size / frame_size;
+ in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
+ in->config.rate = config->sample_rate;
+ in->af_period_multiplier = 1;
+ in->flags |= AUDIO_INPUT_FLAG_VOIP_TX;
} else {
in->config = pcm_config_audio_capture;
frame_size = audio_stream_in_frame_size(&in->stream);
- buffer_size = get_input_buffer_size(config->sample_rate,
- config->format,
- channel_count,
- is_low_latency);
+ buffer_size = get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
+ config->sample_rate,
+ config->format,
+ channel_count,
+ is_low_latency);
in->config.period_size = buffer_size / frame_size;
in->config.rate = config->sample_rate;
in->af_period_multiplier = 1;
@@ -4220,6 +4292,7 @@
}
in->config.channels = channel_count;
+ in->sample_rate = in->config.rate;
/* This stream could be for sound trigger lab,
get sound trigger pcm if present */
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index b1e5e45..28bf19b 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -132,6 +132,10 @@
USECASE_AUDIO_RECORD_AFE_PROXY,
USECASE_AUDIO_DSM_FEEDBACK,
+ /* VOIP usecase*/
+ USECASE_AUDIO_PLAYBACK_VOIP,
+ USECASE_AUDIO_RECORD_VOIP,
+
AUDIO_USECASE_MAX
};
@@ -170,7 +174,8 @@
struct stream_app_type_cfg {
int sample_rate;
- uint32_t bit_width;
+ uint32_t bit_width; // unused
+ const char *mode;
int app_type;
};
@@ -198,7 +203,6 @@
bool muted;
uint64_t written; /* total frames written, not cleared when entering standby */
audio_io_handle_t handle;
- struct stream_app_type_cfg app_type_cfg;
int non_blocking;
int playback_started;
@@ -219,6 +223,8 @@
error_log_t *error_log;
power_log_t *power_log;
+
+ struct stream_app_type_cfg app_type_cfg;
};
struct stream_in {
@@ -232,6 +238,7 @@
int pcm_device_id;
audio_devices_t device;
audio_channel_mask_t channel_mask;
+ unsigned int sample_rate;
audio_usecase_t usecase;
bool enable_aec;
bool enable_ns;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index aa3419d..6d92d93 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2322,12 +2322,16 @@
bool platform_supports_app_type_cfg() { return false; }
-void platform_add_app_type(int bw __unused, const char *uc_type __unused,
- int app_type __unused, int max_sr __unused) {}
+void platform_add_app_type(const char *uc_type __unused,
+ const char *mode __unused,
+ int bw __unused, int app_type __unused,
+ int max_sr __unused) {}
int platform_get_app_type_v2(void *platform __unused,
enum usecase_type_t type __unused,
+ const char *mode __unused,
int bw __unused, int sr __unused,
int *app_type __unused) {
return -ENOSYS;
}
+
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 07dc1af..69bfd62 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -194,6 +194,12 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define VOIP_CAPTURE_PERIOD_DURATION_MSEC 20
+#define VOIP_CAPTURE_PERIOD_COUNT 2
+
+#define VOIP_PLAYBACK_PERIOD_DURATION_MSEC 20
+#define VOIP_PLAYBACK_PERIOD_COUNT 2
+
#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
#define LOW_LATENCY_CAPTURE_USE_CASE 1
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index cfae645..cd7305d 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1153,11 +1153,19 @@
bool platform_supports_app_type_cfg() { return false; }
-void platform_add_app_type(int bw, const char *uc_type,
- int app_type, int max_sr) {}
+void platform_add_app_type(const char *uc_type __unused,
+ const char *mode __unused,
+ int bw __unused, int app_type __unused,
+ int max_sr __unused) {}
+int platform_get_app_type_v2(void *platform __unused,
+ enum usecase_type_t type __unused,
+ const char *mode __unused,
+ int bw __unused, int sr __unused,
+ int *app_type __unused) {
+ return -ENOSYS;
+}
-int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
- int bw, int sr, int *app_type) {
+int platform_get_snd_device_backend_index(snd_device_t snd_device) {
return -ENOSYS;
}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 0835378..1276b73 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -119,6 +119,12 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define VOIP_CAPTURE_PERIOD_DURATION_MSEC 20
+#define VOIP_CAPTURE_PERIOD_COUNT 2
+
+#define VOIP_PLAYBACK_PERIOD_DURATION_MSEC 20
+#define VOIP_PLAYBACK_PERIOD_COUNT 2
+
#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
#define LOW_LATENCY_CAPTURE_USE_CASE 0
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 02512ea..72f9937 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -196,6 +196,10 @@
AFE_PROXY_RECORD_PCM_DEVICE},
[USECASE_AUDIO_DSM_FEEDBACK] = {QUAT_MI2S_PCM_DEVICE, QUAT_MI2S_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_VOIP] = {AUDIO_PLAYBACK_VOIP_PCM_DEVICE,
+ AUDIO_PLAYBACK_VOIP_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_VOIP] = {AUDIO_RECORD_VOIP_PCM_DEVICE,
+ AUDIO_RECORD_VOIP_PCM_DEVICE},
};
/* Array to store sound devices */
@@ -573,6 +577,8 @@
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_DSM_FEEDBACK)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_VOIP)},
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD_VOIP)},
};
static const struct name_to_index usecase_type_index[USECASE_TYPE_MAX] = {
@@ -587,6 +593,7 @@
int bit_width;
int app_type;
int max_rate;
+ char *mode;
struct listnode node; // membership in app_type_entry_list;
};
@@ -722,6 +729,8 @@
int mode = CAL_MODE_RTAC;
struct listnode *node;
struct audio_usecase *usecase;
+ bool valid_uc_type = false;
+ bool valid_dev = false;
if (my_data->acdb_send_gain_dep_cal == NULL) {
ALOGE("%s: dlsym error for acdb_send_gain_dep_cal", __func__);
@@ -736,19 +745,20 @@
// find the current active sound device
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
-
- if (usecase != NULL &&
- usecase->type == PCM_PLAYBACK &&
- (usecase->stream.out->devices == AUDIO_DEVICE_OUT_SPEAKER)) {
-
- ALOGV("%s: out device is %d", __func__, usecase->out_snd_device);
- if (audio_extn_spkr_prot_is_enabled()) {
+ valid_uc_type = usecase->type == PCM_PLAYBACK;
+ audio_devices_t dev = usecase->stream.out->devices;
+ valid_dev = (dev == AUDIO_DEVICE_OUT_SPEAKER ||
+ dev == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ dev == AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
+ if (usecase != NULL && valid_uc_type && valid_dev) {
+ ALOGV("%s: out device is %d", __func__, usecase->out_snd_device);
+ if (audio_extn_spkr_prot_is_enabled()) {
acdb_dev_id = audio_extn_spkr_prot_get_acdb_id(usecase->out_snd_device);
- } else {
- acdb_dev_id = acdb_device_table[usecase->out_snd_device];
- }
+ } else {
+ acdb_dev_id = acdb_device_table[usecase->out_snd_device];
+ }
- if (!my_data->acdb_send_gain_dep_cal(acdb_dev_id, app_type,
+ if (!my_data->acdb_send_gain_dep_cal(acdb_dev_id, app_type,
acdb_dev_type, mode, level)) {
// set ret_val true if at least one calibration is set successfully
ret_val = true;
@@ -1540,6 +1550,7 @@
node = list_head(&app_type_entry_list);
list_remove(node);
ap = node_to_item(node, struct app_type_entry, node);
+ if (ap->mode) free(ap->mode);
free(ap);
}
@@ -3050,7 +3061,9 @@
ALOGE("%s: invalid usecase type", __func__);
ret = -EINVAL;
}
- ALOGV("%s: pcm_device_table[%d][%d] = %d", __func__, usecase, type, pcm_id);
+ ALOGV("%s: pcm_device_table[%d %s][%d] = %d", __func__, usecase,
+ use_case_table[usecase],
+ type, pcm_id);
pcm_device_table[usecase][type] = pcm_id;
done:
return ret;
@@ -3748,7 +3761,8 @@
goto done;
}
- posix_memalign((void **)&be_dai_name_table, 32, size);
+ be_dai_name_table =
+ (const struct be_dai_name_struct *)calloc(1, size);
if (be_dai_name_table == NULL) {
ALOGE("%s: Failed to allocate memory for %s\n",
__func__, mixer_ctl_name);
@@ -3821,7 +3835,7 @@
ALOGV("%s: enter with device %d\n", __func__, device);
- if ((device <= SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
ALOGE("%s: Invalid snd_device = %d",
__func__, device);
be_dai_id = -EINVAL;
@@ -3885,7 +3899,9 @@
}
// called from info parser
-void platform_add_app_type(int bw, const char *uc_type,
+void platform_add_app_type(const char *uc_type,
+ const char *mode,
+ int bw,
int app_type, int max_rate) {
struct app_type_entry *ap =
(struct app_type_entry *)calloc(1, sizeof(struct app_type_entry));
@@ -3908,11 +3924,12 @@
return;
}
- ALOGI("%s bw %d uc %s app_type %d max_rate %d",
- __func__, bw, uc_type, app_type, max_rate);
+ ALOGI("%s uc %s mode %s bw %d app_type %d max_rate %d",
+ __func__, uc_type, mode, bw, app_type, max_rate);
ap->bit_width = bw;
ap->app_type = app_type;
ap->max_rate = max_rate;
+ ap->mode = strdup(mode);
list_add_tail(&app_type_entry_list, &ap->node);
}
@@ -3928,23 +3945,35 @@
return 0;
}
-int platform_get_app_type_v2(void *platform, usecase_type_t uc_type,
+int platform_get_app_type_v2(void *platform,
+ usecase_type_t uc_type,
+ const char *mode,
int bw, int sr __unused,
int *app_type)
{
struct listnode *node;
struct app_type_entry *entry;
*app_type = -1;
+
+ ALOGV("%s find match for uc %d mode %s bw %d rate %d",
+ __func__, uc_type, mode, bw, sr);
list_for_each(node, &app_type_entry_list) {
entry = node_to_item(node, struct app_type_entry, node);
+ ALOGV("%s uc %d mode %s bw %d app_type %d max_rate %d",
+ __func__, entry->uc_type, entry->mode, entry->bit_width,
+ entry->app_type, entry->max_rate);
if (entry->bit_width == bw &&
- entry->uc_type == uc_type) {
+ entry->uc_type == uc_type &&
+ sr <= entry->max_rate &&
+ entry->mode && !strcmp(mode, entry->mode)) {
+ ALOGV("%s found match %d", __func__, entry->app_type);
*app_type = entry->app_type;
break;
}
}
if (*app_type == -1) {
+ ALOGV("%s no match found, return default", __func__);
return platform_get_default_app_type_v2(platform, uc_type, app_type);
}
return 0;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 9df8a1d..4692560 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -182,7 +182,7 @@
};
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
#define OUTPUT_SAMPLING_RATE_44100 44100
-#define DEFAULT_INPUT_SAMPLING_RATE 48000
+#define DEFAULT_INPUT_SAMPLING_RATE 48000
enum {
DEFAULT_CODEC_BACKEND,
@@ -245,6 +245,12 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define VOIP_CAPTURE_PERIOD_DURATION_MSEC 20
+#define VOIP_CAPTURE_PERIOD_COUNT 2
+
+#define VOIP_PLAYBACK_PERIOD_DURATION_MSEC 20
+#define VOIP_PLAYBACK_PERIOD_COUNT 2
+
#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
#define LOW_LATENCY_CAPTURE_USE_CASE 1
@@ -266,6 +272,10 @@
#define LOWLATENCY_PCM_DEVICE 15
#define VOICE_VSID 0x10C01000
+//needs verification
+#define AUDIO_PLAYBACK_VOIP_PCM_DEVICE 5
+#define AUDIO_RECORD_VOIP_PCM_DEVICE 6
+
#ifdef PLATFORM_MSM8x26
#define VOICE_CALL_PCM_DEVICE 2
#define VOICE2_CALL_PCM_DEVICE 14
diff --git a/hal/platform_api.h b/hal/platform_api.h
index c51c492..98e4223 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -51,7 +51,7 @@
int platform_get_snd_device_acdb_id(snd_device_t snd_device);
int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
- int app_type, int sample_rate);
+ int app_type, int sample_rate);
int platform_get_default_app_type_v2(void *platform, enum usecase_type_t type, int *app_type);
int platform_switch_voice_call_device_pre(void *platform);
int platform_switch_voice_call_enable_device_config(void *platform,
@@ -134,7 +134,12 @@
unsigned int stream_sr,int *sample_rate);
int platform_get_snd_device_backend_index(snd_device_t snd_device);
bool platform_supports_app_type_cfg();
-int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
+int platform_get_app_type_v2(void *platform,
+ enum usecase_type_t type,
+ const char *mode,
int bw, int sr, int *app_type);
-void platform_add_app_type(int bw, const char *uc_type, int app_type, int max_sr);
+void platform_add_app_type(const char *uc_type,
+ const char *mode,
+ int bw, int app_type, int max_sr);
+int platform_get_snd_device_backend_index(snd_device_t snd_device);
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index cd2b5d4..283936e 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -320,22 +320,28 @@
goto done;
}
- if (strcmp(attr[2], "bit_width")) {
+ if (strcmp(attr[2], "mode")) {
+ ALOGE("%s: mode not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[4], "bit_width")) {
ALOGE("%s: bit_width not found", __func__);
goto done;
}
- if (strcmp(attr[4], "id")) {
+ if (strcmp(attr[6], "id")) {
ALOGE("%s: id not found", __func__);
goto done;
}
- if (strcmp(attr[6], "max_rate")) {
+ if (strcmp(attr[8], "max_rate")) {
ALOGE("%s: max rate not found", __func__);
goto done;
}
- platform_add_app_type(atoi(attr[3]), attr[1], atoi(attr[5]), atoi(attr[7]));
+ platform_add_app_type(attr[1], attr[3], atoi(attr[5]), atoi(attr[7]),
+ atoi(attr[9]));
done:
return;
}
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index 5494fd0..54226b7 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -43,6 +43,7 @@
i == RING?"RING": \
i == ALARM?"ALARM": \
i == VOICE_CALL?"Voice_call": \
+ i == VC_CALL ?"VC_call": \
i == NOTIFICATION?"Notification":\
"--INVALID--"); \
@@ -72,6 +73,7 @@
RING,
ALARM,
VOICE_CALL,
+ VC_CALL,
NOTIFICATION,
MAX_STREAM_TYPES,
};
@@ -206,6 +208,8 @@
static const char *primary_audio_hal_path[] =
{"/vendor/lib/hw/", "/system/lib/hw/"};
+static bool headset_cal_enabled;
+
/*
* Local functions
*/
@@ -225,6 +229,7 @@
context->stream_type == RING ? "RING" :
context->stream_type == ALARM ? "ALARM" :
context->stream_type == VOICE_CALL ? "VOICE_CALL" :
+ context->stream_type == VC_CALL ? "VC_CALL" :
context->stream_type == NOTIFICATION ? "NOTIFICATION" : "--INVALID--",
context->dev_id, context->state, context->session_id, context->left_vol,context->right_vol);
}
@@ -232,6 +237,20 @@
ALOGW("DUMP_END :: ===========");
}
+static inline bool valid_dev_in_context(struct vol_listener_context_s *context)
+{
+ if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER)
+ return true;
+
+ if (context->stream_type == VC_CALL && headset_cal_enabled &&
+ (context->dev_id == AUDIO_DEVICE_OUT_EARPIECE ||
+ context->dev_id == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ context->dev_id == AUDIO_DEVICE_OUT_WIRED_HEADPHONE))
+ return true;
+
+ return false;
+}
+
static void check_and_set_gain_dep_cal()
{
// iterate through list and make decision to set new gain dep cal level for speaker device
@@ -257,7 +276,7 @@
list_for_each(node, &vol_effect_list) {
context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
if ((context->state == VOL_LISTENER_STATE_ACTIVE) &&
- (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER)) {
+ valid_dev_in_context(context)) {
sum_energy_used = true;
temp_vol = fmax(context->left_vol, context->right_vol);
sum_energy += temp_vol * temp_vol;
@@ -437,8 +456,8 @@
// After changing the state and if device is speaker
// recalculate gain dep cal level
- if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
- check_and_set_gain_dep_cal();
+ if (valid_dev_in_context(context)) {
+ check_and_set_gain_dep_cal();
}
break;
@@ -464,7 +483,7 @@
// After changing the state and if device is speaker
// recalculate gain dep cal level
- if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+ if (valid_dev_in_context(context)) {
check_and_set_gain_dep_cal();
}
@@ -495,8 +514,8 @@
__func__, context->dev_id, new_device);
// check if old or new device is speaker
- if ((context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) ||
- (new_device == AUDIO_DEVICE_OUT_SPEAKER)) {
+ if (valid_dev_in_context(context) ||
+ new_device == AUDIO_DEVICE_OUT_SPEAKER) {
recompute_gain_dep_cal_Level = true;
}
@@ -521,7 +540,7 @@
goto exit;
}
- if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+ if (valid_dev_in_context(context)) {
recompute_gain_dep_cal_Level = true;
}
@@ -649,13 +668,8 @@
}
}
- // check system property to see if dumping is required
- char check_dump_val[PROPERTY_VALUE_MAX];
- property_get("audio.volume.listener.dump", check_dump_val, "0");
- if (atoi(check_dump_val)) {
- dumping_enabled = true;
- }
-
+ dumping_enabled = property_get_bool("audio.volume.listener.dump", false);
+ headset_cal_enabled = property_get_bool("audio.volume.headset.gain.depcal", false);
init_status = 0;
list_init(&vol_effect_list);
initialized = true;
@@ -763,7 +777,7 @@
ALOGV("--- Found something to remove ---");
list_remove(node);
PRINT_STREAM_TYPE(context->stream_type);
- if (context->dev_id == AUDIO_DEVICE_OUT_SPEAKER) {
+ if (valid_dev_in_context(context)) {
recompute_flag = true;
}
free(context);