APK for opensl loopback.
BUG=N/A
R=andrew@webrtc.org, fischman@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2212004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4901 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/audio_device/android/audio_manager_jni.h b/modules/audio_device/android/audio_manager_jni.h
index 6f85e72..298890e 100644
--- a/modules/audio_device/android/audio_manager_jni.h
+++ b/modules/audio_device/android/audio_manager_jni.h
@@ -43,9 +43,9 @@
// SetAndroidAudioDeviceObjects.
static void ClearAndroidAudioDeviceObjects();
- bool low_latency_supported() { return low_latency_supported_; }
- int native_output_sample_rate() { return native_output_sample_rate_; }
- int native_buffer_size() { return native_buffer_size_; }
+ bool low_latency_supported() const { return low_latency_supported_; }
+ int native_output_sample_rate() const { return native_output_sample_rate_; }
+ int native_buffer_size() const { return native_buffer_size_; }
private:
bool HasDeviceObjects();
diff --git a/modules/audio_device/android/opensles_common.h b/modules/audio_device/android/opensles_common.h
index e152171..15fa9ef 100644
--- a/modules/audio_device/android/opensles_common.h
+++ b/modules/audio_device/android/opensles_common.h
@@ -17,7 +17,8 @@
enum {
kDefaultSampleRate = 44100,
- kNumChannels = 1
+ kNumChannels = 1,
+ kDefaultBufSizeInSamples = kDefaultSampleRate * 10 / 1000,
};
diff --git a/modules/audio_device/android/test/AndroidManifest.xml b/modules/audio_device/android/test/AndroidManifest.xml
new file mode 100644
index 0000000..3d32a7a
--- /dev/null
+++ b/modules/audio_device/android/test/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1" package="org.webrtc.app" android:versionName="1.07">
+ <application android:icon="@drawable/logo"
+ android:label="@string/app_name"
+ android:debuggable="true">
+ <activity android:name=".OpenSlDemo"
+ android:label="@string/app_name"
+ android:screenOrientation="landscape"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.HEADSET_PLUG"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <uses-sdk android:minSdkVersion="14" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+</manifest>
diff --git a/modules/audio_device/android/test/README b/modules/audio_device/android/test/README
new file mode 100644
index 0000000..59f6de9
--- /dev/null
+++ b/modules/audio_device/android/test/README
@@ -0,0 +1,23 @@
+This directory contains an app for measuring the total delay from the native
+OpenSL implementation. Note that it just loops audio back from mic to speakers.
+
+Prerequisites:
+- Make sure gclient is checking out tools necessary to target Android: your
+ .gclient file should contain a line like:
+ target_os = ['android']
+ Make sure to re-run gclient sync after adding this to download the tools.
+- Env vars need to be set up to target Android; easiest way to do this is to run
+ (from the libjingle trunk directory):
+ . ./build/android/envsetup.sh
+ Note that this clobbers any previously-set $GYP_DEFINES so it must be done
+ before the next item.
+- Set up webrtc-related GYP variables:
+ export GYP_DEFINES="$GYP_DEFINES java_home=</path/to/JDK>
+ enable_android_opensl=1"
+- Finally, run "gclient runhooks" to generate Android-targeting .ninja files.
+
+Example of building & using the app:
+
+cd <path/to/repository>/trunk
+ninja -C out/Debug OpenSlDemo
+adb install -r out/Debug/OpenSlDemo-debug.apk
\ No newline at end of file
diff --git a/modules/audio_device/android/test/build.xml b/modules/audio_device/android/test/build.xml
new file mode 100644
index 0000000..b6e033a
--- /dev/null
+++ b/modules/audio_device/android/test/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="OpenSlDemo" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_SDK_ROOT env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_SDK_ROOT}">
+ <isset property="env.ANDROID_SDK_ROOT" />
+ </condition>
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_SDK_ROOT environment variable."
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/modules/audio_device/android/test/fake_audio_device_buffer.cc b/modules/audio_device/android/test/fake_audio_device_buffer.cc
new file mode 100644
index 0000000..c636ee6
--- /dev/null
+++ b/modules/audio_device/android/test/fake_audio_device_buffer.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_device/android/test/fake_audio_device_buffer.h"
+
+#include <assert.h>
+
+#include "webrtc/modules/audio_device/android/opensles_common.h"
+
+using webrtc_opensl::kDefaultBufSizeInSamples;
+
+namespace webrtc {
+
+FakeAudioDeviceBuffer::FakeAudioDeviceBuffer()
+ : fifo_(kNumBuffers),
+ next_available_buffer_(0),
+ record_channels_(0),
+ play_channels_(0) {
+ buf_.reset(new scoped_array<int8_t>[kNumBuffers]);
+ for (int i = 0; i < kNumBuffers; ++i) {
+ buf_[i].reset(new int8_t[buffer_size_bytes()]);
+ }
+}
+
+int32_t FakeAudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
+ assert(static_cast<int>(fsHz) == sample_rate());
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) {
+ assert(static_cast<int>(fsHz) == sample_rate());
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::SetRecordingChannels(uint8_t channels) {
+ assert(channels > 0);
+ record_channels_ = channels;
+ assert((play_channels_ == 0) ||
+ (record_channels_ == play_channels_));
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::SetPlayoutChannels(uint8_t channels) {
+ assert(channels > 0);
+ play_channels_ = channels;
+ assert((record_channels_ == 0) ||
+ (record_channels_ == play_channels_));
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
+ uint32_t nSamples) {
+ assert(audioBuffer);
+ assert(fifo_.size() < fifo_.capacity());
+ assert(nSamples == kDefaultBufSizeInSamples);
+ int8_t* buffer = buf_[next_available_buffer_].get();
+ next_available_buffer_ = (next_available_buffer_ + 1) % kNumBuffers;
+ memcpy(buffer, audioBuffer, nSamples * sizeof(int16_t));
+ fifo_.Push(buffer);
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::RequestPlayoutData(uint32_t nSamples) {
+ assert(nSamples == kDefaultBufSizeInSamples);
+ return 0;
+}
+
+int32_t FakeAudioDeviceBuffer::GetPlayoutData(void* audioBuffer) {
+ assert(audioBuffer);
+ if (fifo_.size() < 1) {
+ // Playout silence until there is data available.
+ memset(audioBuffer, 0, buffer_size_bytes());
+ return buffer_size_samples();
+ }
+ int8_t* buffer = fifo_.Pop();
+ memcpy(audioBuffer, buffer, buffer_size_bytes());
+ return buffer_size_samples();
+}
+
+int FakeAudioDeviceBuffer::sample_rate() const {
+ return audio_manager_.low_latency_supported() ?
+ audio_manager_.native_output_sample_rate() :
+ webrtc_opensl::kDefaultSampleRate;
+}
+
+int FakeAudioDeviceBuffer::buffer_size_samples() const {
+ return sample_rate() * 10 / 1000;
+}
+
+int FakeAudioDeviceBuffer::buffer_size_bytes() const {
+ return buffer_size_samples() * webrtc_opensl::kNumChannels * sizeof(int16_t);
+}
+
+
+void FakeAudioDeviceBuffer::ClearBuffer() {
+ while (fifo_.size() != 0) {
+ fifo_.Pop();
+ }
+ next_available_buffer_ = 0;
+}
+
+} // namespace webrtc
diff --git a/modules/audio_device/android/test/fake_audio_device_buffer.h b/modules/audio_device/android/test/fake_audio_device_buffer.h
new file mode 100644
index 0000000..9372e29
--- /dev/null
+++ b/modules/audio_device/android/test/fake_audio_device_buffer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_FAKE_AUDIO_DEVICE_BUFFER_H_
+#define WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_FAKE_AUDIO_DEVICE_BUFFER_H_
+
+#include "webrtc/modules/audio_device/android/audio_manager_jni.h"
+#include "webrtc/modules/audio_device/android/single_rw_fifo.h"
+#include "webrtc/modules/audio_device/audio_device_buffer.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+// Fake AudioDeviceBuffer implementation that returns audio data that is pushed
+// to it. It implements all APIs used by the OpenSL implementation.
+class FakeAudioDeviceBuffer : public AudioDeviceBuffer {
+ public:
+ FakeAudioDeviceBuffer();
+ virtual ~FakeAudioDeviceBuffer() {}
+
+ virtual int32_t SetRecordingSampleRate(uint32_t fsHz);
+ virtual int32_t SetPlayoutSampleRate(uint32_t fsHz);
+ virtual int32_t SetRecordingChannels(uint8_t channels);
+ virtual int32_t SetPlayoutChannels(uint8_t channels);
+ virtual int32_t SetRecordedBuffer(const void* audioBuffer,
+ uint32_t nSamples);
+ virtual void SetVQEData(int playDelayMS,
+ int recDelayMS,
+ int clockDrift) {}
+ virtual int32_t DeliverRecordedData() { return 0; }
+ virtual int32_t RequestPlayoutData(uint32_t nSamples);
+ virtual int32_t GetPlayoutData(void* audioBuffer);
+
+ void ClearBuffer();
+
+ private:
+ enum {
+ // Each buffer contains 10 ms of data since that is what OpenSlesInput
+ // delivers. Keep 7 buffers which would cover 70 ms of data. These buffers
+ // are needed because of jitter between OpenSl recording and playing.
+ kNumBuffers = 7,
+ };
+ int sample_rate() const;
+ int buffer_size_samples() const;
+ int buffer_size_bytes() const;
+
+ // Java API handle
+ AudioManagerJni audio_manager_;
+
+ SingleRwFifo fifo_;
+ scoped_array<scoped_array<int8_t> > buf_;
+ int next_available_buffer_;
+
+ uint8_t record_channels_;
+ uint8_t play_channels_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_FAKE_AUDIO_DEVICE_BUFFER_H_
diff --git a/modules/audio_device/android/test/jni/opensl_runner.cc b/modules/audio_device/android/test/jni/opensl_runner.cc
new file mode 100644
index 0000000..ba801a1
--- /dev/null
+++ b/modules/audio_device/android/test/jni/opensl_runner.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_device/android/test/jni/opensl_runner.h"
+
+#include <assert.h>
+
+#include "webrtc/modules/audio_device/android/audio_manager_jni.h"
+
+// Java globals
+static JavaVM* g_vm = NULL;
+static jclass g_osr = NULL;
+
+// Global class implementing native code.
+static webrtc::OpenSlRunner* g_runner = NULL;
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+ // Only called once.
+ assert(!g_vm);
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ jclass local_osr = env->FindClass("org/webrtc/app/OpenSlRunner");
+ assert(local_osr != NULL);
+ g_osr = static_cast<jclass>(env->NewGlobalRef(local_osr));
+ JNINativeMethod nativeFunctions[] = {
+ {"RegisterApplicationContext", "(Landroid/content/Context;)V",
+ reinterpret_cast<void*>(
+ &webrtc::OpenSlRunner::RegisterApplicationContext)},
+ {"Start", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Start)},
+ {"Stop", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Stop)}
+ };
+ int ret_val = env->RegisterNatives(g_osr, nativeFunctions, 3);
+ if (ret_val != 0) {
+ assert(false);
+ }
+ g_vm = vm;
+ return JNI_VERSION_1_6;
+}
+
+namespace webrtc {
+
+OpenSlRunner::OpenSlRunner()
+ : output_(0),
+ input_(0, &output_) {
+ output_.AttachAudioBuffer(&audio_buffer_);
+ if (output_.Init() != 0) {
+ assert(false);
+ }
+ if (output_.InitPlayout() != 0) {
+ assert(false);
+ }
+ input_.AttachAudioBuffer(&audio_buffer_);
+ if (input_.Init() != 0) {
+ assert(false);
+ }
+ if (input_.InitRecording() != 0) {
+ assert(false);
+ }
+}
+
+void OpenSlRunner::StartPlayRecord() {
+ output_.StartPlayout();
+ input_.StartRecording();
+}
+
+void OpenSlRunner::StopPlayRecord() {
+ // There are large enough buffers to compensate for recording and playing
+ // jitter such that the timing of stopping playing or recording should not
+ // result in over or underrun.
+ input_.StopRecording();
+ output_.StopPlayout();
+ audio_buffer_.ClearBuffer();
+}
+
+JNIEXPORT void JNICALL OpenSlRunner::RegisterApplicationContext(
+ JNIEnv * env,
+ jobject,
+ jobject context) {
+ assert(!g_runner); // Should only be called once.
+ AudioManagerJni::SetAndroidAudioDeviceObjects(g_vm, env, context);
+ // Might as well create the global instance since everything is set up at this
+ // point.
+ g_runner = new webrtc::OpenSlRunner();
+}
+
+JNIEXPORT void JNICALL OpenSlRunner::Start(JNIEnv * env, jobject) {
+ g_runner->StartPlayRecord();
+}
+
+JNIEXPORT void JNICALL OpenSlRunner::Stop(JNIEnv * env, jobject) {
+ g_runner->StopPlayRecord();
+}
+
+} // namespace webrtc
diff --git a/modules/audio_device/android/test/jni/opensl_runner.h b/modules/audio_device/android/test/jni/opensl_runner.h
new file mode 100644
index 0000000..5d4f867
--- /dev/null
+++ b/modules/audio_device/android/test/jni/opensl_runner.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <jni.h>
+
+#include "webrtc/modules/audio_device/android/test/fake_audio_device_buffer.h"
+#include "webrtc/modules/audio_device/android/opensles_input.h"
+#include "webrtc/modules/audio_device/android/opensles_output.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+#ifndef WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_JNI_OPENSL_RUNNER_H_
+#define WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_JNI_OPENSL_RUNNER_H_
+
+namespace webrtc {
+
+class FakeAudioDeviceBuffer;
+
+class OpenSlRunner {
+ public:
+ OpenSlRunner();
+ ~OpenSlRunner() {}
+
+ void StartPlayRecord();
+ void StopPlayRecord();
+
+ static JNIEXPORT void JNICALL RegisterApplicationContext(JNIEnv * env,
+ jobject,
+ jobject context);
+ static JNIEXPORT void JNICALL Start(JNIEnv * env, jobject);
+ static JNIEXPORT void JNICALL Stop(JNIEnv * env, jobject);
+
+ private:
+ OpenSlesOutput output_;
+ OpenSlesInput input_;
+ FakeAudioDeviceBuffer audio_buffer_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_JNI_OPENSL_RUNNER_H_
diff --git a/modules/audio_device/android/test/project.properties b/modules/audio_device/android/test/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/modules/audio_device/android/test/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
diff --git a/modules/audio_device/android/test/res/drawable/logo.png b/modules/audio_device/android/test/res/drawable/logo.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/modules/audio_device/android/test/res/drawable/logo.png
Binary files differ
diff --git a/modules/audio_device/android/test/res/layout/open_sl_demo.xml b/modules/audio_device/android/test/res/layout/open_sl_demo.xml
new file mode 100644
index 0000000..1efad73
--- /dev/null
+++ b/modules/audio_device/android/test/res/layout/open_sl_demo.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="bottom">
+ <TextView android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_gravity="top"
+ android:text="About: This application, when started, loops back audio as quickly as the native OpenSL implementation allows. Just starting it will lead to a feedback loop. It can be used to measure delay with the proper hardware. Using it as is has little utility." />
+ <Button android:id="@+id/btStartStopCall"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:text="@string/startCall"
+ android:layout_gravity="center"/>
+ <Button android:id="@+id/btExit"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/exit"/>
+</LinearLayout >
diff --git a/modules/audio_device/android/test/res/values/strings.xml b/modules/audio_device/android/test/res/values/strings.xml
new file mode 100644
index 0000000..f519806
--- /dev/null
+++ b/modules/audio_device/android/test/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">WebRTCOpenSLLoopback</string>
+ <string name="startCall">StartCall</string>
+ <string name="stopCall">StopCall</string>
+ <string name="exit">Exit</string>
+</resources>
diff --git a/modules/audio_device/android/test/src/org/webrtc/app/OpenSlDemo.java b/modules/audio_device/android/test/src/org/webrtc/app/OpenSlDemo.java
new file mode 100644
index 0000000..8060c99
--- /dev/null
+++ b/modules/audio_device/android/test/src/org/webrtc/app/OpenSlDemo.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+package org.webrtc.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+
+public class OpenSlDemo extends Activity implements View.OnClickListener {
+ private static final String TAG = "WEBRTC";
+
+ private Button btStartStopCall;
+ private boolean isRunning = false;
+
+ private WakeLock wakeLock;
+
+ private OpenSlRunner runner;
+
+ // Called when activity is created.
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ PowerManager pm = (PowerManager)this.getSystemService(
+ Context.POWER_SERVICE);
+ wakeLock = pm.newWakeLock(
+ PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
+ wakeLock.acquire(); // Keep screen on until app terminates.
+
+ setContentView(R.layout.open_sl_demo);
+
+ // Direct hardware volume controls to affect the voice call audio stream.
+ setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
+
+ btStartStopCall = (Button) findViewById(R.id.btStartStopCall);
+ btStartStopCall.setOnClickListener(this);
+ findViewById(R.id.btExit).setOnClickListener(this);
+
+ runner = new OpenSlRunner();
+ // Native code calls back into JVM to be able to configure OpenSL to low
+ // latency mode. Provide the context needed to do this.
+ runner.RegisterApplicationContext(getApplicationContext());
+ }
+
+ // Called before activity is destroyed.
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, "onDestroy");
+ wakeLock.release();
+ super.onDestroy();
+ }
+
+ private void startOrStop() {
+ if (isRunning) {
+ runner.Stop();
+ btStartStopCall.setText(R.string.startCall);
+ isRunning = false;
+ } else if (!isRunning){
+ runner.Start();
+ btStartStopCall.setText(R.string.stopCall);
+ isRunning = true;
+ }
+ }
+
+ public void onClick(View arg0) {
+ switch (arg0.getId()) {
+ case R.id.btStartStopCall:
+ startOrStop();
+ break;
+ case R.id.btExit:
+ finish();
+ break;
+ }
+ }
+
+}
diff --git a/modules/audio_device/android/test/src/org/webrtc/app/OpenSlRunner.java b/modules/audio_device/android/test/src/org/webrtc/app/OpenSlRunner.java
new file mode 100644
index 0000000..489cb55
--- /dev/null
+++ b/modules/audio_device/android/test/src/org/webrtc/app/OpenSlRunner.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+package org.webrtc.app;
+
+import android.content.Context;
+
+public class OpenSlRunner {
+ public OpenSlRunner() {
+ System.loadLibrary("opensl-demo-jni");
+ }
+
+ public static native void RegisterApplicationContext(Context context);
+ public static native void Start();
+ public static native void Stop();
+
+}
\ No newline at end of file
diff --git a/modules/audio_device/audio_device.gypi b/modules/audio_device/audio_device.gypi
index 3df12eb..a56c81d 100644
--- a/modules/audio_device/audio_device.gypi
+++ b/modules/audio_device/audio_device.gypi
@@ -256,6 +256,66 @@
['OS=="android" and enable_android_opensl==1', {
'targets': [
{
+ 'target_name': 'libopensl-demo-jni',
+ 'type': 'loadable_module',
+ 'dependencies': [
+ 'audio_device',
+ ],
+ 'sources': [
+ 'android/test/jni/opensl_runner.cc',
+ 'android/test/fake_audio_device_buffer.cc',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-llog',
+ '-lOpenSLES',
+ ],
+ },
+ },
+ {
+ 'target_name': 'OpenSlDemo',
+ 'type': 'none',
+ 'dependencies': [
+ 'libopensl-demo-jni',
+ '<(modules_java_gyp_path):*',
+ ],
+ 'actions': [
+ {
+ # TODO(henrik): Convert building of the demo to a proper GYP
+ # target so this action is not needed once chromium's
+ # apk-building machinery can be used. (crbug.com/225101)
+ 'action_name': 'build_opensldemo_apk',
+ 'variables': {
+ 'android_opensl_demo_root': '<(webrtc_root)/modules/audio_device/android/test',
+ },
+ 'inputs' : [
+ '<(PRODUCT_DIR)/lib.java/audio_device_module_java.jar',
+ '<(PRODUCT_DIR)/libopensl-demo-jni.so',
+ '<!@(find <(android_opensl_demo_root)/src -name "*.java")',
+ '<!@(find <(android_opensl_demo_root)/res -name "*.xml")',
+ '<!@(find <(android_opensl_demo_root)/res -name "*.png")',
+ '<(android_opensl_demo_root)/AndroidManifest.xml',
+ '<(android_opensl_demo_root)/build.xml',
+ '<(android_opensl_demo_root)/project.properties',
+ ],
+ 'outputs': ['<(PRODUCT_DIR)/OpenSlDemo-debug.apk'],
+ 'action': ['bash', '-ec',
+ 'rm -f <(_outputs) && '
+ 'mkdir -p <(android_opensl_demo_root)/libs/<(android_app_abi) && '
+ '<(android_strip) -o <(android_opensl_demo_root)/libs/<(android_app_abi)/libopensl-demo-jni.so <(PRODUCT_DIR)/libopensl-demo-jni.so && '
+ 'cp <(PRODUCT_DIR)/lib.java/audio_device_module_java.jar <(android_opensl_demo_root)/libs/ &&'
+ 'cd <(android_opensl_demo_root) && '
+ 'ant debug && '
+ 'cd - && '
+ 'cp <(android_opensl_demo_root)/bin/OpenSlDemo-debug.apk <(_outputs)'
+ ],
+ },
+ ],
+ }],
+ }],
+ ['OS=="android" and enable_android_opensl==1', {
+ 'targets': [
+ {
'target_name': 'audio_device_unittest',
'type': 'executable',
'dependencies': [
diff --git a/modules/audio_device/audio_device_buffer.h b/modules/audio_device/audio_device_buffer.h
index fd06e7c..84df559 100644
--- a/modules/audio_device/audio_device_buffer.h
+++ b/modules/audio_device/audio_device_buffer.h
@@ -36,13 +36,13 @@
int32_t InitPlayout();
int32_t InitRecording();
- int32_t SetRecordingSampleRate(uint32_t fsHz);
- int32_t SetPlayoutSampleRate(uint32_t fsHz);
+ virtual int32_t SetRecordingSampleRate(uint32_t fsHz);
+ virtual int32_t SetPlayoutSampleRate(uint32_t fsHz);
int32_t RecordingSampleRate() const;
int32_t PlayoutSampleRate() const;
- int32_t SetRecordingChannels(uint8_t channels);
- int32_t SetPlayoutChannels(uint8_t channels);
+ virtual int32_t SetRecordingChannels(uint8_t channels);
+ virtual int32_t SetPlayoutChannels(uint8_t channels);
uint8_t RecordingChannels() const;
uint8_t PlayoutChannels() const;
int32_t SetRecordingChannel(
@@ -50,12 +50,13 @@
int32_t RecordingChannel(
AudioDeviceModule::ChannelType& channel) const;
- int32_t SetRecordedBuffer(const void* audioBuffer, uint32_t nSamples);
+ virtual int32_t SetRecordedBuffer(const void* audioBuffer,
+ uint32_t nSamples);
int32_t SetCurrentMicLevel(uint32_t level);
- void SetVQEData(int playDelayMS,
- int recDelayMS,
- int clockDrift);
- int32_t DeliverRecordedData();
+ virtual void SetVQEData(int playDelayMS,
+ int recDelayMS,
+ int clockDrift);
+ virtual int32_t DeliverRecordedData();
uint32_t NewMicLevel() const;
virtual int32_t RequestPlayoutData(uint32_t nSamples);