Merge branch 'nitehu-fix/equalizer_visualizer_init' into develop

This commit is contained in:
Óscar García Amor 2020-10-25 10:58:37 +01:00
commit 440b2109d3
No known key found for this signature in database
GPG Key ID: E18B2370D3D566EE
8 changed files with 232 additions and 313 deletions

View File

@ -49,10 +49,14 @@ import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.ViewFlipper; import android.widget.ViewFlipper;
import androidx.lifecycle.Observer;
import com.mobeta.android.dslv.DragSortListView; import com.mobeta.android.dslv.DragSortListView;
import org.koin.java.KoinJavaComponent; import org.koin.java.KoinJavaComponent;
import org.moire.ultrasonic.R; 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.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.MusicDirectory; import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicDirectory.Entry; import org.moire.ultrasonic.domain.MusicDirectory.Entry;
@ -117,8 +121,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
private int swipeDistance; private int swipeDistance;
private int swipeVelocity; private int swipeVelocity;
private VisualizerView visualizerView; private VisualizerView visualizerView;
private boolean visualizerAvailable;
private boolean equalizerAvailable;
private boolean jukeboxAvailable; private boolean jukeboxAvailable;
private SilentBackgroundTask<Void> onProgressChangedTask; private SilentBackgroundTask<Void> onProgressChangedTask;
LinearLayout visualizerViewLayout; LinearLayout visualizerViewLayout;
@ -133,6 +135,9 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
private Drawable hollowStar; private Drawable hollowStar;
private Drawable fullStar; private Drawable fullStar;
private boolean isEqualizerAvailable;
private boolean isVisualizerAvailable;
/** /**
* Called when the activity is first created. * Called when the activity is first created.
*/ */
@ -506,8 +511,55 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
mediaPlayerController.setShufflePlayEnabled(true); mediaPlayerController.setShufflePlayEnabled(true);
} }
visualizerAvailable = (mediaPlayerController != null) && (mediaPlayerController.getVisualizerController() != null); visualizerViewLayout.setVisibility(View.GONE);
equalizerAvailable = (mediaPlayerController != null) && (mediaPlayerController.getEqualizerController() != null); 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() new Thread(new Runnable()
{ {
@ -528,36 +580,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
final View nowPlayingMenuItem = findViewById(R.id.menu_now_playing); final View nowPlayingMenuItem = findViewById(R.id.menu_now_playing);
menuDrawer.setActiveView(nowPlayingMenuItem); 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 @Override
@ -768,14 +790,14 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
if (equalizerMenuItem != null) if (equalizerMenuItem != null)
{ {
equalizerMenuItem.setEnabled(equalizerAvailable); equalizerMenuItem.setEnabled(isEqualizerAvailable);
equalizerMenuItem.setVisible(equalizerAvailable); equalizerMenuItem.setVisible(isEqualizerAvailable);
} }
if (visualizerMenuItem != null) if (visualizerMenuItem != null)
{ {
visualizerMenuItem.setEnabled(visualizerAvailable); visualizerMenuItem.setEnabled(isVisualizerAvailable);
visualizerMenuItem.setVisible(visualizerAvailable); visualizerMenuItem.setVisible(isVisualizerAvailable);
} }
final MediaPlayerController mediaPlayerController = getMediaPlayerController(); final MediaPlayerController mediaPlayerController = getMediaPlayerController();

View File

@ -30,6 +30,8 @@ import android.widget.LinearLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.lifecycle.Observer;
import org.moire.ultrasonic.R; import org.moire.ultrasonic.R;
import org.moire.ultrasonic.audiofx.EqualizerController; import org.moire.ultrasonic.audiofx.EqualizerController;
import org.moire.ultrasonic.service.MediaPlayerController; import org.moire.ultrasonic.service.MediaPlayerController;
@ -38,6 +40,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import kotlin.Lazy; import kotlin.Lazy;
import timber.log.Timber;
import static org.koin.java.KoinJavaComponent.inject; import static org.koin.java.KoinJavaComponent.inject;
@ -55,21 +58,34 @@ public class EqualizerActivity extends ResultActivity
private EqualizerController equalizerController; private EqualizerController equalizerController;
private Equalizer equalizer; private Equalizer equalizer;
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
@Override @Override
public void onCreate(Bundle bundle) public void onCreate(Bundle bundle)
{ {
super.onCreate(bundle); super.onCreate(bundle);
setContentView(R.layout.equalizer); 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 @Override
protected void onPause() protected void onPause()
{ {
super.onPause(); super.onPause();
if (equalizerController == null) return;
equalizerController.saveSettings(); equalizerController.saveSettings();
} }
@ -77,16 +93,13 @@ public class EqualizerActivity extends ResultActivity
protected void onResume() protected void onResume()
{ {
super.onResume(); super.onResume();
if (equalizerController == null)
{
setup();
}
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
{ {
super.onCreateContextMenu(menu, view, menuInfo); super.onCreateContextMenu(menu, view, menuInfo);
if (equalizer == null) return;
short currentPreset; short currentPreset;
try try
@ -112,6 +125,7 @@ public class EqualizerActivity extends ResultActivity
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem) public boolean onContextItemSelected(MenuItem menuItem)
{ {
if (equalizer == null) return true;
try try
{ {
short preset = (short) menuItem.getItemId(); short preset = (short) menuItem.getItemId();
@ -128,9 +142,6 @@ public class EqualizerActivity extends ResultActivity
private void setup() private void setup()
{ {
equalizerController = mediaPlayerControllerLazy.getValue().getEqualizerController();
equalizer = equalizerController.getEqualizer();
initEqualizer(); initEqualizer();
final View presetButton = findViewById(R.id.equalizer_preset); final View presetButton = findViewById(R.id.equalizer_preset);
@ -158,12 +169,14 @@ public class EqualizerActivity extends ResultActivity
private void setEqualizerEnabled(boolean enabled) private void setEqualizerEnabled(boolean enabled)
{ {
if (equalizer == null) return;
equalizer.setEnabled(enabled); equalizer.setEnabled(enabled);
updateBars(); updateBars();
} }
private void updateBars() private void updateBars()
{ {
if (equalizer == null) return;
try try
{ {
for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) for (Map.Entry<Short, SeekBar> entry : bars.entrySet())
@ -183,6 +196,7 @@ public class EqualizerActivity extends ResultActivity
private void initEqualizer() private void initEqualizer()
{ {
if (equalizer == null) return;
LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout); LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
try try

View File

@ -21,6 +21,10 @@ package org.moire.ultrasonic.audiofx;
import android.content.Context; import android.content.Context;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.media.audiofx.Equalizer; import android.media.audiofx.Equalizer;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import timber.log.Timber; import timber.log.Timber;
import org.moire.ultrasonic.util.FileUtil; import org.moire.ultrasonic.util.FileUtil;
@ -35,61 +39,83 @@ import java.io.Serializable;
*/ */
public class EqualizerController public class EqualizerController
{ {
private final Context context; private static Boolean available = null;
private Equalizer equalizer; private static MutableLiveData<EqualizerController> instance = new MutableLiveData<>();
private boolean released;
private Context context;
public Equalizer equalizer;
private int audioSessionId; private int audioSessionId;
// Class initialization fails when this throws an exception. /**
static * Retrieves the EqualizerController as LiveData
*/
public static LiveData<EqualizerController> get()
{ {
try return instance;
{
Class.forName("android.media.audiofx.Equalizer");
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
} }
/** /**
* 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) EqualizerController controller = new EqualizerController();
{ controller.context = context;
this.context = context;
try try
{ {
if (mediaPlayer == null) controller.audioSessionId = mediaPlayer.getAudioSessionId();
{ controller.equalizer = new Equalizer(0, controller.audioSessionId);
return; controller.loadSettings();
}
audioSessionId = mediaPlayer.getAudioSessionId(); instance.postValue(controller);
equalizer = new Equalizer(0, audioSessionId);
} }
catch (Throwable x) catch (Throwable x)
{ {
equalizer = null;
Timber.w(x, "Failed to create equalizer."); 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 try
{ {
if (isAvailable()) Class.forName("android.media.audiofx.Equalizer");
{ available = true;
FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat"); }
} 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) catch (Throwable x)
{ {
@ -99,16 +125,14 @@ public class EqualizerController
public void loadSettings() public void loadSettings()
{ {
if (!available) return;
try try
{ {
if (isAvailable()) EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
{
EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
if (settings != null) if (settings != null)
{ {
settings.apply(equalizer); settings.apply(equalizer);
}
} }
} }
catch (Throwable x) 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 class EqualizerSettings implements Serializable
{ {
/**
*
*/
private static final long serialVersionUID = 626565082425206061L; private static final long serialVersionUID = 626565082425206061L;
private final short[] bandLevels; private final short[] bandLevels;
private short preset; private short preset;

View File

@ -20,6 +20,10 @@ package org.moire.ultrasonic.audiofx;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.media.audiofx.Visualizer; import android.media.audiofx.Visualizer;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -31,89 +35,76 @@ import timber.log.Timber;
public class VisualizerController public class VisualizerController
{ {
private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two. 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; public Visualizer visualizer;
private boolean released;
private int audioSessionId; private int audioSessionId;
// Class initialization fails when this throws an exception. /**
static * Retrieves the VisualizerController as LiveData
*/
public static LiveData<VisualizerController> get()
{ {
try return instance;
{
Class.forName("android.media.audiofx.Visualizer");
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
} }
/** /**
* 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 try
{ {
if (mediaPlayer == null) controller.audioSessionId = mediaPlayer.getAudioSessionId();
{ controller.visualizer = new Visualizer(controller.audioSessionId);
return;
}
audioSessionId = mediaPlayer.getAudioSessionId(); int[] captureSizeRange = Visualizer.getCaptureSizeRange();
visualizer = new Visualizer(audioSessionId); 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) catch (Throwable x)
{ {
Timber.w(x, "Failed to create visualizer."); 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(); Class.forName("android.media.audiofx.Visualizer");
released = true; available = true;
} }
} catch (Exception ex)
public Visualizer getVisualizer()
{
if (released)
{ {
released = false; Timber.i(ex, "CheckAvailable received an exception getting class for the Visualizer");
available = false;
try
{
visualizer = new Visualizer(audioSessionId);
}
catch (Throwable x)
{
visualizer = null;
Timber.w(x, "Failed to create visualizer.");
}
} }
return available;
return visualizer;
} }
} }

View File

@ -55,9 +55,6 @@ public class LocalMediaPlayer
public Runnable onPrepared; public Runnable onPrepared;
public Runnable onNextSongRequested; public Runnable onNextSongRequested;
public static boolean equalizerAvailable;
public static boolean visualizerAvailable;
public PlayerState playerState = IDLE; public PlayerState playerState = IDLE;
public DownloadFile currentPlaying; public DownloadFile currentPlaying;
public DownloadFile nextPlaying; public DownloadFile nextPlaying;
@ -77,8 +74,6 @@ public class LocalMediaPlayer
private AudioManager audioManager; private AudioManager audioManager;
private RemoteControlClient remoteControlClient; private RemoteControlClient remoteControlClient;
private EqualizerController equalizerController;
private VisualizerController visualizerController;
private CancellableTask bufferTask; private CancellableTask bufferTask;
private PositionCache positionCache; private PositionCache positionCache;
private int secondaryProgress = -1; private int secondaryProgress = -1;
@ -86,32 +81,6 @@ public class LocalMediaPlayer
private final AudioFocusHandler audioFocusHandler; private final AudioFocusHandler audioFocusHandler;
private final Context context; 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) public LocalMediaPlayer(AudioFocusHandler audioFocusHandler, Context context)
{ {
this.audioFocusHandler = audioFocusHandler; this.audioFocusHandler = audioFocusHandler;
@ -164,6 +133,15 @@ public class LocalMediaPlayer
} }
}).start(); }).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); PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
@ -172,28 +150,6 @@ public class LocalMediaPlayer
Util.registerMediaButtonEventReceiver(context, true); Util.registerMediaButtonEventReceiver(context, true);
setUpRemoteControlClient(); 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"); Timber.i("LocalMediaPlayer created");
} }
@ -208,6 +164,9 @@ public class LocalMediaPlayer
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName()); i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
context.sendBroadcast(i); context.sendBroadcast(i);
EqualizerController.release();
VisualizerController.release();
mediaPlayer.release(); mediaPlayer.release();
if (nextMediaPlayer != null) if (nextMediaPlayer != null)
{ {
@ -216,16 +175,6 @@ public class LocalMediaPlayer
mediaPlayerLooper.quit(); mediaPlayerLooper.quit();
if (equalizerController != null)
{
equalizerController.release();
}
if (visualizerController != null)
{
visualizerController.release();
}
if (bufferTask != null) if (bufferTask != null)
{ {
bufferTask.cancel(); bufferTask.cancel();
@ -249,36 +198,6 @@ public class LocalMediaPlayer
Timber.i("LocalMediaPlayer destroyed"); 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) public synchronized void setPlayerState(final PlayerState playerState)
{ {
Timber.i("%s -> %s (%s)", this.playerState.name(), playerState.name(), currentPlaying); Timber.i("%s -> %s (%s)", this.playerState.name(), playerState.name(), currentPlaying);

View File

@ -93,10 +93,6 @@ public interface MediaPlayerController
String getSuggestedPlaylistName(); String getSuggestedPlaylistName();
EqualizerController getEqualizerController();
VisualizerController getVisualizerController();
boolean isJukeboxEnabled(); boolean isJukeboxEnabled();
boolean isJukeboxAvailable(); boolean isJukeboxAvailable();

View File

@ -510,22 +510,6 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
return suggestedPlaylistName; 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 @Override
public boolean isJukeboxEnabled() public boolean isJukeboxEnabled()
{ {

View File

@ -25,11 +25,15 @@ import android.graphics.Paint;
import android.media.audiofx.Visualizer; import android.media.audiofx.Visualizer;
import android.view.View; import android.view.View;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import org.moire.ultrasonic.audiofx.VisualizerController; import org.moire.ultrasonic.audiofx.VisualizerController;
import org.moire.ultrasonic.domain.PlayerState; import org.moire.ultrasonic.domain.PlayerState;
import org.moire.ultrasonic.service.MediaPlayerController; import org.moire.ultrasonic.service.MediaPlayerController;
import kotlin.Lazy; import kotlin.Lazy;
import timber.log.Timber;
import static org.koin.java.KoinJavaComponent.inject; 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 static final int PREFERRED_CAPTURE_RATE_MILLIHERTZ = 20000;
private final Paint paint = new Paint(); private final Paint paint = new Paint();
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
private byte[] data; private byte[] data;
private float[] points; private float[] points;
private boolean active; private boolean active;
private Visualizer visualizer;
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class); public VisualizerView(final Context context)
public VisualizerView(Context context)
{ {
super(context); super(context);
paint.setStrokeWidth(2f); paint.setStrokeWidth(2f);
paint.setAntiAlias(true); paint.setAntiAlias(true);
paint.setColor(Color.rgb(0, 153, 204)); 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() public boolean isActive()
@ -66,15 +85,9 @@ public class VisualizerView extends View
return active; return active;
} }
public void setActive(boolean active) public void setActive(boolean value)
{ {
this.active = active; active = value;
Visualizer visualizer = getVizualizer();
if (visualizer == null)
{
return;
}
int captureRate = Math.min(PREFERRED_CAPTURE_RATE_MILLIHERTZ, Visualizer.getMaxCaptureRate()); int captureRate = Math.min(PREFERRED_CAPTURE_RATE_MILLIHERTZ, Visualizer.getMaxCaptureRate());
if (active) if (active)
{ {
@ -94,19 +107,13 @@ public class VisualizerView extends View
} }
else 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(); invalidate();
} }
private Visualizer getVizualizer()
{
VisualizerController visualizerController = mediaPlayerControllerLazy.getValue().getVisualizerController();
return visualizerController == null ? null : visualizerController.getVisualizer();
}
private void updateVisualizer(byte[] waveform) private void updateVisualizer(byte[] waveform)
{ {
this.data = waveform; this.data = waveform;