hal: Support for FLAC 24 bit format in offload path
- Add flac in supported codecs list
- Set FLAC codec specific parameters
- Set fragment size based on bit width and sampling rate
for flac
- Configure backend to 24/16 bit based on the current
usecases running
Change-Id: If013078e277fd3053fba6489345803f8f58bd86d
diff --git a/hal/Android.mk b/hal/Android.mk
index 3d6559e..d6f07fa 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -137,6 +137,10 @@
LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED
endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true)
+ LOCAL_CFLAGS += -DQTI_FLAC_DECODER
+endif
+
LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index a858028..7ce1c3a 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -51,6 +51,16 @@
#define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000)
#endif
+#ifndef QTI_FLAC_DECODER
+#define AUDIO_FORMAT_FLAC 0x19000000UL
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"
+#define PCM_OUTPUT_BIT_WIDTH (CODEC_BACKEND_DEFAULT_BIT_WIDTH)
+#else
+#define PCM_OUTPUT_BIT_WIDTH (config->offload_info.bit_width)
+#endif
#define MAX_LENGTH_MIXER_CONTROL_IN_INT (128)
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 0faf8dd..87ea0d3 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -125,7 +125,7 @@
[USECASE_AUDIO_HFP_SCO] = "hfp-sco",
[USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
[USECASE_VOICE_CALL] = "voice-call",
-
+
[USECASE_VOICE2_CALL] = "voice2-call",
[USECASE_VOLTE_CALL] = "volte-call",
[USECASE_QCHAT_CALL] = "qchat-call",
@@ -209,7 +209,8 @@
if (format == AUDIO_FORMAT_MP3 ||
format == AUDIO_FORMAT_AAC ||
format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
- format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
+ format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
+ format == AUDIO_FORMAT_FLAC)
return true;
return false;
@@ -230,6 +231,9 @@
case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
id = SND_AUDIOCODEC_PCM;
break;
+ case AUDIO_FORMAT_FLAC:
+ id = SND_AUDIOCODEC_FLAC;
+ break;
default:
ALOGE("%s: Unsupported audio format :%x", __func__, format);
}
@@ -447,6 +451,15 @@
* because of the limitation that both the devices cannot be enabled
* at the same time as they share the same backend.
*/
+ /*
+ * This call is to check if we need to force routing for a particular stream
+ * If there is a backend configuration change for the device when a
+ * new stream starts, then ADM needs to be closed and re-opened with the new
+ * configuraion. This call check if we need to re-route all the streams
+ * associated with the backend. Touch tone + 24 bit playback.
+ */
+ bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info);
+
/* Disable all the usecases on the shared backend other than the
specified usecase */
for (i = 0; i < AUDIO_USECASE_MAX; i++)
@@ -456,7 +469,7 @@
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->type != PCM_CAPTURE &&
usecase != uc_info &&
- usecase->out_snd_device != snd_device &&
+ (usecase->out_snd_device != snd_device || force_routing) &&
usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
@@ -1501,6 +1514,29 @@
out->send_new_metadata = 1;
}
+ if (out->format == AUDIO_FORMAT_FLAC) {
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ }
+
ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
if(ret >= 0)
is_meta_data_params = true;
@@ -2335,6 +2371,7 @@
out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
out->handle = handle;
+ out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
/* Init use case and pcm_config */
if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
@@ -2409,6 +2446,7 @@
out->stream.resume = out_resume;
out->stream.drain = out_drain;
out->stream.flush = out_flush;
+ out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
if (audio_extn_is_dolby_format(config->offload_info.format))
out->compr_config.codec->id =
@@ -2432,13 +2470,26 @@
out->compr_config.codec->ch_in =
popcount(config->channel_mask);
out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
- out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
+ out->bit_width = PCM_OUTPUT_BIT_WIDTH;
+ if (config->offload_info.format == AUDIO_FORMAT_AAC)
+ out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
- else if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
+ if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+ if (out->bit_width == 24) {
+ out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+ }
+
+ if (out->bit_width == 24 && !platform_check_24_bit_support()) {
+ ALOGW("24 bit support is not enabled, using 16 bit backend");
+ out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
+ }
+
+ out->compr_config.codec->options.flac_dec.sample_size = out->bit_width;
+
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
out->non_blocking = 1;
@@ -3005,6 +3056,8 @@
adev->bluetooth_nrec = true;
adev->acdb_settings = TTY_MODE_OFF;
/* adev->cur_hdmi_channels = 0; by calloc() */
+ adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
voice_init(adev);
list_init(&adev->usecase_list);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index e537377..f1ceedc 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -188,6 +188,7 @@
void *offload_cookie;
struct compr_gapless_mdata gapless_mdata;
int send_new_metadata;
+ unsigned int bit_width;
struct audio_device *dev;
};
@@ -272,6 +273,8 @@
bool bt_wb_speech_enabled;
int snd_card;
+ unsigned int cur_codec_backend_samplerate;
+ unsigned int cur_codec_backend_bit_width;
void *platform;
unsigned int offload_usecases_state;
void *visualizer_lib;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index b27c8ca..e372254 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2041,3 +2041,10 @@
return fragment_size;
}
+bool platform_check_24_bit_support() {
+ return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) {
+ return false;
+}
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 29d6215..2400cd8 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -950,3 +950,12 @@
{
return false;
}
+
+bool platform_check_24_bit_support() {
+ return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) {
+ return false;
+}
+
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 9bfb801..3f62164 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2154,6 +2154,14 @@
fragment_size = atoi(value) * 1024;
}
+ // For FLAC use max size since it is loss less, and has sampling rates
+ // upto 192kHZ
+ if (info != NULL && !info->has_video &&
+ info->format == AUDIO_FORMAT_FLAC) {
+ fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+ ALOGV("FLAC fragment size %d", fragment_size);
+ }
+
if (info != NULL && info->has_video && info->is_streaming) {
fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
ALOGV("%s: offload fragment size reduced for AV streaming to %d",
@@ -2213,3 +2221,190 @@
return fragment_size;
}
+bool platform_check_24_bit_support() {
+
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("audio.offload.24bit.enable", value, "0");
+ if (atoi(value)) {
+ ALOGW("Property audio.offload.24bit.enable is set");
+ return true;
+ }
+ return false;
+}
+
+int platform_set_codec_backend_cfg(struct audio_device* adev,
+ unsigned int bit_width, unsigned int sample_rate)
+{
+ ALOGV("platform_set_codec_backend_cfg bw %d, sr %d", bit_width, sample_rate);
+
+ int ret = 0;
+ if (bit_width != adev->cur_codec_backend_bit_width) {
+ const char * mixer_ctl_name = "SLIM_0_RX Format";
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer command - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ if (bit_width == 24) {
+ mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+ } else {
+ mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ }
+ adev->cur_codec_backend_bit_width = bit_width;
+ ALOGE("Backend bit width is set to %d ", bit_width);
+ }
+
+ if ((adev->cur_codec_backend_bit_width == CODEC_BACKEND_DEFAULT_BIT_WIDTH &&
+ adev->cur_codec_backend_samplerate != CODEC_BACKEND_DEFAULT_SAMPLE_RATE) ||
+ (adev->cur_codec_backend_samplerate < sample_rate)) {
+
+ char *rate_str = NULL;
+ const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
+ struct mixer_ctl *ctl;
+
+ switch (sample_rate) {
+ case 8000:
+ rate_str = "KHZ_8";
+ break;
+ case 11025:
+ rate_str = "KHZ_11_025";
+ break;
+ case 16000:
+ rate_str = "KHZ_16";
+ break;
+ case 22050:
+ rate_str = "KHZ_22_05";
+ break;
+ case 32000:
+ rate_str = "KHZ_32";
+ break;
+ case 44100:
+ rate_str = "KHZ_44_1";
+ break;
+ case 48000:
+ rate_str = "KHZ_48";
+ break;
+ case 64000:
+ rate_str = "KHZ_64";
+ break;
+ case 88200:
+ rate_str = "KHZ_88_2";
+ break;
+ case 96000:
+ rate_str = "KHZ_96";
+ break;
+ case 176400:
+ rate_str = "KHZ_176_4";
+ break;
+ case 192000:
+ rate_str = "KHZ_192";
+ break;
+ default:
+ rate_str = "KHZ_48";
+ break;
+ }
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if(!ctl) {
+ ALOGE("%s: Could not get ctl for mixer command - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ ALOGV("Set sample rate as rate_str = %s", rate_str);
+ mixer_ctl_set_enum_by_string(ctl, rate_str);
+ adev->cur_codec_backend_samplerate = sample_rate;
+ }
+
+ return ret;
+}
+
+bool platform_check_codec_backend_cfg(struct audio_device* adev,
+ struct audio_usecase* usecase,
+ unsigned int* new_bit_width,
+ unsigned int* new_sample_rate)
+{
+ bool backend_change = false;
+ struct listnode *node;
+ struct stream_out *out = NULL;
+
+ // For voice calls use default configuration
+ // force routing is not required here, caller will do it anyway
+ if (adev->mode == AUDIO_MODE_IN_CALL ||
+ adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+ ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
+ *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ *new_sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ backend_change = true;
+ }
+
+
+ if (!backend_change) {
+ // go through all the offload usecases, and
+ // find the max bit width and samplerate
+ list_for_each(node, &adev->usecase_list) {
+ struct audio_usecase *curr_usecase;
+ curr_usecase = node_to_item(node, struct audio_usecase, list);
+ if (curr_usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ struct stream_out *out =
+ (struct stream_out*) curr_usecase->stream.out;
+ if (out != NULL ) {
+ ALOGV("Offload playback running bw %d sr %d",
+ out->bit_width, out->sample_rate);
+ if (*new_bit_width < out->bit_width) {
+ *new_bit_width = out->bit_width;
+ }
+ if (*new_sample_rate < out->sample_rate) {
+ *new_sample_rate = out->sample_rate;
+ }
+ }
+ }
+ }
+ }
+
+ // Force routing if the expected bitwdith or samplerate
+ // is not same as current backend comfiguration
+ if ((*new_bit_width != adev->cur_codec_backend_bit_width) ||
+ (*new_sample_rate != adev->cur_codec_backend_samplerate)) {
+ backend_change = true;
+ ALOGW("Codec backend needs to be updated");
+ }
+
+ return backend_change;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
+{
+ // check if 24bit configuration is enabled first
+ if (!platform_check_24_bit_support()) {
+ ALOGW("24bit not enable, no need to check for backend change");
+ return false;
+ }
+
+ ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+ unsigned int new_bit_width, old_bit_width;
+ unsigned int new_sample_rate, old_sample_rate;
+
+ new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
+ new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+
+ ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
+ if (platform_check_codec_backend_cfg(adev, usecase,
+ &new_bit_width, &new_sample_rate)) {
+ platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+ }
+
+ if (old_bit_width != adev->cur_codec_backend_bit_width ||
+ old_sample_rate != adev->cur_codec_backend_samplerate) {
+ ALOGW("New codec backend bit width %d, sample rate %d",
+ adev->cur_codec_backend_bit_width, adev->cur_codec_backend_samplerate);
+ return true;
+ }
+
+ return false;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 6c64073..e09b070 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -21,6 +21,9 @@
#define AUDIO_PLATFORM_API_H
#include <sound/voice_params.h>
+#define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16
+#define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000
+
void *platform_init(struct audio_device *adev);
void platform_deinit(void *platform);
const char *platform_get_snd_device_name(snd_device_t snd_device);
@@ -80,4 +83,6 @@
uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
+bool platform_check_24_bit_support();
#endif // AUDIO_PLATFORM_API_H