Compare commits

...
14 Commits
9 changed files with 174 additions and 36 deletions

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.limelight" package="com.limelight"
android:versionCode="12" android:versionCode="14"
android:versionName="2.1.6" > android:versionName="2.2.1" >
<uses-sdk <uses-sdk
android:minSdkVersion="16" android:minSdkVersion="16"
+12 -9
View File
@@ -35,18 +35,21 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
public static final int ic_launcher=0x7f020000; public static final int ic_launcher=0x7f020000;
} }
public static final class id { public static final class id {
public static final int autoDec=0x7f080005; public static final int autoDec=0x7f080006;
public static final int config1080p30Selected=0x7f080009; public static final int bitrateLabel=0x7f08000c;
public static final int config1080p60Selected=0x7f08000a; public static final int bitrateSeekBar=0x7f08000d;
public static final int config720p30Selected=0x7f080007; public static final int config1080p30Selected=0x7f08000a;
public static final int config720p60Selected=0x7f080008; public static final int config1080p60Selected=0x7f08000b;
public static final int hardwareDec=0x7f080006; public static final int config720p30Selected=0x7f080008;
public static final int config720p60Selected=0x7f080009;
public static final int decoderConfigGroup=0x7f080003;
public static final int hardwareDec=0x7f080007;
public static final int hostTextView=0x7f080000; public static final int hostTextView=0x7f080000;
public static final int pairButton=0x7f080002; public static final int pairButton=0x7f080002;
public static final int softwareDec=0x7f080004; public static final int softwareDec=0x7f080005;
public static final int statusButton=0x7f080001; public static final int statusButton=0x7f080001;
public static final int streamConfigGroup=0x7f080003; public static final int streamConfigGroup=0x7f080004;
public static final int surfaceView=0x7f08000b; public static final int surfaceView=0x7f08000e;
} }
public static final class layout { public static final class layout {
public static final int activity_connection=0x7f030000; public static final int activity_connection=0x7f030000;
Binary file not shown.
BIN
View File
Binary file not shown.
+25 -6
View File
@@ -5,7 +5,7 @@
android:paddingBottom="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="10dp"
tools:context=".Connection" > tools:context=".Connection" >
<RelativeLayout <RelativeLayout
@@ -45,12 +45,13 @@
android:text="Pair with PC" /> android:text="Pair with PC" />
<RadioGroup <RadioGroup
android:id="@+id/decoderConfigGroup"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_below="@+id/streamConfigGroup" android:layout_below="@+id/streamConfigGroup"
android:layout_marginTop="25dp" android:layout_marginTop="15dp"
android:orientation="vertical" > android:orientation="vertical" >
<RadioButton <RadioButton
@@ -79,7 +80,7 @@
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_below="@+id/pairButton" android:layout_below="@+id/pairButton"
android:layout_marginTop="25dp" android:layout_marginTop="10dp"
android:orientation="vertical" > android:orientation="vertical" >
<RadioButton <RadioButton
@@ -92,24 +93,42 @@
android:id="@+id/config720p60Selected" android:id="@+id/config720p60Selected"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="7dp"
android:text="720p 60 FPS (Recommended for most devices and networks)" /> android:text="720p 60 FPS (Recommended for most devices and networks)" />
<RadioButton <RadioButton
android:id="@+id/config1080p30Selected" android:id="@+id/config1080p30Selected"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="7dp"
android:text="1080p 30 FPS (Recommended for most devices if 1080p streaming is desired)" /> android:text="1080p 30 FPS (Recommended for most devices if 1080p streaming is desired)" />
<RadioButton <RadioButton
android:id="@+id/config1080p60Selected" android:id="@+id/config1080p60Selected"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="7dp"
android:text="1080p 60 FPS (Requires extremely fast device and network)" /> android:text="1080p 60 FPS (Requires extremely fast device and network)" />
</RadioGroup> </RadioGroup>
<TextView
android:id="@+id/bitrateLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_below="@+id/decoderConfigGroup" />
<SeekBar
android:id="@+id/bitrateSeekBar"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/decoderConfigGroup"
android:layout_toLeftOf="@+id/bitrateLabel" />
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>
+71 -4
View File
@@ -20,6 +20,8 @@ import android.widget.Button;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.app.Activity; import android.app.Activity;
@@ -33,6 +35,8 @@ public class Connection extends Activity {
private SharedPreferences prefs; private SharedPreferences prefs;
private RadioButton rbutton720p30, rbutton720p60, rbutton1080p30, rbutton1080p60; private RadioButton rbutton720p30, rbutton720p60, rbutton1080p30, rbutton1080p60;
private RadioButton forceSoftDec, autoDec, forceHardDec; private RadioButton forceSoftDec, autoDec, forceHardDec;
private SeekBar bitrateSlider;
private TextView bitrateLabel;
private static final String DEFAULT_HOST = ""; private static final String DEFAULT_HOST = "";
public static final String HOST_KEY = "hostText"; public static final String HOST_KEY = "hostText";
@@ -42,6 +46,7 @@ public class Connection extends Activity {
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putString(Connection.HOST_KEY, this.hostText.getText().toString()); editor.putString(Connection.HOST_KEY, this.hostText.getText().toString());
editor.putInt(Game.BITRATE_PREF_STRING, bitrateSlider.getProgress());
editor.apply(); editor.apply();
super.onPause(); super.onPause();
@@ -66,6 +71,8 @@ public class Connection extends Activity {
this.forceSoftDec = (RadioButton) findViewById(R.id.softwareDec); this.forceSoftDec = (RadioButton) findViewById(R.id.softwareDec);
this.autoDec = (RadioButton) findViewById(R.id.autoDec); this.autoDec = (RadioButton) findViewById(R.id.autoDec);
this.forceHardDec = (RadioButton) findViewById(R.id.hardwareDec); this.forceHardDec = (RadioButton) findViewById(R.id.hardwareDec);
this.bitrateLabel = (TextView) findViewById(R.id.bitrateLabel);
this.bitrateSlider = (SeekBar) findViewById(R.id.bitrateSeekBar);
prefs = getSharedPreferences(Game.PREFS_FILE_NAME, Context.MODE_MULTI_PROCESS); prefs = getSharedPreferences(Game.PREFS_FILE_NAME, Context.MODE_MULTI_PROCESS);
this.hostText.setText(prefs.getString(Connection.HOST_KEY, Connection.DEFAULT_HOST)); this.hostText.setText(prefs.getString(Connection.HOST_KEY, Connection.DEFAULT_HOST));
@@ -73,6 +80,10 @@ public class Connection extends Activity {
boolean res720p = prefs.getInt(Game.HEIGHT_PREF_STRING, Game.DEFAULT_HEIGHT) == 720; boolean res720p = prefs.getInt(Game.HEIGHT_PREF_STRING, Game.DEFAULT_HEIGHT) == 720;
boolean fps30 = prefs.getInt(Game.REFRESH_RATE_PREF_STRING, Game.DEFAULT_REFRESH_RATE) == 30; boolean fps30 = prefs.getInt(Game.REFRESH_RATE_PREF_STRING, Game.DEFAULT_REFRESH_RATE) == 30;
bitrateSlider.setMax(Game.BITRATE_CEILING);
bitrateSlider.setProgress(prefs.getInt(Game.BITRATE_PREF_STRING, Game.DEFAULT_BITRATE));
updateBitrateLabel();
rbutton720p30.setChecked(false); rbutton720p30.setChecked(false);
rbutton720p60.setChecked(false); rbutton720p60.setChecked(false);
rbutton1080p30.setChecked(false); rbutton1080p30.setChecked(false);
@@ -124,22 +135,30 @@ public class Connection extends Activity {
if (buttonView == rbutton720p30) { if (buttonView == rbutton720p30) {
prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1280). prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1280).
putInt(Game.HEIGHT_PREF_STRING, 720). putInt(Game.HEIGHT_PREF_STRING, 720).
putInt(Game.REFRESH_RATE_PREF_STRING, 30).commit(); putInt(Game.REFRESH_RATE_PREF_STRING, 30).
putInt(Game.BITRATE_PREF_STRING, Game.BITRATE_DEFAULT_720_30).commit();
bitrateSlider.setProgress(Game.BITRATE_DEFAULT_720_30);
} }
else if (buttonView == rbutton720p60) { else if (buttonView == rbutton720p60) {
prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1280). prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1280).
putInt(Game.HEIGHT_PREF_STRING, 720). putInt(Game.HEIGHT_PREF_STRING, 720).
putInt(Game.REFRESH_RATE_PREF_STRING, 60).commit(); putInt(Game.REFRESH_RATE_PREF_STRING, 60).
putInt(Game.BITRATE_PREF_STRING, Game.BITRATE_DEFAULT_720_60).commit();
bitrateSlider.setProgress(Game.BITRATE_DEFAULT_720_60);
} }
else if (buttonView == rbutton1080p30) { else if (buttonView == rbutton1080p30) {
prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1920). prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1920).
putInt(Game.HEIGHT_PREF_STRING, 1080). putInt(Game.HEIGHT_PREF_STRING, 1080).
putInt(Game.REFRESH_RATE_PREF_STRING, 30).commit(); putInt(Game.REFRESH_RATE_PREF_STRING, 30).
putInt(Game.BITRATE_PREF_STRING, Game.BITRATE_DEFAULT_1080_30).commit();
bitrateSlider.setProgress(Game.BITRATE_DEFAULT_1080_30);
} }
else if (buttonView == rbutton1080p60) { else if (buttonView == rbutton1080p60) {
prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1920). prefs.edit().putInt(Game.WIDTH_PREF_STRING, 1920).
putInt(Game.HEIGHT_PREF_STRING, 1080). putInt(Game.HEIGHT_PREF_STRING, 1080).
putInt(Game.REFRESH_RATE_PREF_STRING, 60).commit(); putInt(Game.REFRESH_RATE_PREF_STRING, 60).
putInt(Game.BITRATE_PREF_STRING, Game.BITRATE_DEFAULT_1080_60).commit();
bitrateSlider.setProgress(Game.BITRATE_DEFAULT_1080_60);
} }
else if (buttonView == forceSoftDec) { else if (buttonView == forceSoftDec) {
prefs.edit().putInt(Game.DECODER_PREF_STRING, Game.FORCE_SOFTWARE_DECODER).commit(); prefs.edit().putInt(Game.DECODER_PREF_STRING, Game.FORCE_SOFTWARE_DECODER).commit();
@@ -160,6 +179,45 @@ public class Connection extends Activity {
forceHardDec.setOnCheckedChangeListener(occl); forceHardDec.setOnCheckedChangeListener(occl);
autoDec.setOnCheckedChangeListener(occl); autoDec.setOnCheckedChangeListener(occl);
this.bitrateSlider.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// Verify the user's selection
if (fromUser) {
int floor;
if (rbutton720p30.isChecked()) {
floor = Game.BITRATE_FLOOR_720_30;
}
else if (rbutton720p60.isChecked()){
floor = Game.BITRATE_FLOOR_720_60;
}
else if (rbutton1080p30.isChecked()){
floor = Game.BITRATE_FLOOR_1080_30;
}
else /*if (rbutton1080p60.isChecked())*/ {
floor = Game.BITRATE_FLOOR_1080_60;
}
if (progress < floor) {
seekBar.setProgress(floor);
return;
}
}
updateBitrateLabel();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
this.statusButton.setOnClickListener(new OnClickListener() { this.statusButton.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View arg0) { public void onClick(View arg0) {
@@ -168,6 +226,12 @@ public class Connection extends Activity {
return; return;
} }
// Ensure that the bitrate preference is up to date before
// starting the game activity
prefs.edit().
putInt(Game.BITRATE_PREF_STRING, bitrateSlider.getProgress()).
commit();
Intent intent = new Intent(Connection.this, Game.class); Intent intent = new Intent(Connection.this, Game.class);
intent.putExtra("host", Connection.this.hostText.getText().toString()); intent.putExtra("host", Connection.this.hostText.getText().toString());
Connection.this.startActivity(intent); Connection.this.startActivity(intent);
@@ -240,4 +304,7 @@ public class Connection extends Activity {
} }
private void updateBitrateLabel() {
bitrateLabel.setText("Max Bitrate: "+bitrateSlider.getProgress()+" Mbps");
}
} }
+51 -10
View File
@@ -20,6 +20,7 @@ import android.graphics.Point;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.view.Display; import android.view.Display;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -63,11 +64,25 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
public static final String HEIGHT_PREF_STRING = "ResV"; public static final String HEIGHT_PREF_STRING = "ResV";
public static final String REFRESH_RATE_PREF_STRING = "FPS"; public static final String REFRESH_RATE_PREF_STRING = "FPS";
public static final String DECODER_PREF_STRING = "Decoder"; public static final String DECODER_PREF_STRING = "Decoder";
public static final String BITRATE_PREF_STRING = "Bitrate";
public static final int BITRATE_FLOOR_720_30 = 2;
public static final int BITRATE_FLOOR_720_60 = 4;
public static final int BITRATE_FLOOR_1080_30 = 4;
public static final int BITRATE_FLOOR_1080_60 = 10;
public static final int BITRATE_DEFAULT_720_30 = 5;
public static final int BITRATE_DEFAULT_720_60 = 10;
public static final int BITRATE_DEFAULT_1080_30 = 10;
public static final int BITRATE_DEFAULT_1080_60 = 30;
public static final int BITRATE_CEILING = 50;
public static final int DEFAULT_WIDTH = 1280; public static final int DEFAULT_WIDTH = 1280;
public static final int DEFAULT_HEIGHT = 720; public static final int DEFAULT_HEIGHT = 720;
public static final int DEFAULT_REFRESH_RATE = 60; public static final int DEFAULT_REFRESH_RATE = 60;
public static final int DEFAULT_DECODER = 0; public static final int DEFAULT_DECODER = 0;
public static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60;
public static final int FORCE_HARDWARE_DECODER = -1; public static final int FORCE_HARDWARE_DECODER = -1;
public static final int AUTOSELECT_DECODER = 0; public static final int AUTOSELECT_DECODER = 0;
@@ -77,15 +92,24 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// We don't want a title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Full-screen and don't let the display go off // Full-screen and don't let the display go off
getWindow().setFlags( getWindow().addFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// We don't want a title bar // If we're going to use immersive mode, we want to have
requestWindowFeature(Window.FEATURE_NO_TITLE); // the entire screen
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
}
// Change volume button behavior // Change volume button behavior
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
@@ -116,10 +140,11 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
break; break;
} }
int refreshRate; int refreshRate, bitrate;
width = prefs.getInt(WIDTH_PREF_STRING, DEFAULT_WIDTH); width = prefs.getInt(WIDTH_PREF_STRING, DEFAULT_WIDTH);
height = prefs.getInt(HEIGHT_PREF_STRING, DEFAULT_HEIGHT); height = prefs.getInt(HEIGHT_PREF_STRING, DEFAULT_HEIGHT);
refreshRate = prefs.getInt(REFRESH_RATE_PREF_STRING, DEFAULT_REFRESH_RATE); refreshRate = prefs.getInt(REFRESH_RATE_PREF_STRING, DEFAULT_REFRESH_RATE);
bitrate = prefs.getInt(BITRATE_PREF_STRING, DEFAULT_BITRATE);
sh.setFixedSize(width, height); sh.setFixedSize(width, height);
Display display = getWindowManager().getDefaultDisplay(); Display display = getWindowManager().getDefaultDisplay();
@@ -130,7 +155,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
// Start the connection // Start the connection
conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this, conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this,
new StreamConfiguration(width, height, refreshRate)); new StreamConfiguration(width, height, refreshRate, bitrate * 1000));
keybTranslator = new KeyboardTranslator(conn); keybTranslator = new KeyboardTranslator(conn);
controllerHandler = new ControllerHandler(conn); controllerHandler = new ControllerHandler(conn);
@@ -147,8 +172,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
private void hideSystemUi() { private Runnable hideSystemUi = new Runnable() {
runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
// Use immersive mode on 4.4+ or standard low profile on previous builds // Use immersive mode on 4.4+ or standard low profile on previous builds
@@ -167,7 +191,14 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
View.SYSTEM_UI_FLAG_LOW_PROFILE); View.SYSTEM_UI_FLAG_LOW_PROFILE);
} }
} }
}); };
private void hideSystemUi() {
Handler h = getWindow().getDecorView().getHandler();
if (h != null) {
h.removeCallbacks(hideSystemUi);
h.postDelayed(hideSystemUi, 1000);
}
} }
@Override @Override
@@ -220,6 +251,16 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
// Pressing a volume button drops the immersive flag so the UI shows up again and doesn't
// go away. I'm not sure if that's a bug or a feature, but we're working around it here
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
Handler h = getWindow().getDecorView().getHandler();
if (h != null) {
h.removeCallbacks(hideSystemUi);
h.postDelayed(hideSystemUi, 2000);
}
}
if (event.getDevice() != null && if (event.getDevice() != null &&
(event.getDevice().getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC)) { (event.getDevice().getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC)) {
short translated = keybTranslator.translate(event.getKeyCode()); short translated = keybTranslator.translate(event.getKeyCode());
+5 -2
View File
@@ -25,8 +25,11 @@ public class Dialog implements Runnable {
public static void closeDialogs() public static void closeDialogs()
{ {
for (Dialog d : rundownDialogs) for (Dialog d : rundownDialogs) {
d.alert.dismiss(); if (d.alert.isShowing()) {
d.alert.dismiss();
}
}
rundownDialogs.clear(); rundownDialogs.clear();
} }
+8 -3
View File
@@ -33,8 +33,11 @@ public class SpinnerDialog implements Runnable,OnCancelListener {
public static void closeDialogs() public static void closeDialogs()
{ {
for (SpinnerDialog d : rundownDialogs) for (SpinnerDialog d : rundownDialogs) {
d.progress.dismiss(); if (d.progress.isShowing()) {
d.progress.dismiss();
}
}
rundownDialogs.clear(); rundownDialogs.clear();
} }
@@ -86,7 +89,9 @@ public class SpinnerDialog implements Runnable,OnCancelListener {
} }
else else
{ {
progress.dismiss(); if (progress.isShowing()) {
progress.dismiss();
}
} }
} }