agm: fix infinite loop for mmap poll
This reverts fb0fcde8d99dc566ad5053847910a10c33a64ba2
and come with a more generic solution.
Previous solution checks for default sound card status,
while if a dynamic sound card such as USB headset may also
be unvailable during playback, this can still cause
infinite loop waiting for available buffers.
Instead, check for time in waiting for available
buffers, if real time elapsed is much longer than
expected buffer size, prompt an error to indicate
possible under layer failures.
Change-Id: Iccfba9c21299fb8e6eb7c6fb812b490fd92bf664
diff --git a/plugins/tinyalsa/src/agm_pcm_plugin.c b/plugins/tinyalsa/src/agm_pcm_plugin.c
index 176a218..92561fc 100644
--- a/plugins/tinyalsa/src/agm_pcm_plugin.c
+++ b/plugins/tinyalsa/src/agm_pcm_plugin.c
@@ -59,7 +59,8 @@
#define AGM_PULL_PUSH_IDX_RETRY_COUNT 2
#define AGM_PULL_PUSH_FRAME_CNT_RETRY_COUNT 5
-#define SNDCARD_PATH "/sys/kernel/snd_card/card_state"
+/* multiplier of timeout for wating for mmap buffers */
+#define MMAP_TOUT_MULTI 4
struct agm_shared_pos_buffer {
volatile uint32_t frame_counter;
@@ -100,7 +101,7 @@
/* idx: 0: out port, 1: in port */
struct agm_mmap_buffer_port mmap_buffer_port[2];
bool mmap_status;
- int fd;
+ uint32_t mmap_buf_tout;
};
struct pcm_plugin_hw_constraints agm_pcm_constrs = {
@@ -310,28 +311,6 @@
return -EAGAIN;
}
-static int agm_pcm_plugin_get_card_status(struct agm_pcm_priv *priv)
-{
- char buf[10];
- int card_status = -1;
-
- if (priv->fd < 0) {
- if ((priv->fd = open(SNDCARD_PATH, O_RDWR)) < 0) {
- AGM_LOGE(LOG_TAG, "Open failed snd sysfs node");
- errno = ENETRESET;
- return -ENETRESET;
- }
- AGM_LOGD(LOG_TAG, "Snd sysfs node open successful");
- }
-
- memset(buf, 0, sizeof(buf));
- read(priv->fd, buf, 1);
- lseek(priv->fd, 0L, SEEK_SET);
- sscanf(buf, "%d", &card_status);
-
- return card_status;
-}
-
static int agm_pcm_plugin_update_hw_ptr(struct agm_pcm_priv *priv)
{
int retries = 10;
@@ -344,15 +323,8 @@
int ret = 0;
uint32_t period_size = priv->period_size; /** in frames */
uint32_t crossed_boundary = 0;
- int card_status = -1;
uint32_t old_frame_counter = priv->pos_buf->frame_counter;
- card_status = agm_pcm_plugin_get_card_status(priv);
- if (card_status != 1) { // 1 assume to be snd card status online
- AGM_LOGE("%s: Snd card is Offline\n", __func__);
- errno = ENETRESET;
- return -ENETRESET;
- }
do {
ret = agm_pcm_plugin_get_shared_pos(priv->pos_buf,
&read_index, &wall_clk_msw, &wall_clk_lsw);
@@ -727,10 +699,6 @@
close(priv->buf_info->data_buf_fd);
free(priv->buf_info);
}
- if (priv->fd >= 0) {
- close(priv->fd);
- priv->fd = -1;
- }
free(plugin->priv);
free(plugin);
@@ -767,6 +735,7 @@
uint32_t period_size = priv->period_size;
snd_pcm_sframes_t avail;
int ret = 0;
+ uint32_t period_to_msec = period_size / (priv->media_config->rate / 1000);
avail = agm_pcm_get_avail(plugin);
@@ -777,8 +746,6 @@
ret = agm_pcm_plugin_update_hw_ptr(priv);
if (ret == 0)
avail = agm_pcm_get_avail(plugin);
- else if (ret == -ENETRESET)
- return ret;
}
if (avail >= period_size) {
@@ -789,8 +756,16 @@
pfd->revents = POLLOUT;
ret = POLLOUT;
}
+ priv->mmap_buf_tout = 0;
} else {
ret = 0; /* TIMEOUT */
+ priv->mmap_buf_tout += timeout;
+ if (priv->mmap_buf_tout > (period_to_msec * MMAP_TOUT_MULTI)) {
+ AGM_LOGE("timeout in waiting for mmap buffer");
+ priv->mmap_buf_tout = 0;
+ errno = ETIMEDOUT;
+ return -ETIMEDOUT;
+ }
}
return ret;
@@ -967,13 +942,6 @@
goto err_buf_free;
}
- priv->fd = -1;
- if ((priv->fd = open(SNDCARD_PATH, O_RDWR)) < 0) {
- AGM_LOGE(LOG_TAG, "Open failed snd sysfs node");
- ret = -EINVAL;
- goto err_session_free;
- }
-
card_node = snd_card_def_get_card(card);
if (!card_node) {
ret = -EINVAL;
@@ -1021,10 +989,6 @@
err_card_put:
snd_card_def_put_card(card_node);
err_session_free:
- if (priv->fd >= 0) {
- close(priv->fd);
- priv->fd = -1;
- }
free(session_config);
err_buf_free:
free(buffer_config);