aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Fietz <Martin.Fietz@gmail.com>2015-11-13 13:27:56 +0100
committerMartin Fietz <Martin.Fietz@gmail.com>2015-11-13 13:27:56 +0100
commit11b12f4c1cdae1a7a018c37aa50d05434835c06d (patch)
treecc81ab89c1f8e5b9cedf563f68e1b923155229b3
parent6d1bcd771809cc40927237861f0840f26060556a (diff)
downloadAudioPlayer-11b12f4c1cdae1a7a018c37aa50d05434835c06d.tar.gz
Sonic: Allow downmixing
-rw-r--r--library/build.gradle10
-rw-r--r--library/src/main/java/org/antennapod/audio/AbstractAudioPlayer.java4
-rw-r--r--library/src/main/java/org/antennapod/audio/AndroidAudioPlayer.java10
-rw-r--r--library/src/main/java/org/antennapod/audio/MediaPlayer.java23
-rw-r--r--library/src/main/java/org/antennapod/audio/ServiceBackedAudioPlayer.java10
-rw-r--r--library/src/main/java/org/antennapod/audio/SonicAudioPlayer.java109
6 files changed, 136 insertions, 30 deletions
diff --git a/library/build.gradle b/library/build.gradle
index 69d397c..09dfc36 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -1,20 +1,18 @@
-apply plugin: 'com.android.library'
+apply plugin: "com.android.library"
android {
compileSdkVersion 23
- buildToolsVersion '23.0.1'
+ buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionCode 1
- versionName "1.0.5"
+ versionName "1.0.6"
}
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
- productFlavors {
- }
}
diff --git a/library/src/main/java/org/antennapod/audio/AbstractAudioPlayer.java b/library/src/main/java/org/antennapod/audio/AbstractAudioPlayer.java
index 0630302..05198a7 100644
--- a/library/src/main/java/org/antennapod/audio/AbstractAudioPlayer.java
+++ b/library/src/main/java/org/antennapod/audio/AbstractAudioPlayer.java
@@ -41,6 +41,8 @@ public abstract class AbstractAudioPlayer {
public abstract boolean canSetSpeed();
+ public abstract boolean canDownmix();
+
public abstract float getCurrentPitchStepsAdjustment();
public abstract int getCurrentPosition();
@@ -85,6 +87,8 @@ public abstract class AbstractAudioPlayer {
public abstract void setPlaybackSpeed(float f);
+ public abstract void setDownmix(boolean enable);
+
public abstract void setVolume(float leftVolume, float rightVolume);
public abstract void setWakeMode(Context context, int mode);
diff --git a/library/src/main/java/org/antennapod/audio/AndroidAudioPlayer.java b/library/src/main/java/org/antennapod/audio/AndroidAudioPlayer.java
index 7b8be82..e994bde 100644
--- a/library/src/main/java/org/antennapod/audio/AndroidAudioPlayer.java
+++ b/library/src/main/java/org/antennapod/audio/AndroidAudioPlayer.java
@@ -237,6 +237,11 @@ public class AndroidAudioPlayer extends AbstractAudioPlayer {
}
@Override
+ public boolean canDownmix() {
+ return false;
+ }
+
+ @Override
public int getCurrentPosition() {
owningMediaPlayer.lock.lock();
try {
@@ -447,6 +452,11 @@ public class AndroidAudioPlayer extends AbstractAudioPlayer {
}
@Override
+ public void setDownmix(boolean enable) {
+ return;
+ }
+
+ @Override
public void setVolume(float leftVolume, float rightVolume) {
owningMediaPlayer.lock.lock();
try {
diff --git a/library/src/main/java/org/antennapod/audio/MediaPlayer.java b/library/src/main/java/org/antennapod/audio/MediaPlayer.java
index 3bdfd12..c9e2299 100644
--- a/library/src/main/java/org/antennapod/audio/MediaPlayer.java
+++ b/library/src/main/java/org/antennapod/audio/MediaPlayer.java
@@ -302,6 +302,7 @@ public class MediaPlayer {
this.mpi = this.amp = new AndroidAudioPlayer(this, context);
if(Build.VERSION.SDK_INT >= 16) {
this.smp = new SonicAudioPlayer(this, context);
+ this.smp.setDownMix(downmix());
}
// setupMpi will go get the Service, if it can, then bring that
@@ -314,6 +315,10 @@ public class MediaPlayer {
return false;
}
+ protected boolean downmix() {
+ return false;
+ }
+
private boolean invalidServiceConnectionConfiguration() {
if(smp != null) {
boolean usingSonic = this.mpi instanceof SonicAudioPlayer;
@@ -626,6 +631,15 @@ public class MediaPlayer {
}
}
+ public boolean canDownmix() {
+ lock.lock();
+ try {
+ return this.mpi.canDownmix();
+ } finally {
+ lock.unlock();
+ }
+ }
+
protected void finalize() throws Throwable {
lock.lock();
try {
@@ -1071,6 +1085,15 @@ public class MediaPlayer {
}
}
+ public void setDownmix(boolean enable) {
+ lock.lock();
+ try {
+ this.mpi.setDownmix(enable);
+ } finally {
+ lock.unlock();
+ }
+ }
+
/**
* Functions identically to android.media.MediaPlayer.setVolume(float
* leftVolume, float rightVolume) Sets the stereo volume
diff --git a/library/src/main/java/org/antennapod/audio/ServiceBackedAudioPlayer.java b/library/src/main/java/org/antennapod/audio/ServiceBackedAudioPlayer.java
index 1391152..0f4ade5 100644
--- a/library/src/main/java/org/antennapod/audio/ServiceBackedAudioPlayer.java
+++ b/library/src/main/java/org/antennapod/audio/ServiceBackedAudioPlayer.java
@@ -216,6 +216,16 @@ public class ServiceBackedAudioPlayer extends AbstractAudioPlayer {
return false;
}
+ @Override
+ public boolean canDownmix() {
+ return false;
+ }
+
+ @Override
+ public void setDownmix(boolean enable) {
+ return;
+ }
+
void error(int what, int extra) {
owningMediaPlayer.lock.lock();
Log.e(SBMP_TAG, "error(" + what + ", " + extra + ")");
diff --git a/library/src/main/java/org/antennapod/audio/SonicAudioPlayer.java b/library/src/main/java/org/antennapod/audio/SonicAudioPlayer.java
index d3fa0c4..bbb2e2e 100644
--- a/library/src/main/java/org/antennapod/audio/SonicAudioPlayer.java
+++ b/library/src/main/java/org/antennapod/audio/SonicAudioPlayer.java
@@ -61,8 +61,8 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
private int mCurrentState;
private final Context mContext;
private PowerManager.WakeLock mWakeLock = null;
+ private boolean mDownMix;
- private final static int TRACK_NUM = 0;
private final static String TAG_TRACK = "SonicTrack";
private final static int STATE_IDLE = 0;
@@ -89,6 +89,7 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
mUri = null;
mLock = new ReentrantLock();
mDecoderLock = new Object();
+ mDownMix = false;
}
@Override
@@ -131,6 +132,16 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
return mCurrentSpeed;
}
+ @Override
+ public boolean canDownmix() {
+ return true;
+ }
+
+ @Override
+ public void setDownmix(boolean enable) {
+ mDownMix = enable;
+ }
+
public int getDuration() {
switch (mCurrentState) {
case STATE_INITIALIZED:
@@ -334,35 +345,49 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
}
public void seekTo(final int msec) {
+ boolean playing = false;
switch (mCurrentState) {
- case STATE_PREPARED:
case STATE_STARTED:
+ playing = true;
+ pause();
+ case STATE_PREPARED:
case STATE_PAUSED:
case STATE_PLAYBACK_COMPLETED:
- Thread t = new Thread(new Runnable() {
- @Override
- public void run() {
- mLock.lock();
- if (mTrack == null) {
- return;
- }
- mTrack.flush();
- mExtractor.seekTo(((long) msec * 1000), MediaExtractor.SEEK_TO_CLOSEST_SYNC);
- Log.d(TAG, "seek completed");
- if(owningMediaPlayer.onSeekCompleteListener != null) {
- owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer);
- }
- mLock.unlock();
- }
- });
- t.setDaemon(true);
- t.start();
+ mLock.lock();
+ if (mTrack == null) {
+ return;
+ }
+ mTrack.flush();
+ mExtractor.seekTo(((long) msec * 1000), MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+ if(hasVideoTrack()) {
+ Log.d(TAG, "sample time: " + mExtractor.getSampleTime());
+ mExtractor.advance();
+ Log.d(TAG, "sample time: " + mExtractor.getSampleTime());
+ }
+ Log.d(TAG, "seek completed, position: " + (mExtractor.getSampleTime() / 1000L));
+ if (owningMediaPlayer.onSeekCompleteListener != null) {
+ owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer);
+ }
+ mLock.unlock();
+ if (playing) {
+ start();
+ }
break;
default:
error();
}
}
+ private boolean hasVideoTrack() {
+ for(int i=0, count = mExtractor.getTrackCount(); i < count; i++) {
+ MediaFormat format = mExtractor.getTrackFormat(i);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ Log.d(TAG, "mime: " + mime);
+ }
+ return false;
+ }
+
+
@Override
public void setAudioStreamType(int streamtype) {
return;
@@ -419,6 +444,10 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
}
}
+ public void setDownMix(boolean downmix) {
+ mDownMix = downmix;
+ }
+
@SuppressWarnings("deprecation")
@Override
public void setVolume(float leftVolume, float rightVolume) {
@@ -486,7 +515,22 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
throw new IOException();
}
- final MediaFormat oFormat = mExtractor.getTrackFormat(TRACK_NUM);
+ int trackNum = -1;
+ for(int i=0; i < mExtractor.getTrackCount(); i++) {
+ final MediaFormat oFormat = mExtractor.getTrackFormat(i);
+ String mime = oFormat.getString(MediaFormat.KEY_MIME);
+ if(trackNum < 0 && mime.startsWith("audio/")) {
+ trackNum = i;
+ } else {
+ mExtractor.unselectTrack(i);
+ }
+ }
+
+ if(trackNum < 0) {
+ throw new IOException("No audio track found");
+ }
+
+ final MediaFormat oFormat = mExtractor.getTrackFormat(trackNum);
int sampleRate = oFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
int channelCount = oFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
final String mime = oFormat.getString(MediaFormat.KEY_MIME);
@@ -496,7 +540,7 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
Log.v(TAG_TRACK, "Mime type: " + mime);
initDevice(sampleRate, channelCount);
- mExtractor.selectTrack(TRACK_NUM);
+ mExtractor.selectTrack(trackNum);
mCodec = MediaCodec.createDecoderByType(mime);
mCodec.configure(oFormat, null, null, 0);
mLock.unlock();
@@ -592,8 +636,25 @@ public class SonicAudioPlayer extends AbstractAudioPlayer {
if (modifiedSamples.length < available) {
modifiedSamples = new byte[available];
}
- mSonic.readBytesFromStream(modifiedSamples, available);
- mTrack.write(modifiedSamples, 0, available);
+ if (mDownMix && mSonic.getNumChannels() == 2) {
+ int maxBytes = (available / 4) * 4;
+ mSonic.readBytesFromStream(modifiedSamples, maxBytes);
+
+ for (int i = 0; (i + 3) < modifiedSamples.length; i += 4) {
+ short left = (short) ((modifiedSamples[i] & 0xff) | (modifiedSamples[i + 1] << 8));
+ short right = (short) ((modifiedSamples[i + 2] & 0xff) | (modifiedSamples[i + 3] << 8));
+ short value = (short) (0.5 * left + 0.5 * right);
+
+ modifiedSamples[i] = (byte) (value & 0xff);
+ modifiedSamples[i + 1] = (byte) (value >> 8);
+ modifiedSamples[i + 2] = (byte) (value & 0xff);
+ modifiedSamples[i + 3] = (byte) (value >> 8);
+ }
+ mTrack.write(modifiedSamples, 0, maxBytes);
+ } else {
+ mSonic.readBytesFromStream(modifiedSamples, available);
+ mTrack.write(modifiedSamples, 0, available);
+ }
}
mCodec.releaseOutputBuffer(outputBufIndex, false);