diff --git a/gen/com/limelight/R.java b/gen/com/limelight/R.java index 1baa8d20..889f9c8d 100644 --- a/gen/com/limelight/R.java +++ b/gen/com/limelight/R.java @@ -52,12 +52,13 @@ or to a theme attribute in the form "?[package:][type:]na public static final int discoveryText=0x7f08000b; public static final int hardwareDec=0x7f080005; public static final int hostTextView=0x7f080000; - public static final int manuallyAddPc=0x7f080013; + public static final int manuallyAddPc=0x7f080014; public static final int pcListView=0x7f080008; - public static final int rowTextView=0x7f080014; + public static final int rowTextView=0x7f080015; public static final int settingsButton=0x7f08000c; public static final int softwareDec=0x7f080003; public static final int streamConfigGroup=0x7f08000d; + public static final int stretchToFill=0x7f080013; public static final int surfaceView=0x7f08000a; } public static final class layout { diff --git a/libs/limelight-common.jar b/libs/limelight-common.jar index 11380301..3eef702c 100644 Binary files a/libs/limelight-common.jar and b/libs/limelight-common.jar differ diff --git a/res/layout/activity_game.xml b/res/layout/activity_game.xml index 396013e8..c64a8ab3 100644 --- a/res/layout/activity_game.xml +++ b/res/layout/activity_game.xml @@ -2,12 +2,13 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#0099cc" + android:background="#000" tools:context=".Game" > + android:layout_height="match_parent" + android:layout_gravity="center" /> diff --git a/res/layout/activity_stream_settings.xml b/res/layout/activity_stream_settings.xml index 8847b66a..0f69e4f9 100644 --- a/res/layout/activity_stream_settings.xml +++ b/res/layout/activity_stream_settings.xml @@ -54,7 +54,7 @@ android:id="@+id/advancedSettingsButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/streamConfigGroup" + android:layout_below="@+id/stretchToFill" android:layout_centerHorizontal="true" android:layout_marginTop="15dp" android:text="Advanced Settings" /> @@ -67,6 +67,14 @@ android:layout_centerHorizontal="true" android:text="Add PC Manually" /> + + diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java index 10b00d96..1fc7c9b1 100644 --- a/src/com/limelight/Game.java +++ b/src/com/limelight/Game.java @@ -32,6 +32,7 @@ import android.view.SurfaceView; import android.view.View; import android.view.View.OnGenericMotionListener; import android.view.View.OnTouchListener; +import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.Toast; @@ -58,6 +59,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM private boolean connecting = false; private boolean connected = false; + private boolean stretchToFit; + private ConfigurableDecoderRenderer decoderRenderer; private WifiManager.WifiLock wifiLock; @@ -76,6 +79,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM public static final String REFRESH_RATE_PREF_STRING = "FPS"; public static final String DECODER_PREF_STRING = "Decoder"; public static final String BITRATE_PREF_STRING = "Bitrate"; + public static final String STRETCH_PREF_STRING = "Stretch"; public static final int BITRATE_DEFAULT_720_30 = 5; public static final int BITRATE_DEFAULT_720_60 = 10; @@ -87,6 +91,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM public static final int DEFAULT_REFRESH_RATE = 60; public static final int DEFAULT_DECODER = 0; public static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60; + public static final boolean DEFAULT_STRETCH = false; public static final int FORCE_HARDWARE_DECODER = -1; public static final int AUTOSELECT_DECODER = 0; @@ -121,13 +126,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM // Inflate the content setContentView(R.layout.activity_game); - // Listen for events on the game surface - SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView); - sv.setOnGenericMotionListener(this); - sv.setOnTouchListener(this); - - SurfaceHolder sh = sv.getHolder(); - // Start the spinner spinner = SpinnerDialog.displayDialog(this, "Establishing Connection", "Starting connection", true); @@ -143,16 +141,32 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM drFlags |= VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING; break; } + + stretchToFit = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH); + if (stretchToFit) { + drFlags |= VideoDecoderRenderer.FLAG_FILL_SCREEN; + } int refreshRate, bitrate; width = prefs.getInt(WIDTH_PREF_STRING, DEFAULT_WIDTH); height = prefs.getInt(HEIGHT_PREF_STRING, DEFAULT_HEIGHT); refreshRate = prefs.getInt(REFRESH_RATE_PREF_STRING, DEFAULT_REFRESH_RATE); bitrate = prefs.getInt(BITRATE_PREF_STRING, DEFAULT_BITRATE); - sh.setFixedSize(width, height); Display display = getWindowManager().getDefaultDisplay(); display.getSize(screenSize); + + // Listen for events on the game surface + SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView); + sv.setOnGenericMotionListener(this); + sv.setOnTouchListener(this); + + SurfaceHolder sh = sv.getHolder(); + + if (stretchToFit) { + // Set the surface to the size of the video + sh.setFixedSize(width, height); + } // Warn the user if they're on a metered connection checkDataConnection(); @@ -181,6 +195,21 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM sh.addCallback(this); } + private void resizeSurfaceWithAspectRatio(SurfaceView sv, double vidWidth, double vidHeight) + { + // Get the visible width of the activity + double visibleWidth = getWindow().getDecorView().getWidth(); + + ViewGroup.LayoutParams lp = sv.getLayoutParams(); + + // Calculate the new size of the SurfaceView + lp.width = (int) visibleWidth; + lp.height = (int) ((vidHeight / vidWidth) * visibleWidth); + + // Apply the size change + sv.setLayoutParams(lp); + } + private void checkDataConnection() { ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); @@ -233,7 +262,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM int averageDecoderLat = decoderRenderer.getAverageDecoderLatency(); String message = null; if (averageEndToEndLat > 0) { - message = "Average total frame latency: "+averageEndToEndLat+" ms"; + message = "Average client-side frame latency: "+averageEndToEndLat+" ms"; if (averageDecoderLat > 0) { message += " (hardware decoder latency: "+averageDecoderLat+" ms)"; } @@ -582,6 +611,13 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM public void surfaceCreated(SurfaceHolder holder) { if (!connected && !connecting) { connecting = true; + + // Resize the surface to match the aspect ratio of the video + // This must be done after the surface is created. + if (!stretchToFit) { + resizeSurfaceWithAspectRatio((SurfaceView) findViewById(R.id.surfaceView), width, height); + } + conn.start(PlatformBinding.getDeviceName(), holder, drFlags, PlatformBinding.getAudioRenderer(), decoderRenderer); } diff --git a/src/com/limelight/StreamSettings.java b/src/com/limelight/StreamSettings.java index 4ff25255..fb31b6b0 100644 --- a/src/com/limelight/StreamSettings.java +++ b/src/com/limelight/StreamSettings.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; +import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.RadioButton; @@ -18,6 +19,7 @@ public class StreamSettings extends Activity { private Button advancedSettingsButton, addComputerButton; private SharedPreferences prefs; private RadioButton rbutton720p30, rbutton720p60, rbutton1080p30, rbutton1080p60; + private CheckBox stretchToFill; @Override protected void onStop() { @@ -32,6 +34,7 @@ public class StreamSettings extends Activity { setContentView(R.layout.activity_stream_settings); + this.stretchToFill = (CheckBox) findViewById(R.id.stretchToFill); this.advancedSettingsButton = (Button) findViewById(R.id.advancedSettingsButton); this.addComputerButton = (Button) findViewById(R.id.manuallyAddPc); this.rbutton720p30 = (RadioButton) findViewById(R.id.config720p30Selected); @@ -44,6 +47,8 @@ public class StreamSettings extends Activity { 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; + stretchToFill.setChecked(prefs.getBoolean(Game.STRETCH_PREF_STRING, Game.DEFAULT_STRETCH)); + rbutton720p30.setChecked(false); rbutton720p60.setChecked(false); rbutton1080p30.setChecked(false); @@ -119,5 +124,12 @@ public class StreamSettings extends Activity { startActivity(i); } }); + stretchToFill.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + prefs.edit().putBoolean(Game.STRETCH_PREF_STRING, isChecked).commit(); + } + }); } }