summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorArun Raghavan <arun.raghavan@collabora.co.uk>2012-01-20 13:22:36 +0530
committerArun Raghavan <arun.raghavan@collabora.co.uk>2012-01-20 13:36:28 +0530
commit80f8586a3f2e08de52f2c10f1956d4eafb988600 (patch)
tree0f85e63ed6a4877436adcdc59c03c0e92656e5a4 /tests
parentb445f166c7c1153fb16540ddd3ea4781a9335485 (diff)
Add test program and scripts
Diffstat (limited to 'tests')
-rw-r--r--tests/Android.mk22
-rw-r--r--tests/audio_test.cpp382
-rwxr-xr-xtests/run_all.sh47
-rwxr-xr-xtests/run_test.sh42
4 files changed, 493 insertions, 0 deletions
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..4ebb3a2
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:=$(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_MODULE := audio_test
+
+LOCAL_MODULE_TAGS:=eng debug
+
+LOCAL_SRC_FILES := \
+ audio_test.cpp
+
+LOCAL_C_INCLUDES := \
+ system/core/include \
+ frameworks/base/include
+
+LOCAL_SHARED_LIBRARIES:= \
+ libmedia \
+ libpulse
+
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_EXECUTABLE)
diff --git a/tests/audio_test.cpp b/tests/audio_test.cpp
new file mode 100644
index 0000000..8ea5334
--- /dev/null
+++ b/tests/audio_test.cpp
@@ -0,0 +1,382 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <semaphore.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <system/audio.h>
+#include <media/AudioTrack.h>
+
+#include <pulse/pulseaudio.h>
+
+#if 0
+#define DEBUG 1
+#define DEBUG_TIMING 1
+#endif
+
+#if 0
+#define LATENCY_TEST 1
+#endif
+
+#ifdef DEBUG
+#define DEBUG_PRINT(...) printf(__VA_ARGS__)
+#define ERROR_PRINT(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG_PRINT(...) do { } while (0)
+#define ERROR_PRINT(...) do { } while (0)
+#endif
+
+#ifdef DEBUG_TIMING
+#include <sys/time.h>
+#endif
+
+using namespace android;
+
+struct userdata {
+ int fd;
+ sem_t sem;
+
+ int rate, latency;
+
+ AudioTrack *at;
+
+ pa_threaded_mainloop *ml;
+ pa_context *c;
+ pa_stream *s;
+
+ volatile int play;
+} ud;
+
+void _af_cb(int event, void *user, void *info)
+{
+ struct userdata *u = (struct userdata *) user;
+
+ switch (event) {
+ case AudioTrack::EVENT_MORE_DATA:
+ {
+ int ret;
+ AudioTrack::Buffer *buf = (AudioTrack::Buffer *) info;
+#ifdef DEBUG_TIMING
+ static struct timeval tv1, tv2;
+#endif
+
+ if (ud.play)
+ ret = read(u->fd, buf->raw, buf->size);
+ else {
+ memset(buf->raw, 0, buf->size);
+ ret = buf->size;
+ }
+
+ if (ret < 0) {
+ perror("Read failed:");
+ exit(EXIT_FAILURE);
+ }
+
+ buf->size = ret;
+
+ if (ret == 0) {
+ sem_post(&u->sem);
+ return;
+ }
+
+#ifdef DEBUG_TIMING
+ gettimeofday(&tv2, NULL);
+ DEBUG_PRINT("[%llu] ", (unsigned long long)
+ ((tv2.tv_sec * 1000000L) + tv2.tv_usec) -
+ ((tv1.tv_sec * 1000000L) + tv1.tv_usec));
+ tv1 = tv2;
+#endif
+
+ DEBUG_PRINT("More data (%d)\n", buf->size);
+
+ break;
+ }
+
+ case AudioTrack::EVENT_UNDERRUN:
+ DEBUG_PRINT("Underrun\n");
+ break;
+
+ case AudioTrack::EVENT_LOOP_END:
+ DEBUG_PRINT("Loop end\n");
+ break;
+
+ case AudioTrack::EVENT_MARKER:
+ DEBUG_PRINT("Marker\n");
+ break;
+
+ case AudioTrack::EVENT_NEW_POS:
+ DEBUG_PRINT("New pos\n");
+ break;
+
+ case AudioTrack::EVENT_BUFFER_END:
+ DEBUG_PRINT("Buffer end\n");
+ break;
+ }
+}
+
+void _pa_stream_write_cb(pa_stream *s, size_t size, void *user)
+{
+ static int once = 0;
+ struct userdata *u = (struct userdata *) user;
+ size_t m_size, orig_size = size;
+ int ret;
+ void *m_buf;
+#ifdef DEBUG_TIMING
+ static struct timeval tv1, tv2;
+#endif
+
+ if (!once) {
+ pa_usec_t l;
+
+ if (pa_stream_get_latency(s, &l, NULL) == 0) {
+ printf("Total latency: %llu\n", (unsigned long long) l);
+ once = 1;
+ }
+ }
+
+
+ while (size) {
+ m_size = size;
+ if (pa_stream_begin_write(s, &m_buf, &m_size) < 0) {
+ ERROR_PRINT("Begin write failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (ud.play)
+ ret = read(u->fd, m_buf, m_size);
+ else {
+ memset(m_buf, 0, m_size);
+ ret = m_size;
+ }
+
+ if (ret < 0) {
+ perror("Read failed:");
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret == 0) {
+ sem_post(&u->sem);
+ return;
+ }
+
+ m_size = ret;
+ size -= m_size;
+ pa_stream_write(s, m_buf, m_size, NULL, 0, PA_SEEK_RELATIVE);
+
+ DEBUG_PRINT("wrote %u\n", m_size);
+ }
+
+#ifdef DEBUG_TIMING
+ gettimeofday(&tv2, NULL);
+ DEBUG_PRINT("[%llu] ", (unsigned long long)
+ ((tv2.tv_sec * 1000000L) + tv2.tv_usec) -
+ ((tv1.tv_sec * 1000000L) + tv1.tv_usec));
+ tv1 = tv2;
+#endif
+
+ DEBUG_PRINT("More data (%d)\n", orig_size);
+}
+
+void _pa_context_cb(pa_context *c, void *user)
+{
+ struct userdata *u = (struct userdata *) user;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY: {
+ pa_sample_spec ss;
+ pa_buffer_attr attr = { -1, -1, -1, -1, -1 };
+
+ ss.format = PA_SAMPLE_S16LE;
+ ss.rate = u->rate;
+ ss.channels = 2;
+
+ u->s = pa_stream_new(c, "Playback test", &ss, NULL);
+
+ if (u->latency > 0)
+ attr.tlength = (pa_bytes_per_second(&ss) * u->latency) / 1000;
+
+ pa_stream_set_write_callback(u->s, _pa_stream_write_cb, u);
+
+ if (pa_stream_connect_playback(u->s,
+ NULL,
+ &attr,
+ (pa_stream_flags_t) (PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_START_UNMUTED),
+ NULL,
+ NULL) < 0) {
+ ERROR_PRINT("Error creating stream\n");
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+ }
+
+ case PA_CONTEXT_FAILED:
+ exit(EXIT_FAILURE);
+ break;
+
+ case PA_CONTEXT_TERMINATED:
+ exit(EXIT_SUCCESS);
+ break;
+
+ default:
+ break;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ enum {
+ AUDIOFLINGER,
+ PULSEAUDIO,
+ };
+
+ int opt;
+ int backend = AUDIOFLINGER;
+ status_t ret;
+
+ struct option long_opts[] = {
+ { "rate", required_argument, NULL, 'r' },
+ { "latency", required_argument, NULL, 'l' },
+ { "backend", required_argument, NULL, 'b' },
+ { 0, 0, 0, 0},
+ };
+
+ if (argc < 2) {
+ ERROR_PRINT("-ENOTENOUGHARGUMENTS\n");
+ return -1;
+ }
+
+ ud.rate = 44100;
+ ud.latency = 0;
+
+ while ((opt = getopt_long(argc, argv, "r:l:b:", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'r':
+ errno = 0;
+ ud.rate = strtol(optarg, NULL, 0);
+
+ if (errno || !ud.rate) {
+ ERROR_PRINT("Bad rate\n");
+ return -1;
+ }
+
+ break;
+
+ case 'l':
+ errno = 0;
+ ud.latency = strtol(optarg, NULL, 0);
+
+ if (errno || !ud.latency) {
+ ERROR_PRINT("Bad latency\n");
+ return -1;
+ }
+
+ break;
+
+ case 'b':
+ if (strcmp(optarg, "af") == 0)
+ backend = AUDIOFLINGER;
+ else if (strcmp(optarg, "pa") == 0)
+ backend = PULSEAUDIO;
+ else {
+ ERROR_PRINT("Invalid backend\n");
+ return -1;
+ }
+
+ break;
+
+ default:
+ ERROR_PRINT("Bad arguments");
+ return -1;
+ }
+ }
+
+ if (optind != argc -1) {
+ ERROR_PRINT("Bad argument count\n");
+ return -1;
+ }
+
+ ud.fd = open(argv[optind], O_RDONLY);
+ if (ud.fd < 0) {
+ perror("Error opening file:");
+ return -1;
+ }
+
+ printf("Rate: %d\n", ud.rate);
+ printf("Req. latency: %d\n", ud.latency);
+
+ sem_init(&ud.sem, 0, 0);
+
+ if (backend == AUDIOFLINGER) {
+ ud.at = new AudioTrack(AUDIO_STREAM_MUSIC,
+ ud.rate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_OUT_STEREO,
+ ud.latency * (ud.rate / 1000),
+ 0,
+ _af_cb,
+ &ud);
+
+ ret = ud.at->initCheck();
+ if (ret != NO_ERROR) {
+ ERROR_PRINT("Init failed, wtf. %d\n", ret);
+ return -1;
+ }
+
+ ud.at->start();
+
+ printf("Total latency: %u\n", ud.at->latency());
+ } else {
+ ud.ml = pa_threaded_mainloop_new();
+ ud.c = pa_context_new(pa_threaded_mainloop_get_api(ud.ml), "Playback test");
+
+ pa_context_set_state_callback(ud.c, _pa_context_cb, &ud);
+
+ if (pa_context_connect(ud.c, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
+ ERROR_PRINT("Failed to connect context");
+ return -1;
+ }
+
+ pa_threaded_mainloop_start(ud.ml);
+ }
+
+#ifdef LATENCY_TEST
+ ud.play = 0;
+ fgetc(stdin);
+ ud.play = 1;
+ fgetc(stdin);
+ ud.play = 0;
+ fgetc(stdin);
+ ud.play = 1;
+ fgetc(stdin);
+ ud.play = 0;
+ fgetc(stdin);
+#endif
+ ud.play = 1;
+
+ sem_wait(&ud.sem);
+
+ if (backend == AUDIOFLINGER) {
+ ud.at->stop();
+ } else {
+ pa_stream_set_write_callback(ud.s, NULL, NULL);
+ pa_stream_disconnect(ud.s);
+ pa_stream_unref(ud.s);
+
+ pa_context_set_state_callback(ud.c, NULL, NULL);
+ pa_context_disconnect(ud.c);
+ pa_context_unref(ud.c);
+
+ pa_threaded_mainloop_stop(ud.ml);
+ pa_threaded_mainloop_free(ud.ml);
+ }
+
+ close(ud.fd);
+ sem_destroy(&ud.sem);
+
+ return 0;
+}
diff --git a/tests/run_all.sh b/tests/run_all.sh
new file mode 100755
index 0000000..7424917
--- /dev/null
+++ b/tests/run_all.sh
@@ -0,0 +1,47 @@
+# Wait for caller to disconnect adb
+sleep 20
+
+# Fake run to get some stats
+sh ./run_test.sh
+
+mkdir af
+cd af
+
+sleep 240
+
+mkdir 48
+cd 48
+sh ../../run_test.sh -b af -r 48000 ../../../g6-48.raw
+cd ..
+
+sleep 240
+
+mkdir 44
+cd 44
+sh ../../run_test.sh -b af -r 44100 ../../../g6-44.raw
+cd ..
+
+cd ..
+
+# wait for AF to release the device
+sleep 240
+
+start-pulseaudio-android -D
+pactl set-sink-port 0 Handsfree
+
+mkdir pa
+cd pa
+
+sleep 240
+
+mkdir 48
+cd 48
+sh ../../run_test.sh -b pa -r 48000 ../../../g6-48.raw
+cd ..
+
+sleep 240
+
+mkdir 44
+cd 44
+sh ../../run_test.sh -b pa -r 44100 ../../../g6-44.raw
+cd ..
diff --git a/tests/run_test.sh b/tests/run_test.sh
new file mode 100755
index 0000000..ca6ef5d
--- /dev/null
+++ b/tests/run_test.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Runs audio_test with the provided arguments and dumps a number of benchmarks
+# to the current working directory.
+
+# Switch to lowest available power mode
+echo "powersave" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+echo "powersave" > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
+
+# Start playback
+audio_test ${@} &
+
+# Wait for things to settle down a bit
+sleep 5
+
+# amixer settings, for sanity
+amixer scontents > amixer.scontents
+amixer contents > mixer.scontents
+
+# Get some vmstat numbers
+vmstat -n 6 > vmstat
+
+# Collect per-thread top numbers as well
+top -m 100 -n 1 -s cpu -t > top.0
+top -m 100 -n 1 -s cpu -t > top.1
+top -m 100 -n 1 -s cpu -t > top.2
+top -m 100 -n 1 -s cpu -t > top.3
+top -m 100 -n 1 -s cpu -t > top.4
+top -m 100 -n 1 -s cpu -t > top.5
+
+# And some wakeup statistics
+
+powertop -d > powertop.0
+powertop -d > powertop.1
+powertop -d > powertop.2
+powertop -d > powertop.3
+powertop -d > powertop.4
+powertop -d > powertop.5
+
+# Switch back to the normal governer
+echo "interactive" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+echo "interactive" > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor