package com.marverenic.music.player;
import android.content.Context;
import android.content.Intent;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.Equalizer;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
public class EqualizedExoPlayer implements ExoPlayer {
private static final int NO_AUDIO_SESSION_ID = 0;
private Context mContext;
private SimpleExoPlayer mExoPlayer;
private Equalizer mEqualizer;
private boolean mEqualizerEnabled;
private Equalizer.Settings mEqualizerSettings;
public EqualizedExoPlayer(Context context, SimpleExoPlayer delegate) {
mContext = context;
mExoPlayer = delegate;
mExoPlayer.setAudioDebugListener(new EqualizerEventListener());
}
public void setEqualizerSettings(boolean enabled, Equalizer.Settings settings) {
boolean invalidate = mEqualizerEnabled != enabled || mEqualizerEnabled;
boolean wasSystem = isUsingSystemEqualizer();
mEqualizerEnabled = enabled;
mEqualizerSettings = settings;
if (invalidate) {
updateEqualizerPrefs(enabled, wasSystem);
}
}
private void updateEqualizerPrefs(boolean useCustom, boolean wasSystem) {
int audioSessionId = mExoPlayer.getAudioSessionId();
if (audioSessionId == NO_AUDIO_SESSION_ID) {
// No equalizer is currently bound. Nothing to do.
return;
}
if (useCustom) {
if (wasSystem || mEqualizer == null) {
// System -> custom
unbindSystemEqualizer(audioSessionId);
bindCustomEqualizer(audioSessionId);
} else {
// Custom -> custom
mEqualizer.setProperties(mEqualizerSettings);
}
} else {
if (!wasSystem) {
// Custom -> system
unbindCustomEqualizer();
bindSystemEqualizer(audioSessionId);
}
// Nothing to do for system -> system
}
}
private boolean isUsingSystemEqualizer() {
return mEqualizerSettings == null || !mEqualizerEnabled;
}
private void onBindEqualizer(int newAudioSessionId) {
if (isUsingSystemEqualizer()) {
bindSystemEqualizer(newAudioSessionId);
} else {
bindCustomEqualizer(newAudioSessionId);
}
}
private void bindSystemEqualizer(int audioSessionId) {
Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId);
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.sendBroadcast(intent);
}
private void bindCustomEqualizer(int audioSessionId) {
mEqualizer = new Equalizer(0, audioSessionId);
mEqualizer.setProperties(mEqualizerSettings);
mEqualizer.setEnabled(true);
}
private void onUnbindEqualizer(int oldAudioSessionId) {
if (isUsingSystemEqualizer()) {
unbindSystemEqualizer(oldAudioSessionId);
} else {
unbindCustomEqualizer();
}
}
private void unbindSystemEqualizer(int audioSessionId) {
Intent intent = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId);
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.sendBroadcast(intent);
}
private void unbindCustomEqualizer() {
if (mEqualizer != null) {
mEqualizer.setEnabled(false);
mEqualizer.release();
mEqualizer = null;
}
}
private class EqualizerEventListener implements AudioRendererEventListener {
private int lastAudioSessionId = NO_AUDIO_SESSION_ID;
@Override
public void onAudioSessionId(int audioSessionId) {
if (audioSessionId != NO_AUDIO_SESSION_ID) {
onBindEqualizer(audioSessionId);
lastAudioSessionId = audioSessionId;
}
}
@Override
public void onAudioDisabled(DecoderCounters counters) {
if (lastAudioSessionId != NO_AUDIO_SESSION_ID) {
onUnbindEqualizer(lastAudioSessionId);
}
}
@Override
public void onAudioEnabled(DecoderCounters counters) {}
@Override
public void onAudioDecoderInitialized(
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
@Override
public void onAudioInputFormatChanged(Format format) {
}
@Override
public void onAudioTrackUnderrun(
int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
}
}
// region DELEGATED METHODS
public void setVolume(float volume) {
mExoPlayer.setVolume(volume);
}
@Override
public void addListener(EventListener listener) {
mExoPlayer.addListener(listener);
}
@Override
public void removeListener(EventListener listener) {
mExoPlayer.removeListener(listener);
}
@Override
public int getPlaybackState() {
return mExoPlayer.getPlaybackState();
}
@Override
public void prepare(MediaSource mediaSource) {
mExoPlayer.prepare(mediaSource);
}
@Override
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetTimeline) {
mExoPlayer.prepare(mediaSource, resetPosition, resetTimeline);
}
@Override
public void setPlayWhenReady(boolean playWhenReady) {
mExoPlayer.setPlayWhenReady(playWhenReady);
}
@Override
public boolean getPlayWhenReady() {
return mExoPlayer.getPlayWhenReady();
}
@Override
public boolean isLoading() {
return mExoPlayer.isLoading();
}
@Override
public void seekToDefaultPosition() {
mExoPlayer.seekToDefaultPosition();
}
@Override
public void seekToDefaultPosition(int windowIndex) {
mExoPlayer.seekToDefaultPosition(windowIndex);
}
@Override
public void seekTo(long windowPositionMs) {
mExoPlayer.seekTo(windowPositionMs);
}
@Override
public void seekTo(int windowIndex, long windowPositionMs) {
mExoPlayer.seekTo(windowIndex, windowPositionMs);
}
@Override
public void stop() {
mExoPlayer.stop();
}
@Override
public void release() {
mExoPlayer.release();
}
@Override
public void sendMessages(ExoPlayerMessage... messages) {
mExoPlayer.sendMessages(messages);
}
@Override
public void blockingSendMessages(ExoPlayerMessage... messages) {
mExoPlayer.blockingSendMessages(messages);
}
@Override
public int getRendererCount() {
return mExoPlayer.getRendererCount();
}
@Override
public int getRendererType(int index) {
return mExoPlayer.getRendererType(index);
}
@Override
public TrackGroupArray getCurrentTrackGroups() {
return mExoPlayer.getCurrentTrackGroups();
}
@Override
public TrackSelectionArray getCurrentTrackSelections() {
return mExoPlayer.getCurrentTrackSelections();
}
@Override
public Object getCurrentManifest() {
return mExoPlayer.getCurrentManifest();
}
@Override
public Timeline getCurrentTimeline() {
return mExoPlayer.getCurrentTimeline();
}
@Override
public int getCurrentPeriodIndex() {
return mExoPlayer.getCurrentPeriodIndex();
}
@Override
public int getCurrentWindowIndex() {
return mExoPlayer.getCurrentWindowIndex();
}
@Override
public long getDuration() {
return mExoPlayer.getDuration();
}
@Override
public long getCurrentPosition() {
return mExoPlayer.getCurrentPosition();
}
@Override
public long getBufferedPosition() {
return mExoPlayer.getBufferedPosition();
}
@Override
public int getBufferedPercentage() {
return mExoPlayer.getBufferedPercentage();
}
@Override
public boolean isCurrentWindowDynamic() {
return mExoPlayer.isCurrentWindowDynamic();
}
@Override
public boolean isCurrentWindowSeekable() {
return mExoPlayer.isCurrentWindowSeekable();
}
// endregion DELEGATED METHODS
}