mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-07 15:28:40 +01:00
Merge branch 'nitehu-fix/equalizer_visualizer_init' into develop
This commit is contained in:
commit
440b2109d3
@ -49,10 +49,14 @@ import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ViewFlipper;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.mobeta.android.dslv.DragSortListView;
|
||||
|
||||
import org.koin.java.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.audiofx.EqualizerController;
|
||||
import org.moire.ultrasonic.audiofx.VisualizerController;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
@ -117,8 +121,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
private int swipeDistance;
|
||||
private int swipeVelocity;
|
||||
private VisualizerView visualizerView;
|
||||
private boolean visualizerAvailable;
|
||||
private boolean equalizerAvailable;
|
||||
private boolean jukeboxAvailable;
|
||||
private SilentBackgroundTask<Void> onProgressChangedTask;
|
||||
LinearLayout visualizerViewLayout;
|
||||
@ -133,6 +135,9 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
private Drawable hollowStar;
|
||||
private Drawable fullStar;
|
||||
|
||||
private boolean isEqualizerAvailable;
|
||||
private boolean isVisualizerAvailable;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@ -506,8 +511,55 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
mediaPlayerController.setShufflePlayEnabled(true);
|
||||
}
|
||||
|
||||
visualizerAvailable = (mediaPlayerController != null) && (mediaPlayerController.getVisualizerController() != null);
|
||||
equalizerAvailable = (mediaPlayerController != null) && (mediaPlayerController.getEqualizerController() != null);
|
||||
visualizerViewLayout.setVisibility(View.GONE);
|
||||
VisualizerController.get().observe(this, new Observer<VisualizerController>() {
|
||||
@Override
|
||||
public void onChanged(VisualizerController visualizerController) {
|
||||
if (visualizerController != null) {
|
||||
Timber.d("VisualizerController Observer.onChanged received controller");
|
||||
visualizerView = new VisualizerView(DownloadActivity.this);
|
||||
visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
|
||||
if (!visualizerView.isActive())
|
||||
{
|
||||
visualizerViewLayout.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
visualizerViewLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
visualizerView.setOnTouchListener(new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch(final View view, final MotionEvent motionEvent)
|
||||
{
|
||||
visualizerView.setActive(!visualizerView.isActive());
|
||||
getMediaPlayerController().setShowVisualization(visualizerView.isActive());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
isVisualizerAvailable = true;
|
||||
} else {
|
||||
Timber.d("VisualizerController Observer.onChanged has no controller");
|
||||
visualizerViewLayout.setVisibility(View.GONE);
|
||||
isVisualizerAvailable = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EqualizerController.get().observe(this, new Observer<EqualizerController>() {
|
||||
@Override
|
||||
public void onChanged(EqualizerController equalizerController) {
|
||||
if (equalizerController != null) {
|
||||
Timber.d("EqualizerController Observer.onChanged received controller");
|
||||
isEqualizerAvailable = true;
|
||||
} else {
|
||||
Timber.d("EqualizerController Observer.onChanged has no controller");
|
||||
isEqualizerAvailable = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@ -528,36 +580,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
|
||||
final View nowPlayingMenuItem = findViewById(R.id.menu_now_playing);
|
||||
menuDrawer.setActiveView(nowPlayingMenuItem);
|
||||
|
||||
if (visualizerAvailable)
|
||||
{
|
||||
visualizerView = new VisualizerView(this);
|
||||
visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
|
||||
if (!visualizerView.isActive())
|
||||
{
|
||||
visualizerViewLayout.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
visualizerViewLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
visualizerView.setOnTouchListener(new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch(final View view, final MotionEvent motionEvent)
|
||||
{
|
||||
visualizerView.setActive(!visualizerView.isActive());
|
||||
getMediaPlayerController().setShowVisualization(visualizerView.isActive());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
visualizerViewLayout.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -768,14 +790,14 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
|
||||
if (equalizerMenuItem != null)
|
||||
{
|
||||
equalizerMenuItem.setEnabled(equalizerAvailable);
|
||||
equalizerMenuItem.setVisible(equalizerAvailable);
|
||||
equalizerMenuItem.setEnabled(isEqualizerAvailable);
|
||||
equalizerMenuItem.setVisible(isEqualizerAvailable);
|
||||
}
|
||||
|
||||
if (visualizerMenuItem != null)
|
||||
{
|
||||
visualizerMenuItem.setEnabled(visualizerAvailable);
|
||||
visualizerMenuItem.setVisible(visualizerAvailable);
|
||||
visualizerMenuItem.setEnabled(isVisualizerAvailable);
|
||||
visualizerMenuItem.setVisible(isVisualizerAvailable);
|
||||
}
|
||||
|
||||
final MediaPlayerController mediaPlayerController = getMediaPlayerController();
|
||||
|
@ -30,6 +30,8 @@ import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.audiofx.EqualizerController;
|
||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||
@ -38,6 +40,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import kotlin.Lazy;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static org.koin.java.KoinJavaComponent.inject;
|
||||
|
||||
@ -55,21 +58,34 @@ public class EqualizerActivity extends ResultActivity
|
||||
private EqualizerController equalizerController;
|
||||
private Equalizer equalizer;
|
||||
|
||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle)
|
||||
{
|
||||
super.onCreate(bundle);
|
||||
setContentView(R.layout.equalizer);
|
||||
|
||||
setup();
|
||||
EqualizerController.get().observe(this, new Observer<EqualizerController>() {
|
||||
@Override
|
||||
public void onChanged(EqualizerController controller) {
|
||||
if (controller != null) {
|
||||
Timber.d("EqualizerController Observer.onChanged received controller");
|
||||
equalizerController = controller;
|
||||
equalizer = controller.equalizer;
|
||||
setup();
|
||||
} else {
|
||||
Timber.d("EqualizerController Observer.onChanged has no controller");
|
||||
equalizerController = null;
|
||||
equalizer = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
if (equalizerController == null) return;
|
||||
equalizerController.saveSettings();
|
||||
}
|
||||
|
||||
@ -77,16 +93,13 @@ public class EqualizerActivity extends ResultActivity
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
if (equalizerController == null)
|
||||
{
|
||||
setup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
if (equalizer == null) return;
|
||||
|
||||
short currentPreset;
|
||||
try
|
||||
@ -112,6 +125,7 @@ public class EqualizerActivity extends ResultActivity
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem)
|
||||
{
|
||||
if (equalizer == null) return true;
|
||||
try
|
||||
{
|
||||
short preset = (short) menuItem.getItemId();
|
||||
@ -128,9 +142,6 @@ public class EqualizerActivity extends ResultActivity
|
||||
|
||||
private void setup()
|
||||
{
|
||||
equalizerController = mediaPlayerControllerLazy.getValue().getEqualizerController();
|
||||
equalizer = equalizerController.getEqualizer();
|
||||
|
||||
initEqualizer();
|
||||
|
||||
final View presetButton = findViewById(R.id.equalizer_preset);
|
||||
@ -158,12 +169,14 @@ public class EqualizerActivity extends ResultActivity
|
||||
|
||||
private void setEqualizerEnabled(boolean enabled)
|
||||
{
|
||||
if (equalizer == null) return;
|
||||
equalizer.setEnabled(enabled);
|
||||
updateBars();
|
||||
}
|
||||
|
||||
private void updateBars()
|
||||
{
|
||||
if (equalizer == null) return;
|
||||
try
|
||||
{
|
||||
for (Map.Entry<Short, SeekBar> entry : bars.entrySet())
|
||||
@ -183,6 +196,7 @@ public class EqualizerActivity extends ResultActivity
|
||||
|
||||
private void initEqualizer()
|
||||
{
|
||||
if (equalizer == null) return;
|
||||
LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
|
||||
|
||||
try
|
||||
|
@ -21,6 +21,10 @@ package org.moire.ultrasonic.audiofx;
|
||||
import android.content.Context;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.audiofx.Equalizer;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
@ -35,61 +39,83 @@ import java.io.Serializable;
|
||||
*/
|
||||
public class EqualizerController
|
||||
{
|
||||
private final Context context;
|
||||
private Equalizer equalizer;
|
||||
private boolean released;
|
||||
private static Boolean available = null;
|
||||
private static MutableLiveData<EqualizerController> instance = new MutableLiveData<>();
|
||||
|
||||
private Context context;
|
||||
public Equalizer equalizer;
|
||||
private int audioSessionId;
|
||||
|
||||
// Class initialization fails when this throws an exception.
|
||||
static
|
||||
/**
|
||||
* Retrieves the EqualizerController as LiveData
|
||||
*/
|
||||
public static LiveData<EqualizerController> get()
|
||||
{
|
||||
try
|
||||
{
|
||||
Class.forName("android.media.audiofx.Equalizer");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the {@link Equalizer} class is not available.
|
||||
* Initializes the EqualizerController instance with a MediaPlayer
|
||||
*/
|
||||
public static void checkAvailable() throws Throwable
|
||||
public static void create(Context context, MediaPlayer mediaPlayer)
|
||||
{
|
||||
// Calling here forces class initialization.
|
||||
}
|
||||
if (mediaPlayer == null) return;
|
||||
if (!isAvailable()) return;
|
||||
|
||||
public EqualizerController(Context context, MediaPlayer mediaPlayer)
|
||||
{
|
||||
this.context = context;
|
||||
EqualizerController controller = new EqualizerController();
|
||||
controller.context = context;
|
||||
|
||||
try
|
||||
{
|
||||
if (mediaPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
controller.audioSessionId = mediaPlayer.getAudioSessionId();
|
||||
controller.equalizer = new Equalizer(0, controller.audioSessionId);
|
||||
controller.loadSettings();
|
||||
|
||||
audioSessionId = mediaPlayer.getAudioSessionId();
|
||||
equalizer = new Equalizer(0, audioSessionId);
|
||||
instance.postValue(controller);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
equalizer = null;
|
||||
Timber.w(x, "Failed to create equalizer.");
|
||||
}
|
||||
}
|
||||
|
||||
public void saveSettings()
|
||||
/**
|
||||
* Releases the EqualizerController instance when the underlying MediaPlayer is no longer available
|
||||
*/
|
||||
public static void release()
|
||||
{
|
||||
EqualizerController controller = instance.getValue();
|
||||
if (controller == null) return;
|
||||
|
||||
controller.equalizer.release();
|
||||
instance.postValue(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@link Equalizer} class is available.
|
||||
*/
|
||||
private static boolean isAvailable()
|
||||
{
|
||||
if (available != null) return available;
|
||||
try
|
||||
{
|
||||
if (isAvailable())
|
||||
{
|
||||
FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat");
|
||||
}
|
||||
Class.forName("android.media.audiofx.Equalizer");
|
||||
available = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Timber.i(ex, "CheckAvailable received an exception getting class for the Equalizer");
|
||||
available = false;
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
public void saveSettings()
|
||||
{
|
||||
if (!available) return;
|
||||
try
|
||||
{
|
||||
FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat");
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
@ -99,16 +125,14 @@ public class EqualizerController
|
||||
|
||||
public void loadSettings()
|
||||
{
|
||||
if (!available) return;
|
||||
try
|
||||
{
|
||||
if (isAvailable())
|
||||
{
|
||||
EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
|
||||
EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
settings.apply(equalizer);
|
||||
}
|
||||
if (settings != null)
|
||||
{
|
||||
settings.apply(equalizer);
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
@ -117,46 +141,8 @@ public class EqualizerController
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAvailable()
|
||||
{
|
||||
return equalizer != null;
|
||||
}
|
||||
|
||||
public void release()
|
||||
{
|
||||
if (isAvailable())
|
||||
{
|
||||
released = true;
|
||||
equalizer.release();
|
||||
}
|
||||
}
|
||||
|
||||
public Equalizer getEqualizer()
|
||||
{
|
||||
if (released)
|
||||
{
|
||||
released = false;
|
||||
|
||||
try
|
||||
{
|
||||
equalizer = new Equalizer(0, audioSessionId);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
equalizer = null;
|
||||
Timber.w(x, "Failed to create equalizer.");
|
||||
}
|
||||
}
|
||||
|
||||
return equalizer;
|
||||
}
|
||||
|
||||
private static class EqualizerSettings implements Serializable
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 626565082425206061L;
|
||||
private final short[] bandLevels;
|
||||
private short preset;
|
||||
|
@ -20,6 +20,10 @@ package org.moire.ultrasonic.audiofx;
|
||||
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.audiofx.Visualizer;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
@ -31,89 +35,76 @@ import timber.log.Timber;
|
||||
public class VisualizerController
|
||||
{
|
||||
private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two.
|
||||
private static Boolean available = null;
|
||||
private static MutableLiveData<VisualizerController> instance = new MutableLiveData<>();
|
||||
|
||||
private Visualizer visualizer;
|
||||
private boolean released;
|
||||
public Visualizer visualizer;
|
||||
private int audioSessionId;
|
||||
|
||||
// Class initialization fails when this throws an exception.
|
||||
static
|
||||
/**
|
||||
* Retrieves the VisualizerController as LiveData
|
||||
*/
|
||||
public static LiveData<VisualizerController> get()
|
||||
{
|
||||
try
|
||||
{
|
||||
Class.forName("android.media.audiofx.Visualizer");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the {@link Visualizer} class is not available.
|
||||
* Initializes the VisualizerController instance with a MediaPlayer
|
||||
*/
|
||||
public static void checkAvailable() throws Throwable
|
||||
public static void create(MediaPlayer mediaPlayer)
|
||||
{
|
||||
// Calling here forces class initialization.
|
||||
}
|
||||
if (mediaPlayer == null) return;
|
||||
if (!isAvailable()) return;
|
||||
|
||||
VisualizerController controller = new VisualizerController();
|
||||
|
||||
public VisualizerController(MediaPlayer mediaPlayer)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mediaPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
controller.audioSessionId = mediaPlayer.getAudioSessionId();
|
||||
controller.visualizer = new Visualizer(controller.audioSessionId);
|
||||
|
||||
audioSessionId = mediaPlayer.getAudioSessionId();
|
||||
visualizer = new Visualizer(audioSessionId);
|
||||
int[] captureSizeRange = Visualizer.getCaptureSizeRange();
|
||||
int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]);
|
||||
captureSize = Math.min(captureSize, captureSizeRange[1]);
|
||||
controller.visualizer.setCaptureSize(captureSize);
|
||||
|
||||
instance.postValue(controller);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
Timber.w(x, "Failed to create visualizer.");
|
||||
}
|
||||
|
||||
if (visualizer != null)
|
||||
{
|
||||
int[] captureSizeRange = Visualizer.getCaptureSizeRange();
|
||||
int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]);
|
||||
captureSize = Math.min(captureSize, captureSizeRange[1]);
|
||||
visualizer.setCaptureSize(captureSize);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAvailable()
|
||||
/**
|
||||
* Releases the VisualizerController instance when the underlying MediaPlayer is no longer available
|
||||
*/
|
||||
public static void release()
|
||||
{
|
||||
return visualizer != null;
|
||||
VisualizerController controller = instance.getValue();
|
||||
if (controller == null) return;
|
||||
|
||||
controller.visualizer.release();
|
||||
instance.postValue(null);
|
||||
}
|
||||
|
||||
public void release()
|
||||
/**
|
||||
* Checks if the {@link Visualizer} class is available.
|
||||
*/
|
||||
private static boolean isAvailable()
|
||||
{
|
||||
if (isAvailable())
|
||||
if (available != null) return available;
|
||||
try
|
||||
{
|
||||
visualizer.release();
|
||||
released = true;
|
||||
Class.forName("android.media.audiofx.Visualizer");
|
||||
available = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Visualizer getVisualizer()
|
||||
{
|
||||
if (released)
|
||||
catch (Exception ex)
|
||||
{
|
||||
released = false;
|
||||
|
||||
try
|
||||
{
|
||||
visualizer = new Visualizer(audioSessionId);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
visualizer = null;
|
||||
Timber.w(x, "Failed to create visualizer.");
|
||||
}
|
||||
Timber.i(ex, "CheckAvailable received an exception getting class for the Visualizer");
|
||||
available = false;
|
||||
}
|
||||
|
||||
return visualizer;
|
||||
return available;
|
||||
}
|
||||
}
|
@ -55,9 +55,6 @@ public class LocalMediaPlayer
|
||||
public Runnable onPrepared;
|
||||
public Runnable onNextSongRequested;
|
||||
|
||||
public static boolean equalizerAvailable;
|
||||
public static boolean visualizerAvailable;
|
||||
|
||||
public PlayerState playerState = IDLE;
|
||||
public DownloadFile currentPlaying;
|
||||
public DownloadFile nextPlaying;
|
||||
@ -77,8 +74,6 @@ public class LocalMediaPlayer
|
||||
private AudioManager audioManager;
|
||||
private RemoteControlClient remoteControlClient;
|
||||
|
||||
private EqualizerController equalizerController;
|
||||
private VisualizerController visualizerController;
|
||||
private CancellableTask bufferTask;
|
||||
private PositionCache positionCache;
|
||||
private int secondaryProgress = -1;
|
||||
@ -86,32 +81,6 @@ public class LocalMediaPlayer
|
||||
private final AudioFocusHandler audioFocusHandler;
|
||||
private final Context context;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
EqualizerController.checkAvailable();
|
||||
equalizerAvailable = true;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
equalizerAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
VisualizerController.checkAvailable();
|
||||
visualizerAvailable = true;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
visualizerAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalMediaPlayer(AudioFocusHandler audioFocusHandler, Context context)
|
||||
{
|
||||
this.audioFocusHandler = audioFocusHandler;
|
||||
@ -164,6 +133,15 @@ public class LocalMediaPlayer
|
||||
}
|
||||
}).start();
|
||||
|
||||
// Create Equalizer and Visualizer on a new thread as this can potentially take some time
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EqualizerController.create(context, mediaPlayer);
|
||||
VisualizerController.create(mediaPlayer);
|
||||
}
|
||||
}).start();
|
||||
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
|
||||
wakeLock.setReferenceCounted(false);
|
||||
@ -172,28 +150,6 @@ public class LocalMediaPlayer
|
||||
Util.registerMediaButtonEventReceiver(context, true);
|
||||
setUpRemoteControlClient();
|
||||
|
||||
if (equalizerAvailable)
|
||||
{
|
||||
equalizerController = new EqualizerController(context, mediaPlayer);
|
||||
if (!equalizerController.isAvailable())
|
||||
{
|
||||
equalizerController = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
equalizerController.loadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
if (visualizerAvailable)
|
||||
{
|
||||
visualizerController = new VisualizerController(mediaPlayer);
|
||||
if (!visualizerController.isAvailable())
|
||||
{
|
||||
visualizerController = null;
|
||||
}
|
||||
}
|
||||
|
||||
Timber.i("LocalMediaPlayer created");
|
||||
}
|
||||
|
||||
@ -208,6 +164,9 @@ public class LocalMediaPlayer
|
||||
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
|
||||
context.sendBroadcast(i);
|
||||
|
||||
EqualizerController.release();
|
||||
VisualizerController.release();
|
||||
|
||||
mediaPlayer.release();
|
||||
if (nextMediaPlayer != null)
|
||||
{
|
||||
@ -216,16 +175,6 @@ public class LocalMediaPlayer
|
||||
|
||||
mediaPlayerLooper.quit();
|
||||
|
||||
if (equalizerController != null)
|
||||
{
|
||||
equalizerController.release();
|
||||
}
|
||||
|
||||
if (visualizerController != null)
|
||||
{
|
||||
visualizerController.release();
|
||||
}
|
||||
|
||||
if (bufferTask != null)
|
||||
{
|
||||
bufferTask.cancel();
|
||||
@ -249,36 +198,6 @@ public class LocalMediaPlayer
|
||||
Timber.i("LocalMediaPlayer destroyed");
|
||||
}
|
||||
|
||||
public EqualizerController getEqualizerController()
|
||||
{
|
||||
if (equalizerAvailable && equalizerController == null)
|
||||
{
|
||||
equalizerController = new EqualizerController(context, mediaPlayer);
|
||||
if (!equalizerController.isAvailable())
|
||||
{
|
||||
equalizerController = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
equalizerController.loadSettings();
|
||||
}
|
||||
}
|
||||
return equalizerController;
|
||||
}
|
||||
|
||||
public VisualizerController getVisualizerController()
|
||||
{
|
||||
if (visualizerAvailable && visualizerController == null)
|
||||
{
|
||||
visualizerController = new VisualizerController(mediaPlayer);
|
||||
if (!visualizerController.isAvailable())
|
||||
{
|
||||
visualizerController = null;
|
||||
}
|
||||
}
|
||||
return visualizerController;
|
||||
}
|
||||
|
||||
public synchronized void setPlayerState(final PlayerState playerState)
|
||||
{
|
||||
Timber.i("%s -> %s (%s)", this.playerState.name(), playerState.name(), currentPlaying);
|
||||
|
@ -93,10 +93,6 @@ public interface MediaPlayerController
|
||||
|
||||
String getSuggestedPlaylistName();
|
||||
|
||||
EqualizerController getEqualizerController();
|
||||
|
||||
VisualizerController getVisualizerController();
|
||||
|
||||
boolean isJukeboxEnabled();
|
||||
|
||||
boolean isJukeboxAvailable();
|
||||
|
@ -510,22 +510,6 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
|
||||
return suggestedPlaylistName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EqualizerController getEqualizerController()
|
||||
{
|
||||
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
|
||||
if (mediaPlayerService == null) return null;
|
||||
return localMediaPlayer.getEqualizerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualizerController getVisualizerController()
|
||||
{
|
||||
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
|
||||
if (mediaPlayerService == null) return null;
|
||||
return localMediaPlayer.getVisualizerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJukeboxEnabled()
|
||||
{
|
||||
|
@ -25,11 +25,15 @@ import android.graphics.Paint;
|
||||
import android.media.audiofx.Visualizer;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import org.moire.ultrasonic.audiofx.VisualizerController;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||
|
||||
import kotlin.Lazy;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static org.koin.java.KoinJavaComponent.inject;
|
||||
|
||||
@ -45,20 +49,35 @@ public class VisualizerView extends View
|
||||
private static final int PREFERRED_CAPTURE_RATE_MILLIHERTZ = 20000;
|
||||
|
||||
private final Paint paint = new Paint();
|
||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
|
||||
private byte[] data;
|
||||
private float[] points;
|
||||
private boolean active;
|
||||
private Visualizer visualizer;
|
||||
|
||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
|
||||
public VisualizerView(Context context)
|
||||
public VisualizerView(final Context context)
|
||||
{
|
||||
super(context);
|
||||
|
||||
paint.setStrokeWidth(2f);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(Color.rgb(0, 153, 204));
|
||||
|
||||
VisualizerController.get().observe((LifecycleOwner) context, new Observer<VisualizerController>() {
|
||||
@Override
|
||||
public void onChanged(VisualizerController controller) {
|
||||
if (controller != null) {
|
||||
Timber.d("VisualizerController Observer.onChanged received controller");
|
||||
visualizer = controller.visualizer;
|
||||
setActive(true);
|
||||
} else {
|
||||
Timber.d("VisualizerController Observer.onChanged has no controller");
|
||||
visualizer = null;
|
||||
setActive(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
@ -66,15 +85,9 @@ public class VisualizerView extends View
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active)
|
||||
public void setActive(boolean value)
|
||||
{
|
||||
this.active = active;
|
||||
Visualizer visualizer = getVizualizer();
|
||||
if (visualizer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
active = value;
|
||||
int captureRate = Math.min(PREFERRED_CAPTURE_RATE_MILLIHERTZ, Visualizer.getMaxCaptureRate());
|
||||
if (active)
|
||||
{
|
||||
@ -94,19 +107,13 @@ public class VisualizerView extends View
|
||||
}
|
||||
else
|
||||
{
|
||||
visualizer.setDataCaptureListener(null, captureRate, false, false);
|
||||
if (visualizer != null) visualizer.setDataCaptureListener(null, captureRate, false, false);
|
||||
}
|
||||
|
||||
visualizer.setEnabled(active);
|
||||
if (visualizer != null) visualizer.setEnabled(active);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private Visualizer getVizualizer()
|
||||
{
|
||||
VisualizerController visualizerController = mediaPlayerControllerLazy.getValue().getVisualizerController();
|
||||
return visualizerController == null ? null : visualizerController.getVisualizer();
|
||||
}
|
||||
|
||||
private void updateVisualizer(byte[] waveform)
|
||||
{
|
||||
this.data = waveform;
|
||||
|
Loading…
x
Reference in New Issue
Block a user