mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-21 07:46:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51a630995a | ||
|
|
3a74f0726c | ||
|
|
efa6c7bba0 | ||
|
|
b8141542f8 | ||
|
|
8fc9a90207 | ||
|
|
13d707d98d | ||
|
|
aae0ff6e7a | ||
|
|
69c7b5a0d5 | ||
|
|
d1ad3115fa | ||
|
|
770af402a4 | ||
|
|
3236c0b93a | ||
|
|
51aacc3f38 | ||
|
|
397c6f46f9 | ||
|
|
d00f78f859 | ||
|
|
29fec2e0de | ||
|
|
88d28665ef | ||
|
|
de1f4da258 | ||
|
|
7985be57ab | ||
|
|
a835e7aaa2 | ||
|
|
c4dc5eb9e1 | ||
|
|
db758f386e | ||
|
|
3fb3eefa94 | ||
|
|
2d6c756e70 | ||
|
|
03e965d449 | ||
|
|
4cea483a87 |
No files matched your search
@@ -8,6 +8,8 @@ whether in your own home or over the internet.
|
|||||||
|
|
||||||
[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) are also in development.
|
[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) are also in development.
|
||||||
|
|
||||||
|
Check our [wiki](https://github.com/limelight-stream/limelight-android/wiki) for more detailed information or a troubleshooting guide.
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
|
|
||||||
* Streams any of your games from your PC to your Android device
|
* Streams any of your games from your PC to your Android device
|
||||||
|
|||||||
+6
-4
@@ -31,6 +31,7 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/nonRoot/debug" isTestSource="false" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/nonRoot/debug" isTestSource="false" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/nonRoot/debug" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/nonRoot/debug" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/nonRoot/debug" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/res" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/res" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/resources" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/resources" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/assets" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/assets" type="java-resource" />
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/nonRoot/debug" isTestSource="true" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/nonRoot/debug" isTestSource="true" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/nonRoot/debug" type="java-test-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/nonRoot/debug" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/test/nonRoot/debug" type="java-test-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/res" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/res" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/resources" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/resources" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/assets" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/assets" type="java-resource" />
|
||||||
@@ -102,17 +104,17 @@
|
|||||||
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
|
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" exported="" name="bcprov-jdk15on-1.51" level="project" />
|
<orderEntry type="library" exported="" name="bcprov-jdk15on-1.51" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="androidasync-2.0.5" level="project" />
|
||||||
<orderEntry type="library" exported="" name="gson-2.3.1" level="project" />
|
<orderEntry type="library" exported="" name="gson-2.3.1" level="project" />
|
||||||
<orderEntry type="library" exported="" name="support-v4-r7" level="project" />
|
<orderEntry type="library" exported="" name="support-v4-r7" level="project" />
|
||||||
<orderEntry type="library" exported="" name="jmdns-fixed" level="project" />
|
<orderEntry type="library" exported="" name="jmdns-fixed" level="project" />
|
||||||
<orderEntry type="library" exported="" name="bcpkix-jdk15on-1.51" level="project" />
|
<orderEntry type="library" exported="" name="bcpkix-jdk15on-1.51" level="project" />
|
||||||
<orderEntry type="library" exported="" name="tinyrtsp" level="project" />
|
<orderEntry type="library" exported="" name="tinyrtsp" level="project" />
|
||||||
<orderEntry type="library" exported="" name="okhttp-2.1.0" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="limelight-common" level="project" />
|
<orderEntry type="library" exported="" name="limelight-common" level="project" />
|
||||||
<orderEntry type="library" exported="" name="okio-1.0.1" level="project" />
|
<orderEntry type="library" exported="" name="ion-2.0.5" level="project" />
|
||||||
<orderEntry type="library" exported="" name="androidasync-e1dfb4" level="project" />
|
<orderEntry type="library" exported="" name="okhttp-2.2.0" level="project" />
|
||||||
<orderEntry type="library" exported="" name="jcodec-0.1.9" level="project" />
|
<orderEntry type="library" exported="" name="jcodec-0.1.9" level="project" />
|
||||||
<orderEntry type="library" exported="" name="ion-2f46fa" level="project" />
|
<orderEntry type="library" exported="" name="okio-1.2.0" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
+8
-9
@@ -5,14 +5,14 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 21
|
compileSdkVersion 21
|
||||||
buildToolsVersion "21.1.1"
|
buildToolsVersion "21.1.2"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 21
|
targetSdkVersion 21
|
||||||
|
|
||||||
versionName "3.0.1"
|
versionName "3.0.3"
|
||||||
versionCode = 47
|
versionCode = 49
|
||||||
}
|
}
|
||||||
|
|
||||||
productFlavors {
|
productFlavors {
|
||||||
@@ -27,7 +27,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
runProguard false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,18 +63,17 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile group: 'org.jcodec', name: 'jcodec', version: '+'
|
compile group: 'org.jcodec', name: 'jcodec', version: '+'
|
||||||
|
|
||||||
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '+'
|
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '+'
|
||||||
compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '+'
|
compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '+'
|
||||||
compile group: 'com.google.android', name: 'support-v4', version:'+'
|
|
||||||
|
|
||||||
// FIXME: Pending resolution of issue #346 using custom build
|
compile group: 'com.google.android', name: 'support-v4', version:'+'
|
||||||
//compile group: 'com.koushikdutta.ion', name: 'ion', version:'+'
|
compile group: 'com.koushikdutta.ion', name: 'ion', version:'+'
|
||||||
compile group: 'com.google.code.gson', name: 'gson', version:'+'
|
compile group: 'com.google.code.gson', name: 'gson', version:'+'
|
||||||
compile files('libs/androidasync-e1dfb4.jar')
|
|
||||||
compile files('libs/ion-2f46fa.jar')
|
|
||||||
|
|
||||||
compile group: 'com.squareup.okhttp', name: 'okhttp', version:'+'
|
compile group: 'com.squareup.okhttp', name: 'okhttp', version:'+'
|
||||||
compile group: 'com.squareup.okio', name:'okio', version:'+'
|
compile group: 'com.squareup.okio', name:'okio', version:'+'
|
||||||
|
|
||||||
compile files('libs/jmdns-fixed.jar')
|
compile files('libs/jmdns-fixed.jar')
|
||||||
compile files('libs/limelight-common.jar')
|
compile files('libs/limelight-common.jar')
|
||||||
compile files('libs/tinyrtsp.jar')
|
compile files('libs/tinyrtsp.jar')
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -171,6 +171,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0)
|
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0)
|
||||||
.enableLocalAudioPlayback(prefConfig.playHostAudio)
|
.enableLocalAudioPlayback(prefConfig.playHostAudio)
|
||||||
.setMaxPacketSize(remote ? 1024 : 1292)
|
.setMaxPacketSize(remote ? 1024 : 1292)
|
||||||
|
.setRemote(remote)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Initialize the connection
|
// Initialize the connection
|
||||||
|
|||||||
@@ -527,6 +527,7 @@ public class PcView extends Activity {
|
|||||||
|
|
||||||
if (details.equals(computer.details)) {
|
if (details.equals(computer.details)) {
|
||||||
pcGridAdapter.removeComputer(computer);
|
pcGridAdapter.removeComputer(computer);
|
||||||
|
pcGridAdapter.notifyDataSetChanged();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ public class ControllerHandler {
|
|||||||
private static final int EMULATED_SELECT_UP_DELAY_MS = 30;
|
private static final int EMULATED_SELECT_UP_DELAY_MS = 30;
|
||||||
|
|
||||||
private Vector2d inputVector = new Vector2d();
|
private Vector2d inputVector = new Vector2d();
|
||||||
private Vector2d normalizedInputVector = new Vector2d();
|
|
||||||
|
|
||||||
private HashMap<String, ControllerMapping> mappings = new HashMap<String, ControllerMapping>();
|
private HashMap<String, ControllerMapping> mappings = new HashMap<String, ControllerMapping>();
|
||||||
|
|
||||||
@@ -236,6 +235,11 @@ public class ControllerHandler {
|
|||||||
mapping.isRemote = true;
|
mapping.isRemote = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// NYKO Playpad has a fake hat that mimics the left stick for some reason
|
||||||
|
else if (devName.contains("NYKO PLAYPAD")) {
|
||||||
|
mapping.hatXAxis = -1;
|
||||||
|
mapping.hatYAxis = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LimeLog.info("Analog stick deadzone: "+mapping.leftStickDeadzoneRadius+" "+mapping.rightStickDeadzoneRadius);
|
LimeLog.info("Analog stick deadzone: "+mapping.leftStickDeadzoneRadius+" "+mapping.rightStickDeadzoneRadius);
|
||||||
@@ -374,60 +378,40 @@ public class ControllerHandler {
|
|||||||
|
|
||||||
return keyCode;
|
return keyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2d populateCachedVector(float x, float y) {
|
||||||
|
// Reinitialize our cached Vector2d object
|
||||||
|
inputVector.initialize(x, y);
|
||||||
|
return inputVector;
|
||||||
|
}
|
||||||
|
|
||||||
private Vector2d handleDeadZone(float x, float y, float deadzoneRadius) {
|
private void handleDeadZone(Vector2d stickVector, float deadzoneRadius) {
|
||||||
// Reinitialize our cached Vector2d object
|
if (stickVector.getMagnitude() <= deadzoneRadius) {
|
||||||
inputVector.initialize(x, y);
|
// Deadzone
|
||||||
|
stickVector.initialize(0, 0);
|
||||||
if (inputVector.getMagnitude() <= deadzoneRadius) {
|
|
||||||
// Deadzone -- return the zero vector
|
|
||||||
return Vector2d.ZERO;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/*
|
|
||||||
FIXME: We're not normalizing here because we let the computer handle the deadzones.
|
|
||||||
Normalizing can make the deadzones larger than they should be after the computer also
|
|
||||||
evaluates the deadzone
|
|
||||||
|
|
||||||
// Scale the input based on the distance from the deadzone
|
// We're not normalizing here because we let the computer handle the deadzones.
|
||||||
inputVector.getNormalized(normalizedInputVector);
|
// Normalizing can make the deadzones larger than they should be after the computer also
|
||||||
normalizedInputVector.scalarMultiply((inputVector.getMagnitude() - deadzoneRadius) / (1.0f - deadzoneRadius));
|
// evaluates the deadzone.
|
||||||
|
}
|
||||||
// Bound the X value to -1.0 to 1.0
|
|
||||||
if (normalizedInputVector.getX() > 1.0f) {
|
|
||||||
normalizedInputVector.setX(1.0f);
|
|
||||||
}
|
|
||||||
else if (normalizedInputVector.getX() < -1.0f) {
|
|
||||||
normalizedInputVector.setX(-1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bound the Y value to -1.0 to 1.0
|
|
||||||
if (normalizedInputVector.getY() > 1.0f) {
|
|
||||||
normalizedInputVector.setY(1.0f);
|
|
||||||
}
|
|
||||||
else if (normalizedInputVector.getY() < -1.0f) {
|
|
||||||
normalizedInputVector.setY(-1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizedInputVector;
|
|
||||||
*/
|
|
||||||
|
|
||||||
return inputVector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleAxisSet(ControllerMapping mapping, float lsX, float lsY, float rsX,
|
private void handleAxisSet(ControllerMapping mapping, float lsX, float lsY, float rsX,
|
||||||
float rsY, float lt, float rt, float hatX, float hatY) {
|
float rsY, float lt, float rt, float hatX, float hatY) {
|
||||||
|
|
||||||
if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) {
|
if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) {
|
||||||
Vector2d leftStickVector = handleDeadZone(lsX, lsY, mapping.leftStickDeadzoneRadius);
|
Vector2d leftStickVector = populateCachedVector(lsX, lsY);
|
||||||
|
|
||||||
|
handleDeadZone(leftStickVector, mapping.leftStickDeadzoneRadius);
|
||||||
|
|
||||||
leftStickX = (short) (leftStickVector.getX() * 0x7FFE);
|
leftStickX = (short) (leftStickVector.getX() * 0x7FFE);
|
||||||
leftStickY = (short) (-leftStickVector.getY() * 0x7FFE);
|
leftStickY = (short) (-leftStickVector.getY() * 0x7FFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) {
|
if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) {
|
||||||
Vector2d rightStickVector = handleDeadZone(rsX, rsY, mapping.rightStickDeadzoneRadius);
|
Vector2d rightStickVector = populateCachedVector(rsX, rsY);
|
||||||
|
|
||||||
|
handleDeadZone(rightStickVector, mapping.rightStickDeadzoneRadius);
|
||||||
|
|
||||||
rightStickX = (short) (rightStickVector.getX() * 0x7FFE);
|
rightStickX = (short) (rightStickVector.getX() * 0x7FFE);
|
||||||
rightStickY = (short) (-rightStickVector.getY() * 0x7FFE);
|
rightStickY = (short) (-rightStickVector.getY() * 0x7FFE);
|
||||||
@@ -475,32 +459,9 @@ public class ControllerHandler {
|
|||||||
ControllerMapping mapping = getMappingForDevice(event.getDevice());
|
ControllerMapping mapping = getMappingForDevice(event.getDevice());
|
||||||
float lsX = 0, lsY = 0, rsX = 0, rsY = 0, rt = 0, lt = 0, hatX = 0, hatY = 0;
|
float lsX = 0, lsY = 0, rsX = 0, rsY = 0, rt = 0, lt = 0, hatX = 0, hatY = 0;
|
||||||
|
|
||||||
// Replay the full history before getting the current values
|
// We purposefully ignore the historical values in the motion event as it makes
|
||||||
for (int i = 0; i < event.getHistorySize(); i++) {
|
// the controller feel sluggish for some users.
|
||||||
if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) {
|
|
||||||
lsX = event.getHistoricalAxisValue(mapping.leftStickXAxis, i);
|
|
||||||
lsY = event.getHistoricalAxisValue(mapping.leftStickYAxis, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping.rightStickXAxis != -1 && mapping.rightStickYAxis != -1) {
|
|
||||||
rsX = event.getHistoricalAxisValue(mapping.rightStickXAxis, i);
|
|
||||||
rsY = event.getHistoricalAxisValue(mapping.rightStickYAxis, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping.leftTriggerAxis != -1 && mapping.rightTriggerAxis != -1) {
|
|
||||||
lt = event.getHistoricalAxisValue(mapping.leftTriggerAxis, i);
|
|
||||||
rt = event.getHistoricalAxisValue(mapping.rightTriggerAxis, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping.hatXAxis != -1 && mapping.hatYAxis != -1) {
|
|
||||||
hatX = event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, i);
|
|
||||||
hatY = event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAxisSet(mapping, lsX, lsY, rsX, rsY, lt, rt, hatX, hatY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now handle the current set of values
|
|
||||||
if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) {
|
if (mapping.leftStickXAxis != -1 && mapping.leftStickYAxis != -1) {
|
||||||
lsX = event.getAxisValue(mapping.leftStickXAxis);
|
lsX = event.getAxisValue(mapping.leftStickXAxis);
|
||||||
lsY = event.getAxisValue(mapping.leftStickYAxis);
|
lsY = event.getAxisValue(mapping.leftStickYAxis);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.limelight.binding.input.evdev;
|
package com.limelight.binding.input.evdev;
|
||||||
|
|
||||||
import java.io.IOException;
|
import android.os.Build;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -11,31 +11,33 @@ public class EvdevReader {
|
|||||||
static {
|
static {
|
||||||
System.loadLibrary("evdev_reader");
|
System.loadLibrary("evdev_reader");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void patchSeLinuxPolicies() {
|
||||||
|
//
|
||||||
|
// FIXME: We REALLY shouldn't being changing permissions on the input devices like this.
|
||||||
|
// We should probably do something clever with a separate daemon and talk via a localhost
|
||||||
|
// socket. We don't return the SELinux policies back to default after we're done which I feel
|
||||||
|
// bad about, but we do chmod the input devices back so I don't think any additional attack surface
|
||||||
|
// remains opened after streaming other than listing the /dev/input directory which you wouldn't
|
||||||
|
// normally be able to do with SELinux enforcing on Lollipop.
|
||||||
|
//
|
||||||
|
// We need to modify SELinux policies to allow us to capture input devices on Lollipop and possibly other
|
||||||
|
// more restrictive ROMs. Per Chainfire's SuperSU documentation, the supolicy binary is provided on
|
||||||
|
// 4.4 and later to do live SELinux policy changes.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
|
EvdevShell shell = EvdevShell.getInstance();
|
||||||
|
shell.runCommand("supolicy --live \"allow untrusted_app input_device dir getattr\" " +
|
||||||
|
"\"allow untrusted_app input_device chr_file { open read write ioctl }\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Requires root to chmod /dev/input/eventX
|
// Requires root to chmod /dev/input/eventX
|
||||||
public static boolean setPermissions(String[] files, int octalPermissions) {
|
public static void setPermissions(String[] files, int octalPermissions) {
|
||||||
ProcessBuilder builder = new ProcessBuilder("su");
|
EvdevShell shell = EvdevShell.getInstance();
|
||||||
|
|
||||||
try {
|
for (String file : files) {
|
||||||
Process p = builder.start();
|
shell.runCommand(String.format((Locale)null, "chmod %o %s", octalPermissions, file));
|
||||||
|
}
|
||||||
OutputStream stdin = p.getOutputStream();
|
|
||||||
for (String file : files) {
|
|
||||||
stdin.write(String.format((Locale)null, "chmod %o %s\n", octalPermissions, file).getBytes("UTF-8"));
|
|
||||||
}
|
|
||||||
stdin.write("exit\n".getBytes("UTF-8"));
|
|
||||||
stdin.flush();
|
|
||||||
|
|
||||||
p.waitFor();
|
|
||||||
p.destroy();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the fd to be passed to other function or -1 on error
|
// Returns the fd to be passed to other function or -1 on error
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.limelight.binding.input.evdev;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class EvdevShell {
|
||||||
|
private OutputStream stdin;
|
||||||
|
private InputStream stdout;
|
||||||
|
private Process shell;
|
||||||
|
private final String uuidString = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
private static final EvdevShell globalShell = new EvdevShell();
|
||||||
|
|
||||||
|
public static EvdevShell getInstance() {
|
||||||
|
return globalShell;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startShell() {
|
||||||
|
ProcessBuilder builder = new ProcessBuilder("su");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Redirect stderr to stdout
|
||||||
|
builder.redirectErrorStream(true);
|
||||||
|
shell = builder.start();
|
||||||
|
|
||||||
|
stdin = shell.getOutputStream();
|
||||||
|
stdout = shell.getInputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// This is unexpected
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
// Kill the shell if it spawned
|
||||||
|
if (stdin != null) {
|
||||||
|
try {
|
||||||
|
stdin.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
stdin = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stdout != null) {
|
||||||
|
try {
|
||||||
|
stdout.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
stdout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shell != null) {
|
||||||
|
shell.destroy();
|
||||||
|
shell = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runCommand(String command) {
|
||||||
|
if (shell == null) {
|
||||||
|
// Shell never started
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write the command followed by an echo with our UUID
|
||||||
|
stdin.write((command+'\n').getBytes("UTF-8"));
|
||||||
|
stdin.write(("echo "+uuidString+'\n').getBytes("UTF-8"));
|
||||||
|
stdin.flush();
|
||||||
|
|
||||||
|
// This is the only command in flight so we can use a scanner
|
||||||
|
// without worrying about it eating too many characters
|
||||||
|
Scanner scanner = new Scanner(stdout);
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
if (scanner.next().contains(uuidString)) {
|
||||||
|
// Our command ran
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopShell() throws InterruptedException {
|
||||||
|
boolean exitWritten = false;
|
||||||
|
|
||||||
|
if (shell == null) {
|
||||||
|
// Shell never started
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
stdin.write("exit\n".getBytes("UTF-8"));
|
||||||
|
exitWritten = true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
// We'll destroy the process without
|
||||||
|
// waiting for it to terminate since
|
||||||
|
// we don't know whether our exit command made it
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exitWritten) {
|
||||||
|
try {
|
||||||
|
shell.waitFor();
|
||||||
|
} finally {
|
||||||
|
shell.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shell.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ public class EvdevWatcher {
|
|||||||
private boolean ungrabbed = false;
|
private boolean ungrabbed = false;
|
||||||
private EvdevListener listener;
|
private EvdevListener listener;
|
||||||
private Thread startThread;
|
private Thread startThread;
|
||||||
|
|
||||||
|
private static boolean patchedSeLinuxPolicies = false;
|
||||||
|
|
||||||
private FileObserver observer = new FileObserver(PATH, FileObserver.CREATE | FileObserver.DELETE) {
|
private FileObserver observer = new FileObserver(PATH, FileObserver.CREATE | FileObserver.DELETE) {
|
||||||
@Override
|
@Override
|
||||||
@@ -117,6 +119,15 @@ public class EvdevWatcher {
|
|||||||
startThread = new Thread() {
|
startThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Initialize the root shell
|
||||||
|
EvdevShell.getInstance().startShell();
|
||||||
|
|
||||||
|
// Patch SELinux policies (if needed)
|
||||||
|
if (!patchedSeLinuxPolicies) {
|
||||||
|
EvdevReader.patchSeLinuxPolicies();
|
||||||
|
patchedSeLinuxPolicies = true;
|
||||||
|
}
|
||||||
|
|
||||||
// List all files and allow us access
|
// List all files and allow us access
|
||||||
File[] files = rundownWithPermissionsChange(0666);
|
File[] files = rundownWithPermissionsChange(0666);
|
||||||
|
|
||||||
@@ -139,7 +150,12 @@ public class EvdevWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Giveup eventX permissions
|
// Giveup eventX permissions
|
||||||
rundownWithPermissionsChange(066);
|
rundownWithPermissionsChange(0660);
|
||||||
|
|
||||||
|
// Kill the root shell
|
||||||
|
try {
|
||||||
|
EvdevShell.getInstance().stopShell();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
startThread.start();
|
startThread.start();
|
||||||
|
|||||||
@@ -410,6 +410,23 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
spsBuf.position(header.offset+5);
|
spsBuf.position(header.offset+5);
|
||||||
|
|
||||||
SeqParameterSet sps = SeqParameterSet.read(spsBuf);
|
SeqParameterSet sps = SeqParameterSet.read(spsBuf);
|
||||||
|
|
||||||
|
// Some decoders rely on H264 level to decide how many buffers are needed
|
||||||
|
// Since we only need one frame buffered, we'll set the level as low as we can
|
||||||
|
// for known resolution combinations
|
||||||
|
if (initialWidth == 1280 && initialHeight == 720) {
|
||||||
|
// Max 5 buffered frames at 1280x720x60
|
||||||
|
LimeLog.info("Patching level_idc to 32");
|
||||||
|
sps.level_idc = 32;
|
||||||
|
}
|
||||||
|
else if (initialWidth == 1920 && initialHeight == 1080) {
|
||||||
|
// Max 4 buffered frames at 1920x1080x64
|
||||||
|
LimeLog.info("Patching level_idc to 42");
|
||||||
|
sps.level_idc = 42;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Leave the profile alone (currently 5.0)
|
||||||
|
}
|
||||||
|
|
||||||
// TI OMAP4 requires a reference frame count of 1 to decode successfully. Exynos 4
|
// TI OMAP4 requires a reference frame count of 1 to decode successfully. Exynos 4
|
||||||
// also requires this fixup.
|
// also requires this fixup.
|
||||||
|
|||||||
@@ -355,6 +355,12 @@ public class ComputerManagerService extends Service {
|
|||||||
|
|
||||||
private boolean pollComputer(ComputerDetails details, boolean localFirst) {
|
private boolean pollComputer(ComputerDetails details, boolean localFirst) {
|
||||||
ComputerDetails polledDetails;
|
ComputerDetails polledDetails;
|
||||||
|
|
||||||
|
// If the local address is routable across the Internet,
|
||||||
|
// always consider this PC remote to be conservative
|
||||||
|
if (details.localIp.equals(details.remoteIp)) {
|
||||||
|
localFirst = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (localFirst) {
|
if (localFirst) {
|
||||||
polledDetails = tryPollIp(details, details.localIp);
|
polledDetails = tryPollIp(details, details.localIp);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class PreferenceConfiguration {
|
|||||||
private static final int BITRATE_DEFAULT_720_30 = 5;
|
private static final int BITRATE_DEFAULT_720_30 = 5;
|
||||||
private static final int BITRATE_DEFAULT_720_60 = 10;
|
private static final int BITRATE_DEFAULT_720_60 = 10;
|
||||||
private static final int BITRATE_DEFAULT_1080_30 = 10;
|
private static final int BITRATE_DEFAULT_1080_30 = 10;
|
||||||
private static final int BITRATE_DEFAULT_1080_60 = 30;
|
private static final int BITRATE_DEFAULT_1080_60 = 20;
|
||||||
|
|
||||||
private static final String DEFAULT_RES_FPS = "720p60";
|
private static final String DEFAULT_RES_FPS = "720p60";
|
||||||
private static final String DEFAULT_DECODER = "auto";
|
private static final String DEFAULT_DECODER = "auto";
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
<string name="summary_seekbar_bitrate">Abbassa il bitrate per ridurre lo stuttering; alza il bitrate per aumenteare la qualità dell\'immagine</string>
|
<string name="summary_seekbar_bitrate">Abbassa il bitrate per ridurre lo stuttering; alza il bitrate per aumenteare la qualità dell\'immagine</string>
|
||||||
<string name="suffix_seekbar_bitrate">Mbps</string>
|
<string name="suffix_seekbar_bitrate">Mbps</string>
|
||||||
<string name="title_checkbox_stretch_video">Forza video in full-screen</string>
|
<string name="title_checkbox_stretch_video">Forza video in full-screen</string>
|
||||||
<string name="title_checkbox_disable_warnings">Disabilita i messaggi di warning</string>
|
<string name="title_checkbox_disable_warnings">Disabilita messaggi di warning</string>
|
||||||
<string name="summary_checkbox_disable_warnings">Disabilita i messaggi di warning sullo schermo durante lo streaming</string>
|
<string name="summary_checkbox_disable_warnings">Disabilita i messaggi di warning sullo schermo durante lo streaming</string>
|
||||||
|
|
||||||
<string name="category_gamepad_settings">Impostazioni Gamepad</string>
|
<string name="category_gamepad_settings">Impostazioni Gamepad</string>
|
||||||
@@ -102,5 +102,5 @@
|
|||||||
|
|
||||||
<string name="category_advanced_settings">Impostazioni Avanzate</string>
|
<string name="category_advanced_settings">Impostazioni Avanzate</string>
|
||||||
<string name="title_decoder_list">Cambia decoder</string>
|
<string name="title_decoder_list">Cambia decoder</string>
|
||||||
<string name="summary_decoder_list">Il decoder software può aumentare la latenza video quando si usano impostazioni streaming basse</string>
|
<string name="summary_decoder_list">Il decoder software può ridurre la latenza video quando si usano impostazioni streaming basse</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<?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" >
|
|
||||||
|
|
||||||
<!-- Non-root application name -->
|
<!-- Non-root application name -->
|
||||||
<application android:label="Limelight" />
|
<application android:label="Limelight" />
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?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.root" >
|
|
||||||
|
|
||||||
<!-- Root permissions -->
|
<!-- Root permissions -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:0.13.2'
|
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
#Wed Apr 10 15:27:10 PDT 2013
|
#Sun Dec 07 22:52:07 PST 2014
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||||
|
<output url="file://$MODULE_DIR$/build/classes/main" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/build/classes/test" />
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
|
|||||||
Reference in new issue
Block a user