hal: Add support for multiple instances of offload playback
Add support for multiple offload playback instances
Change-Id: I9d35b68fc8ca27c4eeb3976eb508b06c5ad3ca8f
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 2f67784..86440b8 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -107,6 +107,16 @@
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
+#endif
[USECASE_AUDIO_RECORD] = "audio-record",
[USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
@@ -134,6 +144,19 @@
[USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
};
+static const audio_usecase_t offload_usecases[] = {
+ USECASE_AUDIO_PLAYBACK_OFFLOAD,
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+ USECASE_AUDIO_PLAYBACK_OFFLOAD2,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD3,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD4,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD5,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD6,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD7,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD8,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD9,
+#endif
+};
#define STRING_TO_ENUM(string) { #string, string }
@@ -874,6 +897,51 @@
}
}
+bool is_offload_usecase(audio_usecase_t uc_id)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
+ if (uc_id == offload_usecases[i])
+ return true;
+ }
+ return false;
+}
+
+static audio_usecase_t get_offload_usecase(struct audio_device *adev)
+{
+ audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD;
+ unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+ char value[PROPERTY_VALUE_MAX] = {0};
+
+ property_get("audio.offload.multiple.enabled", value, NULL);
+ if (!(atoi(value) || !strncmp("true", value, 4)))
+ num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */
+
+ ALOGV("%s: num_usecase: %d", __func__, num_usecase);
+ for (i = 0; i < num_usecase; i++) {
+ if (!(adev->offload_usecases_state & (0x1<<i))) {
+ adev->offload_usecases_state |= 0x1 << i;
+ ret = offload_usecases[i];
+ break;
+ }
+ }
+ ALOGV("%s: offload usecase is %d", __func__, ret);
+ return ret;
+}
+
+static void free_offload_usecase(struct audio_device *adev,
+ audio_usecase_t uc_id)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
+ if (offload_usecases[i] == uc_id) {
+ adev->offload_usecases_state &= ~(0x1<<i);
+ break;
+ }
+ }
+ ALOGV("%s: free offload usecase %d", __func__, uc_id);
+}
+
static void *offload_thread_loop(void *context)
{
struct stream_out *out = (struct stream_out *) context;
@@ -1021,7 +1089,7 @@
"no change in HDMI channels", __func__);
ret = false;
break;
- } else if (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
+ } else if (is_offload_usecase(usecase->id) &&
popcount(usecase->stream.out->channel_mask) > 2) {
ALOGD("%s: multi-channel(%x) compress offload playback is active, "
"no change in HDMI channels", __func__, usecase->stream.out->channel_mask);
@@ -1094,7 +1162,7 @@
return -EINVAL;
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
if (adev->visualizer_stop_output != NULL)
adev->visualizer_stop_output(out->handle, out->pcm_device_id);
if (adev->offload_effects_stop_output != NULL)
@@ -1144,7 +1212,7 @@
/* This must be called before adding this usecase to the list */
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
+ if (is_offload_usecase(out->usecase))
check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
else
check_and_set_hdmi_channels(adev, out->config.channels);
@@ -1156,7 +1224,7 @@
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
__func__, 0, out->pcm_device_id);
- if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (!is_offload_usecase(out->usecase)) {
out->pcm = pcm_open(adev->snd_card,
out->pcm_device_id,
PCM_OUT | PCM_MONOTONIC, &out->config);
@@ -1274,7 +1342,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
+ if (is_offload_usecase(out->usecase))
return out->compr_config.fragment_size;
else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
return voice_extn_compress_voip_out_get_buffer_size(out);
@@ -1320,7 +1388,7 @@
if (!out->standby) {
pthread_mutex_lock(&adev->lock);
out->standby = true;
- if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (!is_offload_usecase(out->usecase)) {
if (out->pcm) {
pcm_close(out->pcm);
out->pcm = NULL;
@@ -1487,7 +1555,7 @@
audio_extn_set_parameters(adev, parms);
pthread_mutex_unlock(&adev->lock);
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
pthread_mutex_lock(&out->lock);
parse_compress_metadata(out, parms);
pthread_mutex_unlock(&out->lock);
@@ -1546,7 +1614,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
+ if (is_offload_usecase(out->usecase))
return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
return (out->config.period_count * out->config.period_size * 1000) /
@@ -1563,7 +1631,7 @@
/* only take left channel into account: the API is for stereo anyway */
out->muted = (left == 0.0f);
return 0;
- } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ } else if (is_offload_usecase(out->usecase)) {
char mixer_ctl_name[128];
struct audio_device *adev = out->dev;
struct mixer_ctl *ctl;
@@ -1610,7 +1678,7 @@
}
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%x): writing buffer (%d bytes) to compress device", (unsigned int)out, bytes);
if (out->send_new_metadata) {
ALOGD("copl(%x):send new gapless metadata", (unsigned int)out);
@@ -1660,7 +1728,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
*dsp_frames = 0;
- if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
+ if (is_offload_usecase(out->usecase) && (dsp_frames != NULL)) {
pthread_mutex_lock(&out->lock);
if (out->compr != NULL) {
compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
@@ -1699,7 +1767,7 @@
pthread_mutex_lock(&out->lock);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
if (out->compr != NULL) {
compress_get_tstamp(out->compr, &dsp_frames,
&out->sample_rate);
@@ -1753,7 +1821,7 @@
struct stream_out *out = (struct stream_out *)stream;
int status = -ENOSYS;
ALOGV("%s", __func__);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%x):pause compress driver", (unsigned int)out);
pthread_mutex_lock(&out->lock);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
@@ -1770,7 +1838,7 @@
struct stream_out *out = (struct stream_out *)stream;
int status = -ENOSYS;
ALOGV("%s", __func__);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%x):resume compress driver", (unsigned int)out);
status = 0;
pthread_mutex_lock(&out->lock);
@@ -1788,7 +1856,7 @@
struct stream_out *out = (struct stream_out *)stream;
int status = -ENOSYS;
ALOGV("%s", __func__);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
pthread_mutex_lock(&out->lock);
if (type == AUDIO_DRAIN_EARLY_NOTIFY)
status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
@@ -1803,7 +1871,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
ALOGV("%s", __func__);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%x):calling compress flush", (unsigned int)out);
pthread_mutex_lock(&out->lock);
stop_compressed_output_l(out);
@@ -2166,7 +2234,7 @@
out->compr_config.codec = (struct snd_codec *)
calloc(1, sizeof(struct snd_codec));
- out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
+ out->usecase = get_offload_usecase(adev);
if (config->offload_info.channel_mask)
out->channel_mask = config->offload_info.channel_mask;
else if (config->channel_mask) {
@@ -2321,9 +2389,9 @@
else
out_standby(&stream->common);
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (is_offload_usecase(out->usecase)) {
destroy_offload_callback_thread(out);
-
+ free_offload_usecase(adev, out->usecase);
if (out->compr_config.codec != NULL)
free(out->compr_config.codec);
}
@@ -2699,7 +2767,7 @@
voice_init(adev);
list_init(&adev->usecase_list);
adev->cur_wfd_channels = 2;
-
+ adev->offload_usecases_state = 0;
/* Loads platform specific libraries dynamically */
adev->platform = platform_init(adev);
if (!adev->platform) {