Skip to content

Implement Tunnel Player workaround code #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added res/raw/workaround_1min.mp3
Binary file not shown.
27 changes: 27 additions & 0 deletions src/com/pheelicks/app/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.os.Bundle;
import android.view.View;

import com.pheelicks.utils.TunnelPlayerWorkaround;
import com.pheelicks.visualizer.R;
import com.pheelicks.visualizer.VisualizerView;
import com.pheelicks.visualizer.renderer.BarGraphRenderer;
Expand All @@ -29,6 +30,7 @@
*/
public class MainActivity extends Activity {
private MediaPlayer mPlayer;
private MediaPlayer mSilentPlayer; /* to avoid tunnel player issue */
private VisualizerView mVisualizerView;

/** Called when the activity is first created. */
Expand All @@ -42,6 +44,7 @@ public void onCreate(Bundle savedInstanceState) {
protected void onResume()
{
super.onResume();
initTunnelPlayerWorkaround();
init();
}

Expand Down Expand Up @@ -82,6 +85,30 @@ private void cleanUp()
mPlayer.release();
mPlayer = null;
}

if (mSilentPlayer != null)
{
mSilentPlayer.release();
mSilentPlayer = null;
}
}

// Workaround (for Galaxy S4)
//
// "Visualization does not work on the new Galaxy devices"
// https://github.com/felixpalmer/android-visualizer/issues/5
//
// NOTE:
// This code is not required for visualizing default "test.mp3" file,
// because tunnel player is used when duration is longer than 1 minute.
// (default "test.mp3" file: 8 seconds)
//
private void initTunnelPlayerWorkaround() {
// Read "tunnel.decode" system property to determine
// the workaround is needed
if (TunnelPlayerWorkaround.isTunnelDecodeEnabled(this)) {
mSilentPlayer = TunnelPlayerWorkaround.createSilentMediaPlayer(this);
}
}

// Methods for adding renderers to visualizer
Expand Down
73 changes: 73 additions & 0 deletions src/com/pheelicks/utils/SystemPropertiesProxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* Copyright 2013, Haruki Hasegawa
*
* Licensed under the MIT license:
* http://creativecommons.org/licenses/MIT/
*/

/**
* from http://stackoverflow.com/questions/2641111/where-is-android-os-systemproperties
*/

package com.pheelicks.utils;

import java.lang.reflect.Method;

import android.content.Context;
import android.util.Log;

public class SystemPropertiesProxy {
private static final String TAG = "SystemPropertiesProxy";

/**
* Get the value for the given key, returned as a boolean. Values 'n', 'no',
* '0', 'false' or 'off' are considered false. Values 'y', 'yes', '1', 'true'
* or 'on' are considered true. (case insensitive). If the key does not exist,
* or has any other value, then the default result is returned.
*
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as a boolean, or def if the key isn't found or is
* not able to be parsed as a boolean.
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static Boolean getBoolean(Context context, String key, boolean def)
throws IllegalArgumentException {
return getBoolean(context.getClassLoader(), key, def);
}

public static Boolean getBoolean(ClassLoader cl, String key, boolean def)
throws IllegalArgumentException {

Boolean ret = def;

try {
@SuppressWarnings("rawtypes")
Class SystemProperties = cl.loadClass("android.os.SystemProperties");

// Parameters Types
@SuppressWarnings("rawtypes")
Class[] paramTypes = new Class[2];
paramTypes[0] = String.class;
paramTypes[1] = boolean.class;

@SuppressWarnings("unchecked")
Method getBoolean = SystemProperties.getMethod("getBoolean", paramTypes);

// Parameters
Object[] params = new Object[2];
params[0] = new String(key);
params[1] = Boolean.valueOf(def);

ret = (Boolean) getBoolean.invoke(SystemProperties, params);

} catch (IllegalArgumentException iAE) {
throw iAE;
} catch (Exception e) {
Log.e(TAG, "getBoolean(context, key: " + key + ", def:" + def + ")", e);
ret = def;
}

return ret;
}
}
72 changes: 72 additions & 0 deletions src/com/pheelicks/utils/TunnelPlayerWorkaround.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright 2013, Haruki Hasegawa
*
* Licensed under the MIT license:
* http://creativecommons.org/licenses/MIT/
*/

package com.pheelicks.utils;

import java.io.IOException;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.util.Log;

import com.pheelicks.visualizer.R;

public class TunnelPlayerWorkaround {
private static final String TAG = "TunnelPlayerWorkaround";

private static final String SYSTEM_PROP_TUNNEL_DECODE_ENABLED = "tunnel.decode";

private TunnelPlayerWorkaround()
{
}

/**
* Obtain "tunnel.decode" system property value
*
* @param context Context
* @return Whether tunnel player is enabled
*/
public static boolean isTunnelDecodeEnabled(Context context)
{
return SystemPropertiesProxy.getBoolean(
context, SYSTEM_PROP_TUNNEL_DECODE_ENABLED, false);
}

/**
* Create silent MediaPlayer instance to avoid tunnel player issue
*
* @param context Context
* @return MediaPlayer instance
*/
public static MediaPlayer createSilentMediaPlayer(Context context)
{
boolean result = false;

MediaPlayer mp = null;
try {
mp = MediaPlayer.create(context, R.raw.workaround_1min);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);

// NOTE: start() is no needed
// mp.start();

result = true;
} catch (RuntimeException e) {
Log.e(TAG, "createSilentMediaPlayer()", e);
} finally {
if (!result && mp != null) {
try {
mp.release();
} catch (IllegalStateException e) {
}
}
}

return mp;
}
}