diff options
author | Martin Fietz <Martin.Fietz@gmail.com> | 2015-11-13 13:27:56 +0100 |
---|---|---|
committer | Martin Fietz <Martin.Fietz@gmail.com> | 2015-11-13 13:27:56 +0100 |
commit | 11b12f4c1cdae1a7a018c37aa50d05434835c06d (patch) | |
tree | cc81ab89c1f8e5b9cedf563f68e1b923155229b3 | |
parent | 6d1bcd771809cc40927237861f0840f26060556a (diff) | |
download | AudioPlayer-11b12f4c1cdae1a7a018c37aa50d05434835c06d.tar.gz |
Sonic: Allow downmixing
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); |