summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-02-14 13:54:03 -0800
committerGlenn Kasten <gkasten@google.com>2012-04-27 16:01:44 -0700
commit4f1b21a8e4234651af3c2596d4be1f049a2901f9 (patch)
tree46f1018c8ee36c7c71495750266bde6a6305f2cb
parente1021ba213319c88c47bcc97ab6b35c4193620e0 (diff)
downloaddevice_samsung_tuna-4f1b21a8e4234651af3c2596d4be1f049a2901f9.zip
device_samsung_tuna-4f1b21a8e4234651af3c2596d4be1f049a2901f9.tar.gz
device_samsung_tuna-4f1b21a8e4234651af3c2596d4be1f049a2901f9.tar.bz2
Adjust output buffer size and sample rate
Use 4 buffers of 96 frames each = 4 ms at 48 kHz. Keep the 44.1 kHz -> 48 kHz up-sampler in HAL. Disable mmap mode and non-IRQ mode; this gives better variance for cycle times. Reduce number of buffers from 4 to 2, works OK in non-mmap mode but not mmap mode. Update comments based on code review. Tested with audio input. Not yet tested with echo cancellation. Change-Id: I69db00ab408cd2aad5788d602eb01fc0c7e4e78b
-rw-r--r--audio/audio_hw.c88
1 files changed, 78 insertions, 10 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index 403e5f3..aea5677 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -116,20 +116,70 @@
#define PORT_SPDIF 9
#define PORT_HDMI 0
-/* constraint imposed by ABE: all period sizes must be multiples of 24 */
+/* User serviceable */
+/* #define to use mmap no-irq mode for playback, #undef for non-mmap irq mode */
+#undef PLAYBACK_MMAP // was #define
+/* short period (aka low latency) in milliseconds */
+#define SHORT_PERIOD_MS 4 // was 22
+/* long period (aka low power or deep buffer) in milliseconds */
+#define LONG_PERIOD_MS 308
+
+/* Constraint imposed by ABE: for playback, all period sizes must be multiples of 24 frames
+ * = 500 us at 48 kHz. It seems to be either 48 or 96 for capture, or maybe it is because the
+ * limitation is actually a min number of bytes which translates to a different amount of frames
+ * according to the number of channels.
+ */
#define ABE_BASE_FRAME_COUNT 24
+
+/* Derived from MM_FULL_POWER_SAMPLING_RATE=48000 and ABE_BASE_FRAME_COUNT=24 */
+#define MULTIPLIER_FACTOR 2
+
/* number of base blocks in a short period (low latency) */
-#define SHORT_PERIOD_MULTIPLIER 44 /* 22 ms */
+#define SHORT_PERIOD_MULTIPLIER (SHORT_PERIOD_MS * MULTIPLIER_FACTOR)
/* number of frames per short period (low latency) */
#define SHORT_PERIOD_SIZE (ABE_BASE_FRAME_COUNT * SHORT_PERIOD_MULTIPLIER)
-/* number of short periods in a long period (low power) */
-#define LONG_PERIOD_MULTIPLIER 14 /* 308 ms */
+
+/* number of short periods in a long period */
+#define LONG_PERIOD_MULTIPLIER (LONG_PERIOD_MS / SHORT_PERIOD_MS)
/* number of frames per long period (low power) */
#define LONG_PERIOD_SIZE (SHORT_PERIOD_SIZE * LONG_PERIOD_MULTIPLIER)
/* number of periods for low power playback */
#define PLAYBACK_LONG_PERIOD_COUNT 2
-/* number of pseudo periods for low latency playback */
+/* Number of pseudo periods for low latency playback.
+ * These are called "pseudo" periods in that they are not known as periods by ALSA.
+ * Formerly, ALSA was configured in MMAP mode with 2 large periods, and this
+ * number was set to 4 (2 didn't work).
+ * The short periods size and count were only known by the audio HAL.
+ * Now for low latency, we are using non-MMAP mode and can set this to 2.
+ */
+#ifdef PLAYBACK_MMAP
#define PLAYBACK_SHORT_PERIOD_COUNT 4
+#else
+#define PLAYBACK_SHORT_PERIOD_COUNT 2
+#endif
+
+/* write function */
+#ifdef PLAYBACK_MMAP
+#define PCM_WRITE pcm_mmap_write
+#else
+#define PCM_WRITE pcm_write
+#endif
+
+/* User serviceable */
+#define CAPTURE_PERIOD_MS 22
+
+/* Number of frames per period for capture. This cannot be reduced below 96.
+ * Possibly related to the following rule in sound/soc/omap/omap-pcm.c:
+ * ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 384);
+ * (where 96 * 4 = 384)
+ * The only constraints I can find are periods_min = 2, period_bytes_min = 32.
+ * If you define RULES_DEBUG in sound/core/pcm_native.c, you can see which rule
+ * caused capture to fail.
+ * Decoupling playback and capture period size may have impacts on echo canceler behavior:
+ * to be verified. Currently 96 = 4 x 24 but it could be changed without noticing
+ * if we use separate defines.
+ */
+#define CAPTURE_PERIOD_SIZE (ABE_BASE_FRAME_COUNT * CAPTURE_PERIOD_MS * MULTIPLIER_FACTOR)
/* number of periods for capture */
#define CAPTURE_PERIOD_COUNT 2
/* minimum sleep time in out_write() when write threshold is not reached */
@@ -138,12 +188,12 @@
#define RESAMPLER_BUFFER_FRAMES (SHORT_PERIOD_SIZE * 2)
#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
-#define DEFAULT_OUT_SAMPLING_RATE 44100
+#define DEFAULT_OUT_SAMPLING_RATE 44100 // 48000 is possible but interacts poorly with HDMI
/* sampling rate when using MM low power port */
#define MM_LOW_POWER_SAMPLING_RATE 44100
/* sampling rate when using MM full power port */
-#define MM_FULL_POWER_SAMPLING_RATE 48000
+#define MM_FULL_POWER_SAMPLING_RATE 48000 // affects MULTIPLIER_FACTOR
/* sampling rate when using VX port for narrow band */
#define VX_NB_SAMPLING_RATE 8000
/* sampling rate when using VX port for wide band */
@@ -225,17 +275,27 @@ enum tty_modes {
struct pcm_config pcm_config_mm = {
.channels = 2,
.rate = MM_FULL_POWER_SAMPLING_RATE,
+#ifdef PLAYBACK_MMAP
.period_size = LONG_PERIOD_SIZE,
.period_count = PLAYBACK_LONG_PERIOD_COUNT,
+#else
+ .period_size = SHORT_PERIOD_SIZE,
+ .period_count = PLAYBACK_SHORT_PERIOD_COUNT,
+#endif
.format = PCM_FORMAT_S16_LE,
+#ifdef PLAYBACK_MMAP
.start_threshold = SHORT_PERIOD_SIZE * 2,
.avail_min = LONG_PERIOD_SIZE,
+#else
+ .start_threshold = 0,
+ .avail_min = 0,
+#endif
};
struct pcm_config pcm_config_mm_ul = {
.channels = 2,
.rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = SHORT_PERIOD_SIZE,
+ .period_size = CAPTURE_PERIOD_SIZE,
.period_count = CAPTURE_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
};
@@ -1181,7 +1241,11 @@ static void select_input_device(struct tuna_audio_device *adev)
static int start_output_stream(struct tuna_stream_out *out)
{
struct tuna_audio_device *adev = out->dev;
+#ifdef PLAYBACK_MMAP
unsigned int flags = PCM_OUT | PCM_MMAP | PCM_NOIRQ;
+#else
+ unsigned int flags = PCM_OUT;
+#endif
int i;
bool success = true;
@@ -1589,6 +1653,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
low_power = adev->low_power && !adev->active_input;
pthread_mutex_unlock(&adev->lock);
+#ifdef PLAYBACK_MMAP
if (low_power != out->low_power) {
if (low_power) {
out->write_threshold = LONG_PERIOD_SIZE * PLAYBACK_LONG_PERIOD_COUNT;
@@ -1600,6 +1665,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
}
out->low_power = low_power;
}
+#endif
for (i = 0; i < PCM_TOTAL; i++) {
if (out->pcm[i]) {
@@ -1634,6 +1700,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
out->echo_reference->write(out->echo_reference, &b);
}
+#ifdef PLAYBACK_MMAP
/* do not allow more than out->write_threshold frames in kernel pcm driver buffer */
do {
struct timespec time_stamp;
@@ -1651,16 +1718,17 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
usleep(time);
}
} while (kernel_frames > out->write_threshold);
+#endif
/* Write to all active PCMs */
for (i = 0; i < PCM_TOTAL; i++) {
if (out->pcm[i]) {
if (out->config[i].rate == DEFAULT_OUT_SAMPLING_RATE) {
/* PCM uses native sample rate */
- ret = pcm_mmap_write(out->pcm[i], (void *)buffer, bytes);
+ ret = PCM_WRITE(out->pcm[i], (void *)buffer, bytes);
} else {
/* PCM needs resampler */
- ret = pcm_mmap_write(out->pcm[i], (void *)out->buffer, out_frames * frame_size);
+ ret = PCM_WRITE(out->pcm[i], (void *)out->buffer, out_frames * frame_size);
}
if (ret)
break;