diff --git a/extensions/flac/src/androidTest/AndroidManifest.xml b/extensions/flac/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000000..764b7e98d1
--- /dev/null
+++ b/extensions/flac/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/flac/src/androidTest/assets/bear-flac.mka b/extensions/flac/src/androidTest/assets/bear-flac.mka
new file mode 100644
index 0000000000..457353d722
Binary files /dev/null and b/extensions/flac/src/androidTest/assets/bear-flac.mka differ
diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer/ext/flac/FlacPlaybackTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer/ext/flac/FlacPlaybackTest.java
new file mode 100644
index 0000000000..bb5d97d118
--- /dev/null
+++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer/ext/flac/FlacPlaybackTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer.ext.flac;
+
+import com.google.android.exoplayer.DefaultTrackSelector;
+import com.google.android.exoplayer.ExoPlaybackException;
+import com.google.android.exoplayer.ExoPlayer;
+import com.google.android.exoplayer.TrackRenderer;
+import com.google.android.exoplayer.extractor.ExtractorSampleSource;
+import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
+import com.google.android.exoplayer.upstream.DefaultAllocator;
+import com.google.android.exoplayer.upstream.DefaultDataSource;
+import com.google.android.exoplayer.util.Util;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Looper;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Playback tests using {@link LibflacAudioTrackRenderer}.
+ */
+public class FlacPlaybackTest extends InstrumentationTestCase {
+
+ private static final String BEAR_FLAC_URI = "asset:///bear-flac.mka";
+
+ public void testBasicPlayback() throws ExoPlaybackException {
+ playUri(BEAR_FLAC_URI);
+ }
+
+ private void playUri(String uri) throws ExoPlaybackException {
+ TestPlaybackThread thread = new TestPlaybackThread(Uri.parse(uri),
+ getInstrumentation().getContext());
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ fail(); // Should never happen.
+ }
+ if (thread.playbackException != null) {
+ throw thread.playbackException;
+ }
+ }
+
+ private static class TestPlaybackThread extends Thread implements ExoPlayer.Listener {
+
+ private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
+ private static final int BUFFER_SEGMENT_COUNT = 16;
+
+ private final Context context;
+ private final Uri uri;
+
+ private ExoPlayer player;
+ private ExoPlaybackException playbackException;
+
+ public TestPlaybackThread(Uri uri, Context context) {
+ this.uri = uri;
+ this.context = context;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ LibflacAudioTrackRenderer audioRenderer = new LibflacAudioTrackRenderer();
+ DefaultTrackSelector trackSelector = new DefaultTrackSelector(null, null);
+ player = ExoPlayer.Factory.newInstance(new TrackRenderer[] {audioRenderer}, trackSelector);
+ player.addListener(this);
+ ExtractorSampleSource sampleSource = new ExtractorSampleSource(
+ uri,
+ new DefaultDataSource(context, null, Util.getUserAgent(context, "ExoPlayerExtFlacTest"),
+ false),
+ new DefaultAllocator(BUFFER_SEGMENT_SIZE), BUFFER_SEGMENT_SIZE * BUFFER_SEGMENT_COUNT,
+ new MatroskaExtractor());
+ player.prepare(sampleSource);
+ player.setPlayWhenReady(true);
+ Looper.loop();
+ }
+
+ @Override
+ public void onPlayWhenReadyCommitted () {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPlayerError(ExoPlaybackException error) {
+ playbackException = error;
+ }
+
+ @Override
+ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
+ if (playbackState == ExoPlayer.STATE_ENDED
+ || (playbackState == ExoPlayer.STATE_IDLE && playbackException != null)) {
+ releasePlayerAndQuitLooper();
+ }
+ }
+
+ private void releasePlayerAndQuitLooper() {
+ player.release();
+ Looper.myLooper().quit();
+ }
+
+ }
+
+}
diff --git a/extensions/flac/src/androidTest/project.properties b/extensions/flac/src/androidTest/project.properties
new file mode 100644
index 0000000000..916037e334
--- /dev/null
+++ b/extensions/flac/src/androidTest/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-23
diff --git a/extensions/flac/src/androidTest/res/.README.txt b/extensions/flac/src/androidTest/res/.README.txt
new file mode 100644
index 0000000000..c27147ce56
--- /dev/null
+++ b/extensions/flac/src/androidTest/res/.README.txt
@@ -0,0 +1,2 @@
+This file is needed to make sure the res directory is present.
+The file is ignored by the Android toolchain because its name starts with a dot.
diff --git a/extensions/opus/src/androidTest/AndroidManifest.xml b/extensions/opus/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000000..7b1516a08a
--- /dev/null
+++ b/extensions/opus/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/opus/src/androidTest/assets/bear-opus.webm b/extensions/opus/src/androidTest/assets/bear-opus.webm
new file mode 100644
index 0000000000..c198148814
Binary files /dev/null and b/extensions/opus/src/androidTest/assets/bear-opus.webm differ
diff --git a/extensions/opus/src/androidTest/java/com/google/android/exoplayer/ext/opus/OpusPlaybackTest.java b/extensions/opus/src/androidTest/java/com/google/android/exoplayer/ext/opus/OpusPlaybackTest.java
new file mode 100644
index 0000000000..36249244fc
--- /dev/null
+++ b/extensions/opus/src/androidTest/java/com/google/android/exoplayer/ext/opus/OpusPlaybackTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer.ext.opus;
+
+import com.google.android.exoplayer.DefaultTrackSelector;
+import com.google.android.exoplayer.ExoPlaybackException;
+import com.google.android.exoplayer.ExoPlayer;
+import com.google.android.exoplayer.TrackRenderer;
+import com.google.android.exoplayer.extractor.ExtractorSampleSource;
+import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
+import com.google.android.exoplayer.upstream.DefaultAllocator;
+import com.google.android.exoplayer.upstream.DefaultDataSource;
+import com.google.android.exoplayer.util.Util;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Looper;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Playback tests using {@link LibopusAudioTrackRenderer}.
+ */
+public class OpusPlaybackTest extends InstrumentationTestCase {
+
+ private static final String BEAR_OPUS_URI = "asset:///bear-opus.webm";
+
+ public void testBasicPlayback() throws ExoPlaybackException {
+ playUri(BEAR_OPUS_URI);
+ }
+
+ private void playUri(String uri) throws ExoPlaybackException {
+ TestPlaybackThread thread = new TestPlaybackThread(Uri.parse(uri),
+ getInstrumentation().getContext());
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ fail(); // Should never happen.
+ }
+ if (thread.playbackException != null) {
+ throw thread.playbackException;
+ }
+ }
+
+ private static class TestPlaybackThread extends Thread implements ExoPlayer.Listener {
+
+ private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
+ private static final int BUFFER_SEGMENT_COUNT = 16;
+
+ private final Context context;
+ private final Uri uri;
+
+ private ExoPlayer player;
+ private ExoPlaybackException playbackException;
+
+ public TestPlaybackThread(Uri uri, Context context) {
+ this.uri = uri;
+ this.context = context;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ LibopusAudioTrackRenderer audioRenderer = new LibopusAudioTrackRenderer();
+ DefaultTrackSelector trackSelector = new DefaultTrackSelector(null, null);
+ player = ExoPlayer.Factory.newInstance(new TrackRenderer[] {audioRenderer}, trackSelector);
+ player.addListener(this);
+ ExtractorSampleSource sampleSource = new ExtractorSampleSource(
+ uri,
+ new DefaultDataSource(context, null, Util.getUserAgent(context, "ExoPlayerExtOpusTest"),
+ false),
+ new DefaultAllocator(BUFFER_SEGMENT_SIZE), BUFFER_SEGMENT_SIZE * BUFFER_SEGMENT_COUNT,
+ new MatroskaExtractor());
+ player.prepare(sampleSource);
+ player.setPlayWhenReady(true);
+ Looper.loop();
+ }
+
+ @Override
+ public void onPlayWhenReadyCommitted () {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPlayerError(ExoPlaybackException error) {
+ playbackException = error;
+ }
+
+ @Override
+ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
+ if (playbackState == ExoPlayer.STATE_ENDED
+ || (playbackState == ExoPlayer.STATE_IDLE && playbackException != null)) {
+ releasePlayerAndQuitLooper();
+ }
+ }
+
+ private void releasePlayerAndQuitLooper() {
+ player.release();
+ Looper.myLooper().quit();
+ }
+
+ }
+
+}
diff --git a/extensions/opus/src/androidTest/project.properties b/extensions/opus/src/androidTest/project.properties
new file mode 100644
index 0000000000..916037e334
--- /dev/null
+++ b/extensions/opus/src/androidTest/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-23
diff --git a/extensions/opus/src/androidTest/res/.README.txt b/extensions/opus/src/androidTest/res/.README.txt
new file mode 100644
index 0000000000..c27147ce56
--- /dev/null
+++ b/extensions/opus/src/androidTest/res/.README.txt
@@ -0,0 +1,2 @@
+This file is needed to make sure the res directory is present.
+The file is ignored by the Android toolchain because its name starts with a dot.