Add VanillaMediaPlayer class

This commit adds a new VanillaMediaPlayer class, extending the media player
The class helps to simplify some tasks and also provides a nice getDataSource method
This commit is contained in:
Adrian Ulrich 2015-04-28 19:16:54 +02:00
parent 3974138451
commit 411db0bc91
3 changed files with 149 additions and 53 deletions

View File

@ -26,13 +26,18 @@ public class BastpUtil {
private RGLruCache rgCache;
public BastpUtil() {
rgCache = new RGLruCache(16); /* Cache up to 16 entries */
rgCache = new RGLruCache(64); /* Cache up to 64 entries */
}
/** Returns the ReplayGain values of 'path' as <track,album>
*/
public float[] getReplayGainValues(String path) {
if(path == null) {
// path must not be null
path = "//null\\";
}
float[] cached = rgCache.get(path);
if(cached == null) {

View File

@ -43,7 +43,6 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.audiofx.AudioEffect;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
@ -301,8 +300,8 @@ public final class PlaybackService extends Service
private Looper mLooper;
private Handler mHandler;
MediaPlayer mMediaPlayer;
MediaPlayer mPreparedMediaPlayer;
VanillaMediaPlayer mMediaPlayer;
VanillaMediaPlayer mPreparedMediaPlayer;
private boolean mMediaPlayerInitialized;
private PowerManager.WakeLock mWakeLock;
private NotificationManager mNotificationManager;
@ -404,6 +403,7 @@ public final class PlaybackService extends Service
mPlayCounts = new PlayCountsHelper(this);
mMediaPlayer = getNewMediaPlayer();
mPreparedMediaPlayer = getNewMediaPlayer();
mBastpUtil = new BastpUtil();
mReadahead = new ReadaheadThread();
mReadahead.start();
@ -554,14 +554,15 @@ public final class PlaybackService extends Service
if (mMediaPlayer != null) {
saveState(mMediaPlayer.getCurrentPosition());
Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mMediaPlayer.getAudioSessionId());
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
sendBroadcast(i);
mMediaPlayer.release();
mMediaPlayer = null;
}
if (mPreparedMediaPlayer != null) {
mPreparedMediaPlayer.release();
mPreparedMediaPlayer = null;
}
MediaButtonReceiver.unregisterMediaButton(this);
try {
@ -582,24 +583,18 @@ public final class PlaybackService extends Service
/**
* Returns a new MediaPlayer object
*/
private MediaPlayer getNewMediaPlayer() {
MediaPlayer mp = new MediaPlayer();
private VanillaMediaPlayer getNewMediaPlayer() {
VanillaMediaPlayer mp = new VanillaMediaPlayer(this);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setOnCompletionListener(this);
mp.setOnErrorListener(this);
return mp;
}
public void prepareMediaPlayer(MediaPlayer mp, String path) throws IOException{
public void prepareMediaPlayer(VanillaMediaPlayer mp, String path) throws IOException{
mp.setDataSource(path);
mp.prepare();
Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mp.getAudioSessionId());
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
sendBroadcast(i);
applyReplayGain(mp, path);
applyReplayGain(mp);
}
@ -608,23 +603,17 @@ public final class PlaybackService extends Service
* the (maybe just changed) user settings
*/
private void refreshReplayGainValues() {
Song curSong = getSong(0);
if(mMediaPlayer == null)
return;
if(curSong == null)
return;
applyReplayGain(mMediaPlayer, curSong.path);
if(mPreparedMediaPlayer != null) {
applyReplayGain(mPreparedMediaPlayer, getSong(1).path);
}
applyReplayGain(mMediaPlayer);
applyReplayGain(mPreparedMediaPlayer);
}
private void applyReplayGain(MediaPlayer mp, String path) {
/***
* Reads the replay gain value of the media players data source
* and adjusts the volume
*/
private void applyReplayGain(VanillaMediaPlayer mp) {
float[] rg = getReplayGainValues(path); /* track, album */
float[] rg = getReplayGainValues(mp.getDataSource()); /* track, album */
float adjust = 0f;
if(mReplayGainAlbumEnabled) {
@ -674,22 +663,16 @@ public final class PlaybackService extends Service
* re-creates a newone if needed.
*/
private void triggerGaplessUpdate() {
if(mMediaPlayerInitialized != true)
return;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
return; /* setNextMediaPlayer is supported since JB */
if(mPreparedMediaPlayer != null) {
/* an old prepared player exists and is
* most likely invalid -> destroy it now
*/
mMediaPlayer.setNextMediaPlayer(null);
mPreparedMediaPlayer.release();
mPreparedMediaPlayer = null;
}
// Reset any preparations
mMediaPlayer.setNextMediaPlayer(null);
mPreparedMediaPlayer.reset();
int fa = finishAction(mState);
Song nextSong = getSong(1);
if( nextSong != null
@ -697,7 +680,6 @@ public final class PlaybackService extends Service
&& fa != SongTimeline.FINISH_STOP_CURRENT
&& !mTimeline.isEndOfQueue() ) {
try {
mPreparedMediaPlayer = getNewMediaPlayer();
prepareMediaPlayer(mPreparedMediaPlayer, nextSong.path);
mMediaPlayer.setNextMediaPlayer(mPreparedMediaPlayer);
Log.d("VanillaMusic", "New media player prepared with path "+nextSong.path);
@ -1197,12 +1179,12 @@ public final class PlaybackService extends Service
mMediaPlayerInitialized = false;
mMediaPlayer.reset();
if(mPreparedMediaPlayer != null &&
mPreparedMediaPlayer.isPlaying()) {
mMediaPlayer.release();
if(mPreparedMediaPlayer.isPlaying()) {
VanillaMediaPlayer tmpPlayer = mMediaPlayer;
mMediaPlayer = mPreparedMediaPlayer;
mPreparedMediaPlayer = null;
mPreparedMediaPlayer = tmpPlayer;
mPreparedMediaPlayer.reset();
Log.v("VanillaMusic", "Swapped media players");
}
else if(song.path != null) {
prepareMediaPlayer(mMediaPlayer, song.path);
@ -1210,10 +1192,9 @@ public final class PlaybackService extends Service
mMediaPlayerInitialized = true;
// Cancel any queued gapless triggers: we are updating it right now
// Cancel any pending gapless updates and re-send them
mHandler.removeMessages(GAPLESS_UPDATE);
triggerGaplessUpdate();
mHandler.sendEmptyMessage(GAPLESS_UPDATE);
if (mPendingSeek != 0 && mPendingSeekSong == song.id) {
mMediaPlayer.seekTo(mPendingSeek);
@ -1677,7 +1658,7 @@ public final class PlaybackService extends Service
// This might get canceled if setCurrentSong() also fired a call
// to processSong();
mHandler.removeMessages(GAPLESS_UPDATE);
mHandler.sendEmptyMessageDelayed(GAPLESS_UPDATE, 350);
mHandler.sendEmptyMessageDelayed(GAPLESS_UPDATE, 500);
ArrayList<PlaybackActivity> list = sActivities;
for (int i = list.size(); --i != -1; )

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2015 Adrian Ulrich <adrian@blinkenlights.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.blinkenlights.android.vanilla;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import java.io.IOException;
import android.util.Log;
public class VanillaMediaPlayer extends MediaPlayer {
private Context mContext;
private String mDataSource;
private int mClaimedAudioSessionId = 0;
/**
* Constructs a new VanillaMediaPlayer class
*/
public VanillaMediaPlayer(Context context) {
super();
mContext = context;
_claimAudioSession();
}
/**
* Resets the media player to an unconfigured state
*/
public void reset() {
mDataSource = null;
super.reset();
}
/**
* Releases the media player and frees any claimed AudioEffect
*/
public void release() {
_releaseAudioSession();
mDataSource = null;
super.release();
}
/**
* Sets the data source to use
*/
public void setDataSource(String dataSource) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
mDataSource = dataSource;
super.setDataSource(mDataSource);
_claimAudioSession();
}
/**
* Returns the configured data source, may be null
*/
public String getDataSource() {
return mDataSource;
}
/**
* Creates a new AudioEffect for our AudioSession
*/
private void _claimAudioSession() {
// No active audio session -> claim one
Log.v("VanillaMusic", "_claimAudioSession() -> "+mClaimedAudioSessionId+" -> "+this);
if (mClaimedAudioSessionId == 0) {
mClaimedAudioSessionId = this.getAudioSessionId();
Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mClaimedAudioSessionId);
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.sendBroadcast(i);
}
}
/**
* Releases a previously claimed audio session id
*/
private void _releaseAudioSession() {
Log.v("VanillaMusic", "_releaseAudioSession() "+mClaimedAudioSessionId+" -> "+this);
if (mClaimedAudioSessionId != 0) {
Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mClaimedAudioSessionId);
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.sendBroadcast(i);
mClaimedAudioSessionId = 0;
}
}
}