Skip to content

Commit

Permalink
Implement Tunnel Player workaround code
Browse files Browse the repository at this point in the history
Issue: "Visualization does not work on the new Galaxy devices"
  felixpalmer#5
  • Loading branch information
h6ah4i committed Dec 5, 2013
1 parent 4054f8b commit 0230eef
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
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.decod" 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;
}
}

0 comments on commit 0230eef

Please sign in to comment.