summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2012-05-11 09:17:27 -0700
committerEric Laurent <elaurent@google.com>2012-05-14 18:26:21 -0700
commit2bdfb1ab764c5a7983c6b7c8baa9555e53039bb3 (patch)
tree3d673777ff3a11a3538a9bef4d19936410251194 /audio
parentd3fab12208f3fe5fde070015d2447b1862a37d7e (diff)
downloaddevice_samsung_tuna-2bdfb1ab764c5a7983c6b7c8baa9555e53039bb3.zip
device_samsung_tuna-2bdfb1ab764c5a7983c6b7c8baa9555e53039bb3.tar.gz
device_samsung_tuna-2bdfb1ab764c5a7983c6b7c8baa9555e53039bb3.tar.bz2
audio: variable deep buffer size
Add back the capability to change the deep buffer size according to screen state. This solves various issues related to audio focus, volume and pause control that arise with large audio buffers. Those issues should be ultimately addressed by changes in the audio framework. Change-Id: I6889ecf0e5d8740745152261f27343e1ff533e7b
Diffstat (limited to 'audio')
-rw-r--r--audio/audio_hw.c112
1 files changed, 92 insertions, 20 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index b781b29..54ee3c8 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -125,8 +125,10 @@
#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
+/* deep buffer short period (screen on) in milliseconds */
+#define DEEP_BUFFER_SHORT_PERIOD_MS 22
+/* deep buffer long period (screen off) in milliseconds */
+#define DEEP_BUFFER_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
@@ -143,12 +145,22 @@
/* 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 */
-#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 base blocks in a short deep buffer period (screen on) */
+#define DEEP_BUFFER_SHORT_PERIOD_MULTIPLIER (DEEP_BUFFER_SHORT_PERIOD_MS * MULTIPLIER_FACTOR)
+/* number of frames per short deep buffer period (screen on) */
+#define DEEP_BUFFER_SHORT_PERIOD_SIZE (ABE_BASE_FRAME_COUNT * DEEP_BUFFER_SHORT_PERIOD_MULTIPLIER)
+/* number of periods for deep buffer playback (screen on) */
+#define PLAYBACK_DEEP_BUFFER_SHORT_PERIOD_COUNT 4
+
+/* number of short deep buffer periods in a long period */
+#define DEEP_BUFFER_LONG_PERIOD_MULTIPLIER \
+ (DEEP_BUFFER_LONG_PERIOD_MS / DEEP_BUFFER_SHORT_PERIOD_MS)
+/* number of frames per long deep buffer period (screen off) */
+#define DEEP_BUFFER_LONG_PERIOD_SIZE \
+ (DEEP_BUFFER_SHORT_PERIOD_SIZE * DEEP_BUFFER_LONG_PERIOD_MULTIPLIER)
+/* number of periods for deep buffer playback (screen off) */
+#define PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT 2
+
/* 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
@@ -276,11 +288,11 @@ enum tty_modes {
struct pcm_config pcm_config_mm = {
.channels = 2,
.rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = LONG_PERIOD_SIZE,
- .period_count = PLAYBACK_LONG_PERIOD_COUNT,
+ .period_size = DEEP_BUFFER_LONG_PERIOD_SIZE,
+ .period_count = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
- .start_threshold = LONG_PERIOD_SIZE,
- .avail_min = LONG_PERIOD_SIZE,
+ .start_threshold = DEEP_BUFFER_SHORT_PERIOD_SIZE * 2,
+ .avail_min = DEEP_BUFFER_LONG_PERIOD_SIZE,
};
struct pcm_config pcm_config_tones = {
@@ -616,6 +628,7 @@ struct tuna_audio_device {
bool bluetooth_nrec;
bool device_is_toro;
int wb_amr;
+ bool screen_off;
/* RIL */
struct ril_handle ril;
@@ -639,6 +652,9 @@ struct tuna_stream_out {
size_t buffer_frames;
int standby;
struct echo_reference_itfe *echo_reference;
+ int write_threshold;
+ bool use_long_periods;
+
struct tuna_audio_device *dev;
};
@@ -1387,6 +1403,9 @@ static int start_output_stream_deep_buffer(struct tuna_stream_out *out)
select_output_device(adev);
}
+ out->write_threshold = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT * DEEP_BUFFER_LONG_PERIOD_SIZE;
+ out->use_long_periods = true;
+
out->config[PCM_NORMAL] = pcm_config_mm;
out->config[PCM_NORMAL].rate = MM_FULL_POWER_SAMPLING_RATE;
out->pcm[PCM_NORMAL] = pcm_open(CARD_TUNA_DEFAULT, PORT_MM,
@@ -1397,7 +1416,7 @@ static int start_output_stream_deep_buffer(struct tuna_stream_out *out)
out->pcm[PCM_NORMAL] = NULL;
return -ENOMEM;
}
- out->buffer_frames = pcm_config_mm.period_size * 2;
+ out->buffer_frames = DEEP_BUFFER_SHORT_PERIOD_SIZE * 2;
if (out->buffer == NULL)
out->buffer = malloc(out->buffer_frames * audio_stream_frame_size(&out->stream.common));
@@ -1574,7 +1593,8 @@ static size_t out_get_buffer_size_deep_buffer(const struct audio_stream *stream)
multiple of 16 frames, as audioflinger expects audio buffers to
be a multiple of 16 frames. Note: we use the default rate here
from pcm_config_mm.rate. */
- size_t size = (LONG_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / pcm_config_mm.rate;
+ size_t size = (DEEP_BUFFER_SHORT_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) /
+ pcm_config_mm.rate;
size = ((size + 15) / 16) * 16;
return size * audio_stream_frame_size((struct audio_stream *)stream);
}
@@ -1738,7 +1758,8 @@ static uint32_t out_get_latency_deep_buffer(const struct audio_stream_out *strea
struct tuna_stream_out *out = (struct tuna_stream_out *)stream;
/* Note: we use the default rate here from pcm_config_mm.rate */
- return (LONG_PERIOD_SIZE * PLAYBACK_LONG_PERIOD_COUNT * 1000) / pcm_config_mm.rate;
+ return (DEEP_BUFFER_LONG_PERIOD_SIZE * PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT * 1000) /
+ pcm_config_mm.rate;
}
static int out_set_volume(struct audio_stream_out *stream, float left,
@@ -1847,6 +1868,10 @@ static ssize_t out_write_deep_buffer(struct audio_stream_out *stream, const void
struct tuna_audio_device *adev = out->dev;
size_t frame_size = audio_stream_frame_size(&out->stream.common);
size_t in_frames = bytes / frame_size;
+ size_t out_frames;
+ bool use_long_periods;
+ int kernel_frames;
+ void *buf;
/* acquiring hw device mutex systematically is useful if a low priority thread is waiting
* on the output stream mutex - e.g. executing select_mode() while holding the hw device
@@ -1862,20 +1887,59 @@ static ssize_t out_write_deep_buffer(struct audio_stream_out *stream, const void
}
out->standby = 0;
}
+ use_long_periods = adev->screen_off && !adev->active_input;
pthread_mutex_unlock(&adev->lock);
+ if (use_long_periods != out->use_long_periods) {
+ size_t period_size;
+ size_t period_count;
+
+ if (use_long_periods) {
+ period_size = DEEP_BUFFER_LONG_PERIOD_SIZE;
+ period_count = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT;
+ } else {
+ period_size = DEEP_BUFFER_SHORT_PERIOD_SIZE;
+ period_count = PLAYBACK_DEEP_BUFFER_SHORT_PERIOD_COUNT;
+ }
+ out->write_threshold = period_size * period_count;
+ pcm_set_avail_min(out->pcm[PCM_NORMAL], period_size);
+ out->use_long_periods = use_long_periods;
+ }
+
/* only use resampler if required */
if (out->config[PCM_NORMAL].rate != DEFAULT_OUT_SAMPLING_RATE) {
- size_t out_frames = out->buffer_frames;
-
+ out_frames = out->buffer_frames;
out->resampler->resample_from_input(out->resampler,
(int16_t *)buffer,
&in_frames,
(int16_t *)out->buffer,
&out_frames);
- ret = pcm_mmap_write(out->pcm[PCM_NORMAL], (void *)out->buffer, out_frames * frame_size);
- } else
- ret = pcm_mmap_write(out->pcm[PCM_NORMAL], (void *)buffer, bytes);
+ buf = (void *)out->buffer;
+ } else {
+ out_frames = in_frames;
+ buf = (void *)buffer;
+ }
+
+ /* do not allow more than out->write_threshold frames in kernel pcm driver buffer */
+ do {
+ struct timespec time_stamp;
+
+ if (pcm_get_htimestamp(out->pcm[PCM_NORMAL],
+ (unsigned int *)&kernel_frames, &time_stamp) < 0)
+ break;
+ kernel_frames = pcm_get_buffer_size(out->pcm[PCM_NORMAL]) - kernel_frames;
+
+ if (kernel_frames > out->write_threshold) {
+ unsigned long time = (unsigned long)
+ (((int64_t)(kernel_frames - out->write_threshold) * 1000000) /
+ MM_FULL_POWER_SAMPLING_RATE);
+ if (time < MIN_WRITE_SLEEP_US)
+ time = MIN_WRITE_SLEEP_US;
+ usleep(time);
+ }
+ } while (kernel_frames > out->write_threshold);
+
+ ret = pcm_mmap_write(out->pcm[PCM_NORMAL], buf, out_frames * frame_size);
exit:
pthread_mutex_unlock(&out->lock);
@@ -3075,6 +3139,14 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
adev->bluetooth_nrec = false;
}
+ ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
+ if (ret >= 0) {
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+ adev->screen_off = false;
+ else
+ adev->screen_off = true;
+ }
+
str_parms_destroy(parms);
return ret;
}