hal: various fixes for MMAP NO IRQ mode
- Fix NULL reference in error report
- Adjust period count according to requested buffer size in
create_mmap_buffer()
- Exit standby in create_mmap_buffer()
- Do not call pcm_prepare() before pcm_start() as this is reduncdant.
Bug: 35260844
Test: CTS test_aaudio.cpp
Change-Id: Id7a171e26023fb9fc7a10eed47b1eb96be37c75d
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4af1e9c..7a019ba 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -44,6 +44,7 @@
#include <hardware/audio_effect.h>
#include <hardware/audio_alsaops.h>
#include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include "audio_hw.h"
@@ -85,7 +86,9 @@
#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
-#define MMAP_PERIOD_COUNT 512
+#define MMAP_PERIOD_COUNT_MIN 32
+#define MMAP_PERIOD_COUNT_MAX 512
+#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
/* This constant enables extended precision handling.
@@ -144,7 +147,7 @@
.channels = DEFAULT_CHANNEL_COUNT,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = MMAP_PERIOD_SIZE,
- .period_count = MMAP_PERIOD_COUNT,
+ .period_count = MMAP_PERIOD_COUNT_DEFAULT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = MMAP_PERIOD_SIZE*8,
.stop_threshold = INT32_MAX,
@@ -178,7 +181,7 @@
.channels = DEFAULT_CHANNEL_COUNT,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = MMAP_PERIOD_SIZE,
- .period_count = MMAP_PERIOD_COUNT,
+ .period_count = MMAP_PERIOD_COUNT_DEFAULT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = INT_MAX,
@@ -1313,14 +1316,10 @@
select_devices(adev, in->usecase);
if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
- if (!pcm_is_ready(in->pcm)) {
+ if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
ALOGE("%s: pcm stream not ready", __func__);
goto error_open;
}
- ret = pcm_prepare(in->pcm);
- if (ret < 0) {
- ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret);
- goto error_open; }
ret = pcm_start(in->pcm);
if (ret < 0) {
ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
@@ -1738,14 +1737,10 @@
if (adev->offload_effects_start_output != NULL)
adev->offload_effects_start_output(out->handle, out->pcm_device_id);
} else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
- if (!pcm_is_ready(out->pcm)) {
+ if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
ALOGE("%s: pcm stream not ready", __func__);
goto error_open;
}
- ret = pcm_prepare(out->pcm);
- if (ret < 0) {
- ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret);
- goto error_open; }
ret = pcm_start(out->pcm);
if (ret < 0) {
ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
@@ -1921,6 +1916,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
+ bool do_stop = true;
ALOGV("%s: enter: usecase(%d: %s)", __func__,
out->usecase, use_case_table[out->usecase]);
@@ -1937,6 +1933,7 @@
out->pcm = NULL;
}
if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+ do_stop = out->playback_started;
out->playback_started = false;
}
} else {
@@ -1948,7 +1945,9 @@
out->compr = NULL;
}
}
- stop_output_stream(out);
+ if (do_stop) {
+ stop_output_stream(out);
+ }
pthread_mutex_unlock(&adev->lock);
}
pthread_mutex_unlock(&out->lock);
@@ -2575,9 +2574,7 @@
out->playback_started && out->pcm != NULL) {
pcm_stop(out->pcm);
ret = stop_output_stream(out);
- if (ret == 0) {
- out->playback_started = false;
- }
+ out->playback_started = false;
}
pthread_mutex_unlock(&adev->lock);
return ret;
@@ -2602,6 +2599,26 @@
return ret;
}
+/*
+ * Modify config->period_count based on min_size_frames
+ */
+static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
+{
+ int periodCountRequested = (min_size_frames + config->period_size - 1)
+ / config->period_size;
+ int periodCount = MMAP_PERIOD_COUNT_MIN;
+
+ ALOGV("%s original config.period_size = %d config.period_count = %d",
+ __func__, config->period_size, config->period_count);
+
+ while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
+ periodCount *= 2;
+ }
+ config->period_count = periodCount;
+
+ ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
+}
+
static int out_create_mmap_buffer(const struct audio_stream_out *stream,
int32_t min_size_frames,
struct audio_mmap_buffer_info *info)
@@ -2617,10 +2634,12 @@
pthread_mutex_lock(&adev->lock);
if (info == NULL || min_size_frames == 0) {
+ ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
ret = -EINVAL;
goto exit;
}
if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
+ ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
ret = -ENOSYS;
goto exit;
}
@@ -2631,6 +2650,9 @@
ret = -EINVAL;
goto exit;
}
+
+ adjust_mmap_period_count(&out->config, min_size_frames);
+
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
__func__, adev->snd_card, out->pcm_device_id, out->config.channels);
out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
@@ -2657,6 +2679,8 @@
step = "commit";
goto exit;
}
+
+ out->standby = false;
ret = 0;
ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
@@ -2664,8 +2688,10 @@
exit:
if (ret != 0) {
- ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
- if (out->pcm != NULL) {
+ if (out->pcm == NULL) {
+ ALOGE("%s: %s - %d", __func__, step, ret);
+ } else {
+ ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
pcm_close(out->pcm);
out->pcm = NULL;
}
@@ -2744,6 +2770,8 @@
struct stream_in *in = (struct stream_in *)stream;
struct audio_device *adev = in->dev;
int status = 0;
+ bool do_stop = true;
+
ALOGV("%s: enter", __func__);
lock_input_stream(in);
@@ -2761,6 +2789,7 @@
pthread_mutex_lock(&adev->lock);
in->standby = true;
if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+ do_stop = in->capture_started;
in->capture_started = false;
}
if (in->pcm) {
@@ -2769,7 +2798,9 @@
}
adev->enable_voicerx = false;
platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE );
- status = stop_input_stream(in);
+ if (do_stop) {
+ status = stop_input_stream(in);
+ }
pthread_mutex_unlock(&adev->lock);
}
pthread_mutex_unlock(&in->lock);
@@ -3074,9 +3105,7 @@
in->capture_started && in->pcm != NULL) {
pcm_stop(in->pcm);
ret = stop_input_stream(in);
- if (ret == 0) {
- in->capture_started = false;
- }
+ in->capture_started = false;
}
pthread_mutex_unlock(&adev->lock);
return ret;
@@ -3116,12 +3145,14 @@
pthread_mutex_lock(&adev->lock);
ALOGV("%s in %p", __func__, in);
+
if (info == NULL || min_size_frames == 0) {
- ALOGV("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
+ ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
ret = -EINVAL;
goto exit;
}
if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
+ ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
ALOGV("%s in %p", __func__, in);
ret = -ENOSYS;
goto exit;
@@ -3133,6 +3164,9 @@
ret = -EINVAL;
goto exit;
}
+
+ adjust_mmap_period_count(&in->config, min_size_frames);
+
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
__func__, adev->snd_card, in->pcm_device_id, in->config.channels);
in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
@@ -3161,14 +3195,18 @@
goto exit;
}
+ in->standby = false;
+ ret = 0;
+
ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
__func__, info->shared_memory_address, info->buffer_size_frames);
- ret = 0;
exit:
if (ret != 0) {
- ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
- if (in->pcm != NULL) {
+ if (in->pcm == NULL) {
+ ALOGE("%s: %s - %d", __func__, step, ret);
+ } else {
+ ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
pcm_close(in->pcm);
in->pcm = NULL;
}