hal: SSR support for pcm playback,pcm record usecases
- Added SSR event handling support in HAL
- Added support to drop incoming pcm data for pcm playback
usecase during SSR
- Added support to send dummy input(mute/zero buffer) for
record usecase during SSR
Change-Id: I158b62fa443bb523091128fe1308c9a9b1415502
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1a4ce0a..81ba6f1 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -790,6 +790,15 @@
ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
__func__, &in->stream, in->usecase, use_case_table[in->usecase]);
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) {
+ ALOGE("%s: sound card is not active/SSR returning error", __func__);
+ ret = -ENETRESET;
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+ goto error_config;
+ }
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+
/* Check if source matches incall recording usecase criteria */
ret = voice_check_and_set_incall_rec_usecase(adev, in);
if (ret)
@@ -827,8 +836,11 @@
pcm_close(in->pcm);
in->pcm = NULL;
ret = -EIO;
+ in->pcm_error_type = PCM_ERROR_EIO;
goto error_open;
}
+
+ in->pcm_error_type = PCM_ERROR_NONE;
ALOGV("%s: exit", __func__);
return ret;
@@ -1169,6 +1181,16 @@
ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
__func__, &out->stream, out->usecase, use_case_table[out->usecase],
out->devices);
+
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) {
+ ALOGE("%s: sound card is not active/SSR returning error", __func__);
+ ret = -ENETRESET;
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+ goto error_config;
+ }
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+
out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
if (out->pcm_device_id < 0) {
ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
@@ -1215,8 +1237,10 @@
pcm_close(out->pcm);
out->pcm = NULL;
ret = -EIO;
+ out->pcm_error_type = PCM_ERROR_EIO;
goto error_open;
}
+ out->pcm_error_type = PCM_ERROR_NONE;
} else {
out->pcm = NULL;
out->compr = compress_open(adev->snd_card,
@@ -1642,9 +1666,28 @@
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
+ int scard_state = SND_CARD_STATE_ONLINE;
ssize_t ret = 0;
pthread_mutex_lock(&out->lock);
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ scard_state = adev->snd_card_status.state;
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+ if (out->pcm) {
+ if (SND_CARD_STATE_OFFLINE == scard_state) {
+ ALOGD(" %s: sound card is not active/SSR state", __func__);
+ ret= -ENETRESET;
+ goto exit;
+ } else if (PCM_ERROR_ENETRESET == out->pcm_error_type) {
+ ALOGD(" %s restarting pcm session on post SSR", __func__);
+ out->standby = false;
+ pthread_mutex_unlock(&out->lock);
+ out_standby(&out->stream.common);
+ pthread_mutex_lock(&out->lock);
+ }
+ }
+
if (out->standby) {
out->standby = false;
pthread_mutex_lock(&adev->lock);
@@ -1693,6 +1736,15 @@
}
exit:
+
+ if (-ENETRESET == ret) {
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+ out->pcm_error_type = PCM_ERROR_ENETRESET;
+ out->standby = true; /*standby will be called on post SSR */
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+ }
+
pthread_mutex_unlock(&out->lock);
if (ret != 0) {
@@ -1700,7 +1752,8 @@
ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm));
out_standby(&out->stream.common);
usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
- out_get_sample_rate(&out->stream.common));
+ out_get_sample_rate(&out->stream.common));
+
}
return bytes;
}
@@ -2032,8 +2085,27 @@
struct stream_in *in = (struct stream_in *)stream;
struct audio_device *adev = in->dev;
int i, ret = -1;
+ int scard_state = SND_CARD_STATE_ONLINE;
pthread_mutex_lock(&in->lock);
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ scard_state = adev->snd_card_status.state;
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+ if (in->pcm) {
+ if(SND_CARD_STATE_OFFLINE == scard_state) {
+ ALOGD(" %s: sound card is not active/SSR state", __func__);
+ ret= -ENETRESET;
+ goto exit;
+ } else if (PCM_ERROR_ENETRESET == in->pcm_error_type) {
+ ALOGD(" %s restarting pcm session on post SSR", __func__);
+ in->standby = false;
+ pthread_mutex_unlock(&in->lock);
+ in_standby(&in->stream.common);
+ pthread_mutex_lock(&in->lock);
+ }
+ }
+
if (in->standby) {
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
@@ -2064,13 +2136,22 @@
memset(buffer, 0, bytes);
exit:
+
+ if (-ENETRESET == ret) {
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+ in->pcm_error_type = PCM_ERROR_ENETRESET;
+ memset(buffer, 0, bytes);
+ in->standby = true; /*standby will be called on post SSR */
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+ }
pthread_mutex_unlock(&in->lock);
if (ret != 0) {
in_standby(&in->stream.common);
ALOGV("%s: read failed - sleeping for buffer duration", __func__);
usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) /
- in_get_sample_rate(&in->stream.common));
+ in_get_sample_rate(&in->stream.common));
}
return bytes;
}
@@ -2398,10 +2479,23 @@
int ret = 0, err;
ALOGD("%s: enter: %s", __func__, kvpairs);
-
- pthread_mutex_lock(&adev->lock);
parms = str_parms_create_str(kvpairs);
+ err = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
+ if (err >= 0) {
+ char *snd_card_status = value+2;
+ pthread_mutex_lock(&adev->snd_card_status.lock);
+ if (strstr(snd_card_status, "OFFLINE")) {
+ ALOGD("Received sound card OFFLINE status");
+ adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+ } else if (strstr(snd_card_status, "ONLINE")) {
+ ALOGD("Received sound card ONLINE status");
+ adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
+ }
+ pthread_mutex_unlock(&adev->snd_card_status.lock);
+ }
+
+ pthread_mutex_lock(&adev->lock);
ret = voice_set_parameters(adev, parms);
if (ret != 0)
goto done;
@@ -2762,6 +2856,9 @@
list_init(&adev->usecase_list);
adev->cur_wfd_channels = 2;
adev->offload_usecases_state = 0;
+
+ 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) {
@@ -2773,6 +2870,8 @@
return -EINVAL;
}
+ 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) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 3115f1a..3f780d3 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -52,6 +52,8 @@
#define MAX_SUPPORTED_CHANNEL_MASKS 2
#define DEFAULT_HDMI_OUT_CHANNELS 2
+#define SND_CARD_STATE_OFFLINE 0
+#define SND_CARD_STATE_ONLINE 1
typedef int snd_device_t;
/* These are the supported use cases by the hardware.
@@ -138,6 +140,12 @@
OFFLOAD_STATE_PAUSED,
};
+enum {
+ PCM_ERROR_NONE,
+ PCM_ERROR_EIO,
+ PCM_ERROR_ENETRESET, /* For SSR */
+};
+
struct offload_cmd {
struct listnode node;
int cmd;
@@ -178,6 +186,7 @@
void *offload_cookie;
struct compr_gapless_mdata gapless_mdata;
int send_new_metadata;
+ int pcm_error_type;
struct audio_device *dev;
};
@@ -196,6 +205,7 @@
bool enable_aec;
bool enable_ns;
audio_format_t format;
+ int pcm_error_type;
struct audio_device *dev;
};
@@ -223,6 +233,11 @@
union stream_ptr stream;
};
+struct sound_card_status {
+ pthread_mutex_t lock;
+ int state;
+};
+
struct audio_device {
struct audio_hw_device device;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -251,6 +266,8 @@
void *offload_effects_lib;
int (*offload_effects_start_output)(audio_io_handle_t, int);
int (*offload_effects_stop_output)(audio_io_handle_t, int);
+
+ struct sound_card_status snd_card_status;
};
int select_devices(struct audio_device *adev,