From e2663f06bace3b503ba837d24b01db285afbb86f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 13 Jul 2014 21:44:19 -0700 Subject: [PATCH 1/7] Bump version to 2.5.0.5 --- AndroidManifest.xml | 4 ++-- libs/limelight-common.jar | Bin 410672 -> 410672 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eed7b299..c6c451b1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@  + android:versionCode="25" + android:versionName="2.5.0.5" > +J({U5-SU8?sLEus*-S@A3c1oZe3ssU0vq+6FzbL`>>*BCTMyN&*Z&Ms>_+f9 z0_{dH$f_cT7cOJ5^unbpv48$T3oa;TOH+T(Gc47Vm6y3LC(XNH34PrSz#R8&sL~T_ zj+~^mV{JB;-SMUc*{MOvvSV#q2v&NveIJ@=!#%{wI`*XS#)doZm-e}?k0g^z2a(b8 z)TK?PZ)f*D^|=hH6B8LbTXnEODpI$cT3KHW?e>9G6cndIRKJ zY=K)s#D^=xLkVIB9G*Z){(KYpX5P*DY7!j$+$ORW6WIw+vu$E2hN_+t7=-VK;(1Jj9w1pClbybksw=v@b`2);8wFszuf2KXzi0=7of z)IW}>q${H;;Hjv}{%2HG*c^jqj64)m?&Xc}FftvDs-7#2O1wG_kD=+=xXS)hTuov_ qLWwUV;BnNL*TXIZdkyf_dZlqERh&#x)l)E-O(|JCA407zndlyVB9Mtb3F;EXX1TnD~OdK*oj}Za_9ig5Z3X z5J%=8yz0=J5H_b0H?QP38YJj^#F$M?l$emMGw~7V4CsuDiNSNv|968XfAXF0yw5$S zBaz&ZNN)P(`*>20#b&cv3SN(oroZLke>TMBh^N=8fH>F593sC6a%GqIAW`zV?C!;7sQMcQsmetrv)-#dIO0nZN@#N?n;PDJ+G%x;{rqyIBTLQGW2 zeOh~x5@byLlxWy5vb+G=+&~4}CQDDg#CfMTD955*$*e|}pFYNNHy!L*`gy9w^5YVV zW#Kthn90ElNqjH%JlpEj8Z{8dO5rwn`Q0m4VzEyV@v3o*aFbDNy3%;pd7~+1wDXr~qZ%x*Sa<@EFZ+M{(C|~c zDm$-?(*nuxjRRzPR%ic`Uab^nOBU`5$keZK)^E_bQwjPG{Yzk-)QKKQWBbTJ$5bC! zvvDfbmYaSKEgZ~Kj{5N|7G10w(s2ik{nIe0{zd_F89iLvgww36f+c!d5nFCV#lEJD z0%F3Um#<>)QC>Avw>T0+TX!k@o?6hkpLuNjk>0rO53)2+NFWO7&sDSUl1NnR|4In# z`pFu$1^A_><2q(d<-7*H{;OqW#@JLPdec_+Yc{ Date: Tue, 15 Jul 2014 20:46:12 -0700 Subject: [PATCH 2/7] Fix dialog rundown issues causing spurious crashes --- src/com/limelight/utils/Dialog.java | 31 +++++++++++++--------- src/com/limelight/utils/SpinnerDialog.java | 27 +++++++++++++------ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/com/limelight/utils/Dialog.java b/src/com/limelight/utils/Dialog.java index c4bb6e6b..d95dcfb3 100644 --- a/src/com/limelight/utils/Dialog.java +++ b/src/com/limelight/utils/Dialog.java @@ -11,7 +11,7 @@ public class Dialog implements Runnable { private Activity activity; private boolean endAfterDismiss; - AlertDialog alert; + private AlertDialog alert; private static ArrayList rundownDialogs = new ArrayList(); @@ -25,13 +25,15 @@ public class Dialog implements Runnable { public static void closeDialogs() { - for (Dialog d : rundownDialogs) { - if (d.alert.isShowing()) { - d.alert.dismiss(); + synchronized (rundownDialogs) { + for (Dialog d : rundownDialogs) { + if (d.alert.isShowing()) { + d.alert.dismiss(); + } } + + rundownDialogs.clear(); } - - rundownDialogs.clear(); } public static void displayDialog(Activity activity, String title, String message, boolean endAfterDismiss) @@ -54,16 +56,21 @@ public class Dialog implements Runnable { alert.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - alert.dismiss(); - rundownDialogs.remove(this); + synchronized (rundownDialogs) { + rundownDialogs.remove(this); + alert.dismiss(); + } - if (endAfterDismiss) + if (endAfterDismiss) { activity.finish(); + } } - }); + }); - rundownDialogs.add(this); - alert.show(); + synchronized (rundownDialogs) { + rundownDialogs.add(this); + alert.show(); + } } } diff --git a/src/com/limelight/utils/SpinnerDialog.java b/src/com/limelight/utils/SpinnerDialog.java index a5ec6991..29a35bb2 100644 --- a/src/com/limelight/utils/SpinnerDialog.java +++ b/src/com/limelight/utils/SpinnerDialog.java @@ -33,13 +33,15 @@ public class SpinnerDialog implements Runnable,OnCancelListener { public static void closeDialogs() { - for (SpinnerDialog d : rundownDialogs) { - if (d.progress.isShowing()) { - d.progress.dismiss(); + synchronized (rundownDialogs) { + for (SpinnerDialog d : rundownDialogs) { + if (d.progress.isShowing()) { + d.progress.dismiss(); + } } + + rundownDialogs.clear(); } - - rundownDialogs.clear(); } public void dismiss() @@ -85,18 +87,27 @@ public class SpinnerDialog implements Runnable,OnCancelListener { progress.setCancelable(false); } - progress.show(); + synchronized (rundownDialogs) { + rundownDialogs.add(this); + progress.show(); + } } else { - if (progress.isShowing()) { - progress.dismiss(); + synchronized (rundownDialogs) { + if (rundownDialogs.remove(this) && progress.isShowing()) { + progress.dismiss(); + } } } } @Override public void onCancel(DialogInterface dialog) { + synchronized (rundownDialogs) { + rundownDialogs.remove(this); + } + // This will only be called if finish was true, so we don't need to check again activity.finish(); } From 92143df65caa5a7048f97af47e9631d2b172f2b5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 19 Jul 2014 03:35:17 -0700 Subject: [PATCH 3/7] Don't destroy dialogs until we're really finishing --- src/com/limelight/AppView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/limelight/AppView.java b/src/com/limelight/AppView.java index 622b2cbe..bce04f30 100644 --- a/src/com/limelight/AppView.java +++ b/src/com/limelight/AppView.java @@ -94,8 +94,8 @@ public class AppView extends Activity { } @Override - protected void onStop() { - super.onStop(); + protected void onDestroy() { + super.onDestroy(); Dialog.closeDialogs(); SpinnerDialog.closeDialogs(); From f5ec665115389e834b1d62d961f8929a8b9d0608 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 19 Jul 2014 03:49:44 -0700 Subject: [PATCH 4/7] Park for a bit if there's nothing to do --- .../limelight/binding/video/AndroidCpuDecoderRenderer.java | 2 ++ .../limelight/binding/video/MediaCodecDecoderRenderer.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java index 611c3555..7521ad0c 100644 --- a/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java +++ b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.concurrent.locks.LockSupport; import android.graphics.PixelFormat; import android.os.Build; @@ -169,6 +170,7 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer { long diff = nextFrameTime - System.currentTimeMillis(); if (diff > WAIT_CEILING_MS) { + LockSupport.parkNanos(1); continue; } diff --git a/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java index d91c5509..8a180362 100644 --- a/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -3,6 +3,7 @@ package com.limelight.binding.video; import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.locks.LockSupport; import com.limelight.LimeLog; import com.limelight.nvstream.av.ByteBufferDescriptor; @@ -203,6 +204,9 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { } } else { switch (outIndex) { + case MediaCodec.INFO_TRY_AGAIN_LATER: + LockSupport.parkNanos(1); + break; case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: LimeLog.info("Output buffers changed"); break; From 428d37afd440bab45cc689925142f9a42183e5e1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 19 Jul 2014 03:50:37 -0700 Subject: [PATCH 5/7] Improve input device detection --- src/com/limelight/Game.java | 54 ++++++++++++------ .../binding/input/ControllerHandler.java | 57 ++++++++++++++++++- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java index 5c7e7cf4..10b00d96 100644 --- a/src/com/limelight/Game.java +++ b/src/com/limelight/Game.java @@ -270,10 +270,27 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM return modifier; } + private static boolean isSourceFlagSet(int sourcesFlags, int flag) { + return (sourcesFlags & flag) == flag; + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.getDevice() != null && - (event.getDevice().getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC)) { + InputDevice dev = event.getDevice(); + if (dev == null) { + return super.onKeyDown(keyCode, event); + } + + int source = dev.getSources(); + boolean handled = false; + if (isSourceFlagSet(source, InputDevice.SOURCE_DPAD) || + isSourceFlagSet(source, InputDevice.SOURCE_GAMEPAD) || + isSourceFlagSet(source, InputDevice.SOURCE_JOYSTICK)) + { + handled = controllerHandler.handleButtonDown(keyCode, event); + } + + if (!handled) { short translated = keybTranslator.translate(event.getKeyCode()); if (translated == 0) { return super.onKeyDown(keyCode, event); @@ -282,12 +299,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM keybTranslator.sendKeyDown(translated, getModifierState(event)); } - else { - if (!controllerHandler.handleButtonDown(keyCode, event)) { - return super.onKeyDown(keyCode, event); - } - } - + return true; } @@ -302,22 +314,30 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM h.postDelayed(hideSystemUi, 2000); } } - - if (event.getDevice() != null && - (event.getDevice().getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC)) { + + InputDevice dev = event.getDevice(); + if (dev == null) { + return super.onKeyUp(keyCode, event); + } + + int source = dev.getSources(); + boolean handled = false; + if (isSourceFlagSet(source, InputDevice.SOURCE_DPAD) || + isSourceFlagSet(source, InputDevice.SOURCE_GAMEPAD) || + isSourceFlagSet(source, InputDevice.SOURCE_JOYSTICK)) + { + handled = controllerHandler.handleButtonUp(keyCode, event); + } + + if (!handled) { short translated = keybTranslator.translate(event.getKeyCode()); if (translated == 0) { return super.onKeyUp(keyCode, event); } - + keybTranslator.sendKeyUp(translated, getModifierState(event)); } - else { - if (!controllerHandler.handleButtonUp(keyCode, event)) { - return super.onKeyUp(keyCode, event); - } - } return true; } diff --git a/src/com/limelight/binding/input/ControllerHandler.java b/src/com/limelight/binding/input/ControllerHandler.java index 789fe7be..3a85af60 100644 --- a/src/com/limelight/binding/input/ControllerHandler.java +++ b/src/com/limelight/binding/input/ControllerHandler.java @@ -148,6 +148,10 @@ public class ControllerHandler { } } + mapping.isDpad = (dev.getSources() & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD; + mapping.isGamepad = (dev.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD || + (dev.getSources() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK; + return mapping; } @@ -177,7 +181,48 @@ public class ControllerHandler { leftStickX, leftStickY, rightStickX, rightStickY); } - private int handleRemapping(ControllerMapping mapping, int keyCode) { + private static boolean isEventExpected(ControllerMapping mapping, int keyCode) { + if (mapping.isDpad) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + return true; + } + } + + if (mapping.isGamepad) { + switch (keyCode) { + case KeyEvent.KEYCODE_BUTTON_MODE: + case KeyEvent.KEYCODE_BUTTON_START: + case KeyEvent.KEYCODE_MENU: + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_BUTTON_SELECT: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_BUTTON_B: + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_BUTTON_A: + case KeyEvent.KEYCODE_BUTTON_X: + case KeyEvent.KEYCODE_BUTTON_Y: + case KeyEvent.KEYCODE_BUTTON_L1: + case KeyEvent.KEYCODE_BUTTON_R1: + case KeyEvent.KEYCODE_BUTTON_THUMBL: + case KeyEvent.KEYCODE_BUTTON_THUMBR: + case KeyEvent.KEYCODE_BUTTON_L2: + case KeyEvent.KEYCODE_BUTTON_R2: + return true; + } + } + + return false; + } + + private static int handleRemapping(ControllerMapping mapping, int keyCode) { if (mapping.isDualShock4) { switch (keyCode) { case KeyEvent.KEYCODE_BUTTON_Y: @@ -317,6 +362,10 @@ public class ControllerHandler { return true; } + if (!isEventExpected(mapping, keyCode)) { + return false; + } + // If the button hasn't been down long enough, sleep for a bit before sending the up event // This allows "instant" button presses (like OUYA's virtual menu button) to work. This // path should not be triggered during normal usage. @@ -440,6 +489,10 @@ public class ControllerHandler { return true; } + if (!isEventExpected(mapping, keyCode)) { + return false; + } + switch (keyCode) { case KeyEvent.KEYCODE_BUTTON_MODE: inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG; @@ -549,5 +602,7 @@ public class ControllerHandler { public float hatYDeadzone; public boolean isDualShock4; + public boolean isDpad; + public boolean isGamepad; } } From b9f01b63cc0ab4ada13614e6c726a89eeed82d5a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 19 Jul 2014 22:15:23 -0700 Subject: [PATCH 6/7] Add an option to stretch the video to fill the screen and make preserve aspect ratio the default --- gen/com/limelight/R.java | 5 ++- libs/limelight-common.jar | Bin 410672 -> 410609 bytes res/layout/activity_game.xml | 5 ++- res/layout/activity_stream_settings.xml | 10 ++++- src/com/limelight/Game.java | 54 ++++++++++++++++++++---- src/com/limelight/StreamSettings.java | 12 ++++++ 6 files changed, 72 insertions(+), 14 deletions(-) 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 11380301abc953056ed11ae4c10ffea9f792426f..3eef702c133846d3757d55f194e392c058e8b4d9 100644 GIT binary patch delta 23869 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 delta 23942 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 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(); + } + }); } } From 48ab233d0fd7666278ac23fce80e0b8d2a5d099c Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 19 Jul 2014 22:50:14 -0700 Subject: [PATCH 7/7] Update common and bump version --- AndroidManifest.xml | 4 ++-- libs/limelight-common.jar | Bin 410609 -> 410676 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c6c451b1..5099010a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@  + android:versionCode="26" + android:versionName="2.5.1" > %V(5j)xS_!)R(qO~Xz_M@L7+N3LT0 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 VX5s+_NFO+W2lxRFNq~xq>OUUR$vFT3 delta 4218 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