audio: enable SoundMonitor to handle ADSP SSR events
Enable SoundMonitor in audio hal to handle ADSP SSR events,
do required cleanup and restore any active sessions gracefully.
Change-Id: I83270b7c12095e56a6677f41efe0f5618a27e0e5
diff --git a/configs/msm8909/msm8909.mk b/configs/msm8909/msm8909.mk
index 3405db7..ee80b83 100755
--- a/configs/msm8909/msm8909.mk
+++ b/configs/msm8909/msm8909.mk
@@ -35,6 +35,7 @@
AUDIO_FEATURE_ENABLED_DYNAMIC_LOG := true
MM_AUDIO_ENABLED_FTM := true
TARGET_USES_QCOM_MM_AUDIO := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
diff --git a/configs/msm8937/msm8937.mk b/configs/msm8937/msm8937.mk
index 4b26d6c..0f10b33 100644
--- a/configs/msm8937/msm8937.mk
+++ b/configs/msm8937/msm8937.mk
@@ -56,6 +56,7 @@
AUDIO_FEATURE_ENABLED_SOURCE_TRACKING := true
BOARD_SUPPORTS_QAHW := true
AUDIO_FEATURE_ENABLED_DYNAMIC_LOG := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/configs/msm8953/msm8953.mk b/configs/msm8953/msm8953.mk
index 1adc471..9a778b9 100644
--- a/configs/msm8953/msm8953.mk
+++ b/configs/msm8953/msm8953.mk
@@ -56,6 +56,7 @@
AUDIO_FEATURE_ENABLED_SOURCE_TRACKING := true
BOARD_SUPPORTS_QAHW := true
AUDIO_FEATURE_ENABLED_DYNAMIC_LOG := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/configs/msm8996/msm8996.mk b/configs/msm8996/msm8996.mk
index 7f8d6ec..4b3af40 100644
--- a/configs/msm8996/msm8996.mk
+++ b/configs/msm8996/msm8996.mk
@@ -55,6 +55,7 @@
AUDIO_FEATURE_ENABLED_GEF_SUPPORT := true
BOARD_SUPPORTS_QAHW := true
AUDIO_FEATURE_ENABLED_DYNAMIC_LOG := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/configs/msm8998/msm8998.mk b/configs/msm8998/msm8998.mk
index 524582a..cddd66e 100644
--- a/configs/msm8998/msm8998.mk
+++ b/configs/msm8998/msm8998.mk
@@ -63,6 +63,7 @@
BOARD_SUPPORTS_QAHW := true
AUDIO_FEATURE_ENABLED_RAS := true
AUDIO_FEATURE_ENABLED_DYNAMIC_LOG := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/configs/sdm660/sdm660.mk b/configs/sdm660/sdm660.mk
index 62fe5c8..460a284 100644
--- a/configs/sdm660/sdm660.mk
+++ b/configs/sdm660/sdm660.mk
@@ -62,6 +62,7 @@
AUDIO_FEATURE_ENABLED_SOURCE_TRACKING := true
AUDIO_FEATURE_ENABLED_GEF_SUPPORT := true
AUDIO_FEATURE_ENABLED_RAS := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/configs/sdm845/sdm845.mk b/configs/sdm845/sdm845.mk
index 19802b4..3c2cab7 100644
--- a/configs/sdm845/sdm845.mk
+++ b/configs/sdm845/sdm845.mk
@@ -59,6 +59,7 @@
AUDIO_FEATURE_ENABLED_GEF_SUPPORT := true
BOARD_SUPPORTS_QAHW := false
AUDIO_FEATURE_ENABLED_RAS := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
##AUDIO_FEATURE_FLAGS
#Audio Specific device overlays
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 62b661e..84814f1 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -250,13 +250,6 @@
}
}
-#ifndef FM_POWER_OPT
-#define audio_extn_fm_set_parameters(adev, parms) (0)
-#else
-void audio_extn_fm_set_parameters(struct audio_device *adev,
- struct str_parms *parms);
-#endif
-
#ifndef SOURCE_TRACKING_ENABLED
#define audio_extn_source_track_set_parameters(adev, parms) (0)
#define audio_extn_source_track_get_parameters(adev, query, reply) (0)
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 42719f4..7c86d18 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -836,6 +836,13 @@
struct sound_focus_param *payload);
#endif
+#ifndef FM_POWER_OPT
+#define audio_extn_fm_set_parameters(adev, parms) (0)
+#else
+void audio_extn_fm_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+#endif
+
#ifndef APTX_DECODER_ENABLED
#define audio_extn_aptx_dec_set_license(adev); (0)
#define audio_extn_set_aptx_dec_bt_addr(adev, parms); (0)
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index 5da494d..b34bb22 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -62,7 +62,7 @@
bool is_fm_muted;
float fm_volume;
bool restart_fm;
- int scard_state;
+ card_status_t card_status;
};
static struct fm_module fmmod = {
@@ -72,7 +72,7 @@
.is_fm_running = 0,
.is_fm_muted = 0,
.restart_fm = 0,
- .scard_state = SND_CARD_STATE_ONLINE,
+ .card_status = CARD_STATUS_ONLINE,
};
static int32_t fm_set_volume(struct audio_device *adev, float value, bool persist)
@@ -242,14 +242,14 @@
if (ret >= 0) {
char *snd_card_status = value+2;
if (strstr(snd_card_status, "OFFLINE")) {
- fmmod.scard_state = SND_CARD_STATE_OFFLINE;
+ fmmod.card_status = CARD_STATUS_OFFLINE;
}
else if (strstr(snd_card_status, "ONLINE")) {
- fmmod.scard_state = SND_CARD_STATE_ONLINE;
+ fmmod.card_status = CARD_STATUS_ONLINE;
}
}
if(fmmod.is_fm_running) {
- if (fmmod.scard_state == SND_CARD_STATE_OFFLINE) {
+ if (fmmod.card_status == CARD_STATUS_OFFLINE) {
ALOGD("sound card is OFFLINE, stop FM");
fm_stop(adev);
fmmod.restart_fm = 1;
@@ -263,7 +263,7 @@
select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
}
}
- if (fmmod.restart_fm && (fmmod.scard_state == SND_CARD_STATE_ONLINE)) {
+ if (fmmod.restart_fm && (fmmod.card_status == CARD_STATUS_ONLINE)) {
ALOGD("sound card is ONLINE, restart FM");
fmmod.restart_fm = 0;
fm_start(adev);
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index bf731f6..8cb80e9 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -629,7 +629,6 @@
{
int ret = 0;
struct audio_device *adev = out->dev;
- int snd_card_status = get_snd_card_state(adev);
if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
ret = -EINVAL;
@@ -641,7 +640,8 @@
__func__, &out->stream, out->usecase, use_case_table[out->usecase],
out->devices);
- if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+ if (CARD_STATUS_OFFLINE == out->card_status ||
+ CARD_STATUS_OFFLINE == adev->card_status) {
ALOGE("%s: sound card is not active/SSR returning error", __func__);
ret = -EIO;
usleep(50000);
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index 94a8a2b..a38ca17 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -97,6 +97,15 @@
return NULL;
}
+static void stdev_snd_mon_cb(void * stream __unused, struct str_parms * parms)
+{
+ if (!parms)
+ return;
+
+ audio_extn_sound_trigger_set_parameters(NULL, parms);
+ return;
+}
+
int audio_hw_call_back(sound_trigger_event_type_t event,
sound_trigger_event_info_t* config)
{
@@ -426,6 +435,7 @@
st_dev->adev = adev;
list_init(&st_dev->st_ses_list);
+ audio_extn_snd_mon_register_listener(st_dev, stdev_snd_mon_cb);
return 0;
@@ -442,6 +452,7 @@
{
ALOGI("%s: Enter", __func__);
if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
+ audio_extn_snd_mon_unregister_listener(st_dev);
dlclose(st_dev->lib_handle);
free(st_dev);
st_dev = NULL;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 68f5978..0b3592a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -423,6 +423,26 @@
adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
}
+static int parse_snd_card_status(struct str_parms *parms, int *card,
+ card_status_t *status)
+{
+ char value[32]={0};
+ char state[32]={0};
+
+ int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
+ if (ret < 0)
+ return -1;
+
+ // sscanf should be okay as value is of max length 32.
+ // same as sizeof state.
+ if (sscanf(value, "%d,%s", card, state) < 2)
+ return -1;
+
+ *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
+ CARD_STATUS_OFFLINE;
+ return 0;
+}
+
__attribute__ ((visibility ("default")))
bool audio_hw_send_gain_dep_calibration(int level) {
bool ret_val = false;
@@ -542,35 +562,6 @@
(uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
}
-int get_snd_card_state(struct audio_device *adev)
-{
- int snd_scard_state;
-
- if (!adev)
- return SND_CARD_STATE_OFFLINE;
-
- pthread_mutex_lock(&adev->snd_card_status.lock);
- snd_scard_state = adev->snd_card_status.state;
- pthread_mutex_unlock(&adev->snd_card_status.lock);
-
- return snd_scard_state;
-}
-
-static int set_snd_card_state(struct audio_device *adev, int snd_scard_state)
-{
- if (!adev)
- return -ENOSYS;
-
- pthread_mutex_lock(&adev->snd_card_status.lock);
- if (adev->snd_card_status.state != snd_scard_state) {
- adev->snd_card_status.state = snd_scard_state;
- platform_snd_card_update(adev->platform, snd_scard_state);
- }
- pthread_mutex_unlock(&adev->snd_card_status.lock);
-
- return 0;
-}
-
static int enable_audio_route_for_voice_usecases(struct audio_device *adev,
struct audio_usecase *uc_info)
{
@@ -1793,7 +1784,6 @@
int ret = 0;
struct audio_usecase *uc_info;
struct audio_device *adev = in->dev;
- int snd_card_status = get_snd_card_state(adev);
int usecase = platform_update_usecase_from_source(in->source,in->usecase);
if (get_usecase_from_list(adev, usecase) == NULL)
@@ -1802,8 +1792,9 @@
__func__, &in->stream, in->usecase, use_case_table[in->usecase]);
- if (SND_CARD_STATE_OFFLINE == snd_card_status) {
- ALOGE("%s: sound card is not active/SSR returning error", __func__);
+ if (CARD_STATUS_OFFLINE == in->card_status||
+ CARD_STATUS_OFFLINE == adev->card_status) {
+ ALOGW("in->card_status or adev->card_status offline, try again");
ret = -EIO;
goto error_config;
}
@@ -2111,7 +2102,7 @@
event = STREAM_CBK_EVENT_DRAIN_READY;
ALOGV("copl(%p):send drain callback, ret %d", out, ret);
} else
- ALOGE("%s: Block drain ready event during SSR", __func__);
+ ALOGI("%s: Block drain ready event during SSR", __func__);
break;
case OFFLOAD_CMD_DRAIN:
ALOGD("copl(%p):calling compress_drain", out);
@@ -2120,6 +2111,11 @@
send_callback = true;
event = STREAM_CBK_EVENT_DRAIN_READY;
break;
+ case OFFLOAD_CMD_ERROR:
+ ALOGD("copl(%p): sending error callback to AF", out);
+ send_callback = true;
+ event = STREAM_CBK_EVENT_ERROR;
+ break;
default:
ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
break;
@@ -2230,7 +2226,6 @@
int ret = 0;
struct audio_usecase *uc_info;
struct audio_device *adev = out->dev;
- int snd_card_status = get_snd_card_state(adev);
char mixer_ctl_name[128];
struct mixer_ctl *ctl = NULL;
char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
@@ -2244,8 +2239,9 @@
__func__, &out->stream, out->usecase, use_case_table[out->usecase],
out->devices);
- if (SND_CARD_STATE_OFFLINE == snd_card_status) {
- ALOGE("%s: sound card is not active/SSR returning error", __func__);
+ if (CARD_STATUS_OFFLINE == out->card_status ||
+ CARD_STATUS_OFFLINE == adev->card_status) {
+ ALOGW("out->card_status or adev->card_status offline, try again");
ret = -EIO;
goto error_config;
}
@@ -2679,6 +2675,27 @@
return 0;
}
+static int out_on_error(struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ bool do_standby = false;
+
+ lock_output_stream(out);
+ if (!out->standby) {
+ if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ stop_compressed_output_l(out);
+ send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
+ } else
+ do_standby = true;
+ }
+ pthread_mutex_unlock(&out->lock);
+
+ if (do_standby)
+ return out_standby(&out->stream.common);
+
+ return 0;
+}
+
static int out_dump(const struct audio_stream *stream __unused,
int fd __unused)
{
@@ -2717,6 +2734,43 @@
return out == adev->primary_output || out == adev->voice_tx_output;
}
+// note: this call is safe only if the stream_cb is
+// removed first in close_output_stream (as is done now).
+static void out_snd_mon_cb(void * stream, struct str_parms * parms)
+{
+ if (!stream || !parms)
+ return;
+
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+
+ card_status_t status;
+ int card;
+ if (parse_snd_card_status(parms, &card, &status) < 0)
+ return;
+
+ pthread_mutex_lock(&adev->lock);
+ bool valid_cb = (card == adev->snd_card);
+ pthread_mutex_unlock(&adev->lock);
+
+ if (!valid_cb)
+ return;
+
+ lock_output_stream(out);
+ if (out->card_status != status)
+ out->card_status = status;
+ pthread_mutex_unlock(&out->lock);
+
+ ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
+ use_case_table[out->usecase],
+ status == CARD_STATUS_OFFLINE ? "offline" : "online");
+
+ if (status == CARD_STATUS_OFFLINE)
+ out_on_error(stream);
+
+ return;
+}
+
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct stream_out *out = (struct stream_out *)stream;
@@ -3102,12 +3156,11 @@
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
- int snd_scard_state = get_snd_card_state(adev);
ssize_t ret = 0;
lock_output_stream(out);
- if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
+ if (CARD_STATUS_OFFLINE == out->card_status) {
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
/*during SSR for compress usecase we should return error to flinger*/
@@ -3216,9 +3269,8 @@
send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
} else if (-ENETRESET == ret) {
ALOGE("copl %s: received sound card offline state on compress write", __func__);
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+ out->card_status = CARD_STATUS_OFFLINE;
pthread_mutex_unlock(&out->lock);
- out_standby(&out->stream.common);
return ret;
}
if ( ret == (ssize_t)bytes && !out->non_blocking)
@@ -3309,12 +3361,9 @@
}
exit:
- /* ToDo: There may be a corner case when SSR happens back to back during
- start/stop. Need to post different error to handle that. */
if (-ENETRESET == ret) {
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+ out->card_status = CARD_STATUS_OFFLINE;
}
-
pthread_mutex_unlock(&out->lock);
if (ret != 0) {
@@ -3326,7 +3375,7 @@
pthread_mutex_unlock(&adev->lock);
out->standby = true;
}
- out_standby(&out->stream.common);
+ out_on_error(&out->stream.common);
if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
out_get_sample_rate(&out->stream.common));
@@ -3338,7 +3387,6 @@
uint32_t *dsp_frames)
{
struct stream_out *out = (struct stream_out *)stream;
- struct audio_device *adev = out->dev;
if (dsp_frames == NULL)
return -EINVAL;
@@ -3365,24 +3413,25 @@
ALOGVV("%s rendered frames %d sample_rate %d",
__func__, *dsp_frames, out->sample_rate);
}
- pthread_mutex_unlock(&out->lock);
if (-ENETRESET == ret) {
ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
- return -EINVAL;
+ out->card_status = CARD_STATUS_OFFLINE;
+ ret = -EINVAL;
} else if(ret < 0) {
ALOGE(" ERROR: Unable to get time stamp from compress driver");
- return -EINVAL;
- } else if (get_snd_card_state(adev) == SND_CARD_STATE_OFFLINE){
+ ret = -EINVAL;
+ } else if (out->card_status == CARD_STATUS_OFFLINE) {
/*
* Handle corner case where compress session is closed during SSR
* and timestamp is queried
*/
ALOGE(" ERROR: sound card not active, return error");
- return -EINVAL;
+ ret = -EINVAL;
} else {
- return 0;
+ ret = 0;
}
+ pthread_mutex_unlock(&out->lock);
+ return ret;
} else if (audio_is_linear_pcm(out->format)) {
*dsp_frames = out->written;
return 0;
@@ -3440,7 +3489,7 @@
ret = -errno;
if (-ENETRESET == ret) {
ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+ out->card_status = CARD_STATUS_OFFLINE;
ret = -EINVAL;
} else
ret = 0;
@@ -3463,7 +3512,7 @@
ret = 0;
}
}
- } else if (adev->snd_card_status.state == SND_CARD_STATE_OFFLINE) {
+ } else if (out->card_status == CARD_STATUS_OFFLINE) {
*frames = out->written;
clock_gettime(CLOCK_MONOTONIC, timestamp);
ret = 0;
@@ -3505,10 +3554,7 @@
ALOGD("copl(%p):pause compress driver", out);
lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
- struct audio_device *adev = out->dev;
- int snd_scard_state = get_snd_card_state(adev);
-
- if (SND_CARD_STATE_ONLINE == snd_scard_state)
+ if (out->card_status != CARD_STATUS_OFFLINE)
status = compress_pause(out->compr);
out->offload_state = OFFLOAD_STATE_PAUSED;
@@ -3538,15 +3584,7 @@
status = 0;
lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
- struct audio_device *adev = out->dev;
- int snd_scard_state = get_snd_card_state(adev);
-
- if (SND_CARD_STATE_ONLINE == snd_scard_state) {
- if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- pthread_mutex_lock(&out->dev->lock);
- ALOGV("offload resume, check and set hdmi backend again");
- pthread_mutex_unlock(&out->dev->lock);
- }
+ if (out->card_status != CARD_STATUS_OFFLINE) {
status = compress_resume(out->compr);
}
if (!status) {
@@ -3692,6 +3730,43 @@
return 0;
}
+static void in_snd_mon_cb(void * stream, struct str_parms * parms)
+{
+ if (!stream || !parms)
+ return;
+
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+
+ card_status_t status;
+ int card;
+ if (parse_snd_card_status(parms, &card, &status) < 0)
+ return;
+
+ pthread_mutex_lock(&adev->lock);
+ bool valid_cb = (card == adev->snd_card);
+ pthread_mutex_unlock(&adev->lock);
+
+ if (!valid_cb)
+ return;
+
+ lock_input_stream(in);
+ if (in->card_status != status)
+ in->card_status = status;
+ pthread_mutex_unlock(&in->lock);
+
+ ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
+ use_case_table[in->usecase],
+ status == CARD_STATUS_OFFLINE ? "offline" : "online");
+
+ // a better solution would be to report error back to AF and let
+ // it put the stream to standby
+ if (status == CARD_STATUS_OFFLINE)
+ in_standby(&in->stream.common);
+
+ return;
+}
+
static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct stream_in *in = (struct stream_in *)stream;
@@ -3808,7 +3883,6 @@
struct stream_in *in = (struct stream_in *)stream;
struct audio_device *adev = in->dev;
int ret = -1;
- int snd_scard_state = get_snd_card_state(adev);
size_t bytes_read = 0;
lock_input_stream(in);
@@ -3821,12 +3895,6 @@
return bytes;
}
- if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
- ALOGD(" %s: sound card is not active/SSR state", __func__);
- ret= -EIO;;
- goto exit;
- }
-
if (in->standby) {
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
@@ -3887,11 +3955,8 @@
memset(buffer, 0, bytes);
exit:
- /* ToDo: There may be a corner case when SSR happens back to back during
- start/stop. Need to post different error to handle that. */
if (-ENETRESET == ret)
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
-
+ in->card_status = CARD_STATUS_OFFLINE;
pthread_mutex_unlock(&in->lock);
if (ret != 0) {
@@ -3981,12 +4046,6 @@
*stream_out = NULL;
- if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
- (SND_CARD_STATE_OFFLINE == get_snd_card_state(adev))) {
- ALOGE("sound card is not active rejecting compress output open request");
- return -EINVAL;
- }
-
out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
@@ -4046,6 +4105,16 @@
}
} else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
(out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
+ pthread_mutex_lock(&adev->lock);
+ bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
+ pthread_mutex_unlock(&adev->lock);
+
+ // reject offload during card offline to allow
+ // fallback to s/w paths
+ if (offline) {
+ ret = -ENODEV;
+ goto error_open;
+ }
if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
@@ -4424,6 +4493,18 @@
config->channel_mask = out->stream.common.get_channels(&out->stream.common);
config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
+ /*
+ By locking output stream before registering, we allow the callback
+ to update stream's state only after stream's initial state is set to
+ adev state.
+ */
+ lock_output_stream(out);
+ audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
+ pthread_mutex_lock(&adev->lock);
+ out->card_status = adev->card_status;
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+
*stream_out = &out->stream;
ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
use_case_table[out->usecase]);
@@ -4474,6 +4555,10 @@
ALOGD("%s: enter:stream_handle(%p)",__func__, out);
+ // must deregister from sndmonitor first to prevent races
+ // between the callback and close_stream
+ audio_extn_snd_mon_unregister_listener(out);
+
/* close adsp hdrl session before standby */
if (out->adsp_hdlr_stream_handle) {
ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
@@ -4522,29 +4607,6 @@
ALOGV("%s: exit", __func__);
}
-static void close_compress_sessions(struct audio_device *adev)
-{
- struct stream_out *out;
- struct listnode *node, *tempnode;
- struct audio_usecase *usecase;
- pthread_mutex_lock(&adev->lock);
-
- list_for_each_safe(node, tempnode, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- if (is_offload_usecase(usecase->id)) {
- if (usecase->stream.out) {
- ALOGI(" %s closing compress session %d on OFFLINE state", __func__, usecase->id);
- out = usecase->stream.out;
- pthread_mutex_unlock(&adev->lock);
- out_standby(&out->stream.common);
- pthread_mutex_lock(&adev->lock);
- tempnode = list_head(&adev->usecase_list);
- }
- }
- }
- pthread_mutex_unlock(&adev->lock);
-}
-
static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
{
struct audio_device *adev = (struct audio_device *)dev;
@@ -4559,21 +4621,6 @@
if (!parms)
goto error;
- ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
- if (ret >= 0) {
- char *snd_card_status = value+2;
- if (strstr(snd_card_status, "OFFLINE")) {
- ALOGD("Received sound card OFFLINE status");
- set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
- //close compress sessions on OFFLINE status
- close_compress_sessions(adev);
- } else if (strstr(snd_card_status, "ONLINE")) {
- ALOGD("Received sound card ONLINE status");
- set_snd_card_state(adev,SND_CARD_STATE_ONLINE);
- //send dts hpx license if enabled
- audio_extn_dts_eagle_send_lic();
- }
- }
pthread_mutex_lock(&adev->lock);
status = voice_set_parameters(adev, parms);
@@ -4765,17 +4812,6 @@
return NULL;
}
- ret = str_parms_get_str(query, "SND_CARD_STATUS", value,
- sizeof(value));
- if (ret >=0) {
- int val = 1;
- pthread_mutex_lock(&adev->snd_card_status.lock);
- if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state)
- val = 0;
- pthread_mutex_unlock(&adev->snd_card_status.lock);
- str_parms_add_int(reply, "SND_CARD_STATUS", val);
- goto exit;
- }
//handle vr audio getparam
ret = str_parms_get_str(query,
@@ -5102,6 +5138,13 @@
get sound trigger pcm if present */
audio_extn_sound_trigger_check_and_get_session(in);
+ lock_input_stream(in);
+ audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
+ pthread_mutex_lock(&adev->lock);
+ in->card_status = adev->card_status;
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&in->lock);
+
*stream_in = &in->stream;
ALOGV("%s: exit", __func__);
return ret;
@@ -5121,6 +5164,10 @@
ALOGD("%s: enter:stream_handle(%p)",__func__, in);
+ // must deregister from sndmonitor first to prevent races
+ // between the callback and close_stream
+ audio_extn_snd_mon_unregister_listener(stream);
+
/* Disable echo reference while closing input stream */
platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
@@ -5169,6 +5216,7 @@
pthread_mutex_lock(&adev_init_lock);
if ((--audio_device_ref_count) == 0) {
+ audio_extn_snd_mon_unregister_listener(adev);
audio_extn_sound_trigger_deinit(adev);
audio_extn_listen_deinit(adev);
audio_extn_utils_release_streams_cfg_lists(
@@ -5184,6 +5232,7 @@
adev->adm_deinit(adev->adm_data);
qahwi_deinit(device);
audio_extn_adsp_hdlr_deinit();
+ audio_extn_snd_mon_deinit();
free(device);
adev = NULL;
}
@@ -5210,6 +5259,40 @@
}
}
+static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
+{
+ bool is_snd_card_status = false;
+ bool is_ext_device_status = false;
+ char value[32];
+ int card = -1;
+ card_status_t status;
+
+ if (cookie != adev || !parms)
+ return;
+
+ if (!parse_snd_card_status(parms, &card, &status)) {
+ is_snd_card_status = true;
+ } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
+ is_ext_device_status = true;
+ } else {
+ // not a valid event
+ return;
+ }
+
+ pthread_mutex_lock(&adev->lock);
+ if (card == adev->snd_card || is_ext_device_status) {
+ if (is_snd_card_status && adev->card_status != status) {
+ adev->card_status = status;
+ platform_snd_card_update(adev->platform, status);
+ audio_extn_fm_set_parameters(adev, parms);
+ } else if (is_ext_device_status) {
+ platform_set_parameters(adev->platform, parms);
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return;
+}
+
static int adev_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
@@ -5283,8 +5366,6 @@
adev->perf_lock_opts[1] = 0x20E;
adev->perf_lock_opts_size = 2;
- pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
- adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
/* Loads platform specific libraries dynamically */
adev->platform = platform_init(adev);
if (!adev->platform) {
@@ -5294,7 +5375,6 @@
*device = NULL;
pthread_mutex_unlock(&adev_init_lock);
pthread_mutex_destroy(&adev->lock);
- pthread_mutex_destroy(&adev->snd_card_status.lock);
return -EINVAL;
}
@@ -5313,8 +5393,6 @@
adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
}
- adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
-
if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
if (adev->visualizer_lib == NULL) {
@@ -5331,7 +5409,6 @@
}
audio_extn_init(adev);
audio_extn_listen_init(adev, adev->snd_card);
- audio_extn_sound_trigger_init(adev);
audio_extn_gef_init(adev);
if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
@@ -5443,6 +5520,14 @@
qahwi_init(*device);
audio_extn_perf_lock_init();
audio_extn_adsp_hdlr_init(adev->mixer);
+
+ audio_extn_snd_mon_init();
+ pthread_mutex_lock(&adev->lock);
+ audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
+ adev->card_status = CARD_STATUS_ONLINE;
+ pthread_mutex_unlock(&adev->lock);
+ audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
+
ALOGV("%s: exit", __func__);
return 0;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 5044551..00013bc 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -81,9 +81,6 @@
#define DEFAULT_HDMI_OUT_SAMPLE_RATE 48000
#define DEFAULT_HDMI_OUT_FORMAT AUDIO_FORMAT_PCM_16_BIT
-#define SND_CARD_STATE_OFFLINE 0
-#define SND_CARD_STATE_ONLINE 1
-
#define MAX_PERF_LOCK_OPTS 20
#define MAX_STREAM_PROFILE_STR_LEN 32
@@ -260,6 +257,7 @@
bool realtime;
int af_period_multiplier;
struct audio_device *dev;
+ card_status_t card_status;
void* qaf_stream_handle;
pthread_cond_t qaf_offload_cond;
@@ -303,6 +301,7 @@
qahwi_stream_in_t qahwi_in;
struct audio_device *dev;
+ card_status_t card_status;
};
typedef enum {
@@ -330,11 +329,6 @@
union stream_ptr stream;
};
-struct sound_card_status {
- pthread_mutex_t lock;
- int state;
-};
-
struct stream_format {
struct listnode list;
audio_format_t format;
@@ -402,6 +396,7 @@
bool allow_afe_proxy_usage;
int snd_card;
+ card_status_t card_status;
unsigned int cur_codec_backend_samplerate;
unsigned int cur_codec_backend_bit_width;
bool is_channel_status_set;
@@ -414,7 +409,6 @@
int (*offload_effects_start_output)(audio_io_handle_t, int, struct mixer *);
int (*offload_effects_stop_output)(audio_io_handle_t, int);
- struct sound_card_status snd_card_status;
int (*offload_effects_set_hpx_state)(bool);
void *adm_data;
@@ -470,7 +464,6 @@
int pcm_ioctl(struct pcm *pcm, int request, ...);
-int get_snd_card_state(struct audio_device *adev);
audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
usecase_type_t type);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c20cd3d..eba8e97 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2579,11 +2579,11 @@
return my_data->is_acdb_initialized;
}
-void platform_snd_card_update(void *platform, int snd_scard_state)
+void platform_snd_card_update(void *platform, card_status_t card_status)
{
struct platform_data *my_data = (struct platform_data *)platform;
- if (snd_scard_state == SND_CARD_STATE_ONLINE) {
+ if (card_status == CARD_STATUS_ONLINE) {
if (!platform_is_acdb_initialized(my_data)) {
if(platform_acdb_init(my_data))
ALOGE("%s: acdb initialization is failed", __func__);
@@ -4915,7 +4915,7 @@
}
if ((prop_playback_enabled && (voice_is_in_call(my_data->adev))) ||
- (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev))) {
+ (CARD_STATUS_OFFLINE == my_data->adev->card_status)) {
char *decoder_mime_type = value;
//check if unsupported mime type or not
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 840c75a..6f4bc0a 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2273,11 +2273,11 @@
return my_data->is_acdb_initialized;
}
-void platform_snd_card_update(void *platform, int snd_scard_state)
+void platform_snd_card_update(void *platform, card_status_t card_status)
{
struct platform_data *my_data = (struct platform_data *)platform;
- if (snd_scard_state == SND_CARD_STATE_ONLINE) {
+ if (card_status == CARD_STATUS_ONLINE) {
if (!platform_is_acdb_initialized(my_data)) {
if(platform_acdb_init(my_data))
ALOGE("%s: acdb initialization is failed", __func__);
@@ -4699,7 +4699,7 @@
}
if ((prop_playback_enabled && (voice_is_in_call(my_data->adev))) ||
- (SND_CARD_STATE_OFFLINE == get_snd_card_state(my_data->adev))) {
+ (CARD_STATUS_OFFLINE == my_data->adev->card_status)) {
char *decoder_mime_type = value;
//check if unsupported mime type or not
diff --git a/hal/platform_api.h b/hal/platform_api.h
index a5ba7bf..b31ed94 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -149,7 +149,7 @@
/* From platform_info.c */
int platform_info_init(const char *filename, void *, caller_t);
-void platform_snd_card_update(void *platform, int snd_scard_state);
+void platform_snd_card_update(void *platform, card_status_t scard_status);
struct audio_offload_info_t;
uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 5fff2d5..0ab3fc0 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -531,11 +531,11 @@
int ret = 0;
struct audio_device *adev = out->dev;
struct audio_usecase *uc_info;
- int snd_card_status = get_snd_card_state(adev);
ALOGD("%s: enter", __func__);
- if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+ if (CARD_STATUS_OFFLINE == out->card_status ||
+ CARD_STATUS_OFFLINE == adev->card_status) {
ret = -ENETRESET;
ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
goto error;
@@ -565,11 +565,11 @@
{
int ret = 0;
struct audio_device *adev = in->dev;
- int snd_card_status = get_snd_card_state(adev);
ALOGD("%s: enter", __func__);
- if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+ if (CARD_STATUS_OFFLINE == in->card_status ||
+ CARD_STATUS_OFFLINE == adev->card_status) {
ret = -ENETRESET;
ALOGE("%s: sound card is not active/SSR returning error %d ", __func__, ret);
goto error;