mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-04 00:35:47 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f10085f552 | ||
|
eb7f0887bf | ||
|
34a9132d60 | ||
|
24d3fb000a | ||
|
b7b6adaff7 | ||
|
85ed72802f | ||
|
f54f8c83e7 | ||
|
124bfdf418 | ||
|
01507d9995 | ||
|
070c82bc44 | ||
|
17df15293f | ||
|
6551076613 |
@ -1,14 +1,14 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
ndkVersion "23.2.8568313"
|
ndkVersion "27.0.12077973"
|
||||||
|
|
||||||
compileSdk 34
|
compileSdk 34
|
||||||
|
|
||||||
namespace 'com.limelight'
|
namespace 'com.limelight'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk 16
|
minSdk 21
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
|
|
||||||
versionName "12.1"
|
versionName "12.1"
|
||||||
@ -136,12 +136,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
|
||||||
implementation 'org.jcodec:jcodec:0.2.3'
|
implementation 'org.jcodec:jcodec:0.2.5'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||||
implementation 'com.squareup.okio:okio:1.17.5'
|
implementation 'org.jmdns:jmdns:3.5.9'
|
||||||
// 3.5.8 requires minSdk 19, uses StandardCharsets.UTF_8 internally
|
|
||||||
implementation 'org.jmdns:jmdns:3.5.7'
|
|
||||||
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0.1'
|
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0.1'
|
||||||
}
|
}
|
||||||
|
@ -195,14 +195,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
// If we're going to use immersive mode, we want to have
|
// If we're going to use immersive mode, we want to have
|
||||||
// the entire screen
|
// the entire screen
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
getWindow().getDecorView().setSystemUiVisibility(
|
||||||
getWindow().getDecorView().setSystemUiVisibility(
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
|
||||||
|
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for UI visibility events
|
// Listen for UI visibility events
|
||||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
||||||
@ -560,39 +558,19 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If we don't have a reason to lock to portrait or landscape, allow any orientation
|
// If we don't have a reason to lock to portrait or landscape, allow any orientation
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// For regular displays, we always request landscape
|
// For regular displays, we always request landscape
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,7 +898,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
displayRefreshRate = bestMode.getRefreshRate();
|
displayRefreshRate = bestMode.getRefreshRate();
|
||||||
}
|
}
|
||||||
// On L, we can at least tell the OS that we want a refresh rate
|
// On L, we can at least tell the OS that we want a refresh rate
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
float bestRefreshRate = display.getRefreshRate();
|
float bestRefreshRate = display.getRefreshRate();
|
||||||
for (float candidate : display.getSupportedRefreshRates()) {
|
for (float candidate : display.getSupportedRefreshRates()) {
|
||||||
LimeLog.info("Examining refresh rate: "+candidate);
|
LimeLog.info("Examining refresh rate: "+candidate);
|
||||||
@ -944,19 +922,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// Apply the refresh rate change
|
// Apply the refresh rate change
|
||||||
getWindow().setAttributes(windowLayoutParams);
|
getWindow().setAttributes(windowLayoutParams);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Otherwise, the active display refresh rate is just
|
|
||||||
// whatever is currently in use.
|
|
||||||
displayRefreshRate = display.getRefreshRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 4.4 to 5.1 we can't ask for a 4K display mode, so we'll
|
// Until Marshmallow, we can't ask for a 4K display mode, so we'll
|
||||||
// need to hint the OS to provide one.
|
// need to hint the OS to provide one.
|
||||||
boolean aspectRatioMatch = false;
|
boolean aspectRatioMatch = false;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
// We'll calculate whether we need to scale by aspect ratio. If not, we'll use
|
||||||
// On KitKat and later (where we can use the whole screen via immersive mode), we'll
|
|
||||||
// calculate whether we need to scale by aspect ratio or not. If not, we'll use
|
|
||||||
// setFixedSize so we can handle 4K properly. The only known devices that have
|
// setFixedSize so we can handle 4K properly. The only known devices that have
|
||||||
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
||||||
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
||||||
@ -1011,8 +982,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||||
}
|
}
|
||||||
// Use immersive mode on 4.4+ or standard low profile on previous builds
|
else {
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
// Use immersive mode
|
||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||||
@ -1021,11 +992,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
|
||||||
View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2214,13 +2180,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View view, MotionEvent event) {
|
public boolean onTouch(View view, MotionEvent event) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
// Tell the OS not to buffer input events for us
|
||||||
// Tell the OS not to buffer input events for us
|
//
|
||||||
//
|
// NB: This is still needed even when we call the newer requestUnbufferedDispatch()!
|
||||||
// NB: This is still needed even when we call the newer requestUnbufferedDispatch()!
|
view.requestUnbufferedDispatch(event);
|
||||||
view.requestUnbufferedDispatch(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleMotionEvent(view, event);
|
return handleMotionEvent(view, event);
|
||||||
@ -2667,14 +2631,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
||||||
hideSystemUi(2000);
|
hideSystemUi(2000);
|
||||||
}
|
}
|
||||||
// This flag is only set on 4.4+
|
else if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
|
||||||
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT &&
|
|
||||||
(visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
|
|
||||||
hideSystemUi(2000);
|
|
||||||
}
|
|
||||||
// This flag is only set before 4.4+
|
|
||||||
else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT &&
|
|
||||||
(visibility & View.SYSTEM_UI_FLAG_LOW_PROFILE) == 0) {
|
|
||||||
hideSystemUi(2000);
|
hideSystemUi(2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,26 @@ import android.content.ServiceConnection;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import com.limelight.computers.ComputerDatabaseManager;
|
||||||
import com.limelight.computers.ComputerManagerListener;
|
import com.limelight.computers.ComputerManagerListener;
|
||||||
import com.limelight.computers.ComputerManagerService;
|
import com.limelight.computers.ComputerManagerService;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
import com.limelight.nvstream.http.PairingManager;
|
import com.limelight.nvstream.http.PairingManager;
|
||||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||||
|
import com.limelight.utils.CacheHelper;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
import com.limelight.utils.ServerHelper;
|
import com.limelight.utils.ServerHelper;
|
||||||
import com.limelight.utils.SpinnerDialog;
|
import com.limelight.utils.SpinnerDialog;
|
||||||
import com.limelight.utils.UiHelper;
|
import com.limelight.utils.UiHelper;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ShortcutTrampoline extends Activity {
|
public class ShortcutTrampoline extends Activity {
|
||||||
@ -33,6 +40,7 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
private SpinnerDialog blockingLoadSpinner;
|
private SpinnerDialog blockingLoadSpinner;
|
||||||
|
|
||||||
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
||||||
|
|
||||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||||
final ComputerManagerService.ComputerManagerBinder localBinder =
|
final ComputerManagerService.ComputerManagerBinder localBinder =
|
||||||
@ -214,9 +222,9 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected boolean validateInput(String uuidString, String appIdString) {
|
protected boolean validateInput(String uuidString, String appIdString, String nameString) {
|
||||||
// Validate UUID
|
// Validate PC UUID/Name
|
||||||
if (uuidString == null) {
|
if (uuidString == null && nameString == null) {
|
||||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
getResources().getString(R.string.conn_error_title),
|
getResources().getString(R.string.conn_error_title),
|
||||||
getResources().getString(R.string.scut_invalid_uuid),
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
@ -224,14 +232,25 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (uuidString != null && !uuidString.isEmpty()) {
|
||||||
UUID.fromString(uuidString);
|
try {
|
||||||
} catch (IllegalArgumentException ex) {
|
UUID.fromString(uuidString);
|
||||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
} catch (IllegalArgumentException ex) {
|
||||||
getResources().getString(R.string.conn_error_title),
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
getResources().getString(R.string.scut_invalid_uuid),
|
getResources().getString(R.string.conn_error_title),
|
||||||
true);
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
return false;
|
true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// UUID is null, so fallback to Name
|
||||||
|
if (nameString == null || nameString.isEmpty()) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
|
true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate App ID (if provided)
|
// Validate App ID (if provided)
|
||||||
@ -255,24 +274,93 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
UiHelper.notifyNewRootView(this);
|
UiHelper.notifyNewRootView(this);
|
||||||
|
ComputerDatabaseManager dbManager = new ComputerDatabaseManager(this);
|
||||||
|
ComputerDetails _computer = null;
|
||||||
|
|
||||||
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
// PC arguments, both are optional, but at least one must be provided
|
||||||
uuidString = getIntent().getStringExtra(AppView.UUID_EXTRA);
|
uuidString = getIntent().getStringExtra(AppView.UUID_EXTRA);
|
||||||
|
String nameString = getIntent().getStringExtra(AppView.NAME_EXTRA);
|
||||||
|
|
||||||
if (validateInput(uuidString, appIdString)) {
|
// App arguments, both are optional, but one must be provided in order to start an app
|
||||||
if (appIdString != null && !appIdString.isEmpty()) {
|
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
||||||
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
String appNameString = getIntent().getStringExtra(Game.EXTRA_APP_NAME);
|
||||||
Integer.parseInt(appIdString),
|
|
||||||
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
if (!validateInput(uuidString, appIdString, nameString)) {
|
||||||
|
// Invalid input, so just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuidString == null || uuidString.isEmpty()) {
|
||||||
|
// Use nameString to find the corresponding UUID
|
||||||
|
_computer = dbManager.getComputerByName(nameString);
|
||||||
|
|
||||||
|
if (_computer == null) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_pc_not_found),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to the computer manager service
|
uuidString = _computer.uuid;
|
||||||
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
|
||||||
Service.BIND_AUTO_CREATE);
|
|
||||||
|
|
||||||
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
// Set the AppView UUID intent, since it wasn't provided
|
||||||
getResources().getString(R.string.applist_connect_msg), true);
|
setIntent(new Intent(getIntent()).putExtra(AppView.UUID_EXTRA, uuidString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appIdString != null && !appIdString.isEmpty()) {
|
||||||
|
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
||||||
|
Integer.parseInt(appIdString),
|
||||||
|
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||||
|
}
|
||||||
|
else if (appNameString != null && !appNameString.isEmpty()) {
|
||||||
|
// Use appNameString to find the corresponding AppId
|
||||||
|
try {
|
||||||
|
int appId = -1;
|
||||||
|
String rawAppList = CacheHelper.readInputStreamToString(CacheHelper.openCacheFileForInput(getCacheDir(), "applist", uuidString));
|
||||||
|
|
||||||
|
if (rawAppList.isEmpty()) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<NvApp> applist = NvHTTP.getAppListByReader(new StringReader(rawAppList));
|
||||||
|
|
||||||
|
for (NvApp _app : applist) {
|
||||||
|
if (_app.getAppName().equals(appNameString)) {
|
||||||
|
appId = _app.getAppId();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (appId < 0) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIntent(new Intent(getIntent()).putExtra(Game.EXTRA_APP_ID, appId));
|
||||||
|
app = new NvApp(
|
||||||
|
appNameString,
|
||||||
|
appId,
|
||||||
|
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||||
|
} catch (IOException | XmlPullParserException e) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind to the computer manager service
|
||||||
|
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
||||||
|
Service.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
|
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
||||||
|
getResources().getString(R.string.applist_connect_msg), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,51 +26,41 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
|
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
||||||
return new AudioTrack(AudioManager.STREAM_MUSIC,
|
.setUsage(AudioAttributes.USAGE_GAME);
|
||||||
sampleRate,
|
AudioFormat format = new AudioFormat.Builder()
|
||||||
channelConfig,
|
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
||||||
AudioFormat.ENCODING_PCM_16BIT,
|
.setSampleRate(sampleRate)
|
||||||
bufferSize,
|
.setChannelMask(channelConfig)
|
||||||
AudioTrack.MODE_STREAM);
|
.build();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
// Use FLAG_LOW_LATENCY on L through N
|
||||||
|
if (lowLatency) {
|
||||||
|
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
||||||
|
.setAudioFormat(format)
|
||||||
|
.setAudioAttributes(attributesBuilder.build())
|
||||||
|
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||||
|
.setBufferSizeInBytes(bufferSize);
|
||||||
|
|
||||||
|
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
||||||
|
if (lowLatency) {
|
||||||
|
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackBuilder.build();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
return new AudioTrack(attributesBuilder.build(),
|
||||||
.setUsage(AudioAttributes.USAGE_GAME);
|
format,
|
||||||
AudioFormat format = new AudioFormat.Builder()
|
bufferSize,
|
||||||
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
AudioTrack.MODE_STREAM,
|
||||||
.setSampleRate(sampleRate)
|
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
||||||
.setChannelMask(channelConfig)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
||||||
// Use FLAG_LOW_LATENCY on L through N
|
|
||||||
if (lowLatency) {
|
|
||||||
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
|
||||||
.setAudioFormat(format)
|
|
||||||
.setAudioAttributes(attributesBuilder.build())
|
|
||||||
.setTransferMode(AudioTrack.MODE_STREAM)
|
|
||||||
.setBufferSizeInBytes(bufferSize);
|
|
||||||
|
|
||||||
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
|
||||||
if (lowLatency) {
|
|
||||||
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackBuilder.build();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new AudioTrack(attributesBuilder.build(),
|
|
||||||
format,
|
|
||||||
bufferSize,
|
|
||||||
AudioTrack.MODE_STREAM,
|
|
||||||
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,20 +81,10 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
||||||
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
||||||
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
||||||
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
||||||
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// On KitKat and lower, creation of the AudioTrack will fail if we specify
|
|
||||||
// CHANNEL_OUT_SIDE_LEFT or CHANNEL_OUT_SIDE_RIGHT. That leaves us with
|
|
||||||
// the old CHANNEL_OUT_7POINT1 which uses left-of-center and right-of-center
|
|
||||||
// speakers instead of side-left and side-right. This non-standard layout
|
|
||||||
// is probably not what the user wants, but we don't really have a choice.
|
|
||||||
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LimeLog.severe("Decoder returned unhandled channel count");
|
LimeLog.severe("Decoder returned unhandled channel count");
|
||||||
|
@ -666,7 +666,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// back button to function for navigation.
|
// back button to function for navigation.
|
||||||
//
|
//
|
||||||
// First, check if this is an internal device we're being called on.
|
// First, check if this is an internal device we're being called on.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !isExternal(dev)) {
|
if (!isExternal(dev)) {
|
||||||
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
||||||
|
|
||||||
boolean foundInternalGamepad = false;
|
boolean foundInternalGamepad = false;
|
||||||
@ -712,10 +712,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
String devName = dev.getName();
|
String devName = dev.getName();
|
||||||
|
|
||||||
LimeLog.info("Creating controller context for device: "+devName);
|
LimeLog.info("Creating controller context for device: "+devName);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
LimeLog.info("Vendor ID: " + dev.getVendorId());
|
||||||
LimeLog.info("Vendor ID: "+dev.getVendorId());
|
LimeLog.info("Product ID: "+dev.getProductId());
|
||||||
LimeLog.info("Product ID: "+dev.getProductId());
|
|
||||||
}
|
|
||||||
LimeLog.info(dev.toString());
|
LimeLog.info(dev.toString());
|
||||||
|
|
||||||
context.inputDevice = dev;
|
context.inputDevice = dev;
|
||||||
@ -723,15 +721,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.id = dev.getId();
|
context.id = dev.getId();
|
||||||
context.external = isExternal(dev);
|
context.external = isExternal(dev);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
context.vendorId = dev.getVendorId();
|
||||||
context.vendorId = dev.getVendorId();
|
context.productId = dev.getProductId();
|
||||||
context.productId = dev.getProductId();
|
|
||||||
|
|
||||||
// These aren't always present in the Android key layout files, so they won't show up
|
// These aren't always present in the Android key layout files, so they won't show up
|
||||||
// in our normal InputDevice.hasKeys() probing.
|
// in our normal InputDevice.hasKeys() probing.
|
||||||
context.hasPaddles = MoonBridge.guessControllerHasPaddles(context.vendorId, context.productId);
|
context.hasPaddles = MoonBridge.guessControllerHasPaddles(context.vendorId, context.productId);
|
||||||
context.hasShare = MoonBridge.guessControllerHasShareButton(context.vendorId, context.productId);
|
context.hasShare = MoonBridge.guessControllerHasShareButton(context.vendorId, context.productId);
|
||||||
}
|
|
||||||
|
|
||||||
// Try to use the InputDevice's associated vibrators first
|
// Try to use the InputDevice's associated vibrators first
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasQuadAmplitudeControlledRumbleVibrators(dev.getVibratorManager())) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasQuadAmplitudeControlledRumbleVibrators(dev.getVibratorManager())) {
|
||||||
@ -790,11 +786,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
// Detect if the gamepad has Mode and Select buttons according to the Android key layouts.
|
// Detect if the gamepad has Mode and Select buttons according to the Android key layouts.
|
||||||
// We do this first because other codepaths below may override these defaults.
|
// We do this first because other codepaths below may override these defaults.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
boolean[] buttons = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_MODE, KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
||||||
boolean[] buttons = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_MODE, KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
context.hasMode = buttons[0];
|
||||||
context.hasMode = buttons[0];
|
context.hasSelect = buttons[1] || buttons[2];
|
||||||
context.hasSelect = buttons[1] || buttons[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
context.touchpadXRange = dev.getMotionRange(MotionEvent.AXIS_X, InputDevice.SOURCE_TOUCHPAD);
|
context.touchpadXRange = dev.getMotionRange(MotionEvent.AXIS_X, InputDevice.SOURCE_TOUCHPAD);
|
||||||
context.touchpadYRange = dev.getMotionRange(MotionEvent.AXIS_Y, InputDevice.SOURCE_TOUCHPAD);
|
context.touchpadYRange = dev.getMotionRange(MotionEvent.AXIS_Y, InputDevice.SOURCE_TOUCHPAD);
|
||||||
@ -844,22 +838,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
||||||
InputDevice.MotionRange ryRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RY);
|
InputDevice.MotionRange ryRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RY);
|
||||||
if (rxRange != null && ryRange != null && devName != null) {
|
if (rxRange != null && ryRange != null && devName != null) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (dev.getVendorId() == 0x054c) { // Sony
|
||||||
if (dev.getVendorId() == 0x054c) { // Sony
|
if (dev.hasKeys(KeyEvent.KEYCODE_BUTTON_C)[0]) {
|
||||||
if (dev.hasKeys(KeyEvent.KEYCODE_BUTTON_C)[0]) {
|
LimeLog.info("Detected non-standard DualShock 4 mapping");
|
||||||
LimeLog.info("Detected non-standard DualShock 4 mapping");
|
context.isNonStandardDualShock4 = true;
|
||||||
context.isNonStandardDualShock4 = true;
|
} else {
|
||||||
}
|
LimeLog.info("Detected DualShock 4 (Linux standard mapping)");
|
||||||
else {
|
context.usesLinuxGamepadStandardFaceButtons = true;
|
||||||
LimeLog.info("Detected DualShock 4 (Linux standard mapping)");
|
|
||||||
context.usesLinuxGamepadStandardFaceButtons = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!devName.contains("Xbox") && !devName.contains("XBox") && !devName.contains("X-Box")) {
|
|
||||||
LimeLog.info("Assuming non-standard DualShock 4 mapping on < 4.4");
|
|
||||||
context.isNonStandardDualShock4 = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.isNonStandardDualShock4) {
|
if (context.isNonStandardDualShock4) {
|
||||||
// The old DS4 driver uses RX and RY for triggers
|
// The old DS4 driver uses RX and RY for triggers
|
||||||
@ -943,16 +930,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The ADT-1 controller needs a similar fixup to the ASUS Gamepad
|
// The ADT-1 controller needs a similar fixup to the ASUS Gamepad
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (dev.getVendorId() == 0x18d1 && dev.getProductId() == 0x2c40) {
|
||||||
// The device name provided is just "Gamepad" which is pretty useless, so we
|
context.backIsStart = true;
|
||||||
// use VID/PID instead
|
context.modeIsSelect = true;
|
||||||
if (dev.getVendorId() == 0x18d1 && dev.getProductId() == 0x2c40) {
|
context.triggerDeadzone = 0.30f;
|
||||||
context.backIsStart = true;
|
context.hasSelect = true;
|
||||||
context.modeIsSelect = true;
|
context.hasMode = false;
|
||||||
context.triggerDeadzone = 0.30f;
|
|
||||||
context.hasSelect = true;
|
|
||||||
context.hasMode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ignoreBack = shouldIgnoreBack(dev);
|
context.ignoreBack = shouldIgnoreBack(dev);
|
||||||
@ -962,16 +945,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// use the back button as start since it doesn't have a start/menu button
|
// use the back button as start since it doesn't have a start/menu button
|
||||||
// on the controller
|
// on the controller
|
||||||
if (devName.contains("ASUS Gamepad")) {
|
if (devName.contains("ASUS Gamepad")) {
|
||||||
// We can only do this check on KitKat or higher, but it doesn't matter since ATV
|
boolean[] hasStartKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_MENU, 0);
|
||||||
// is Android 5.0 anyway
|
if (!hasStartKey[0] && !hasStartKey[1]) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
context.backIsStart = true;
|
||||||
boolean[] hasStartKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_MENU, 0);
|
context.modeIsSelect = true;
|
||||||
if (!hasStartKey[0] && !hasStartKey[1]) {
|
context.hasSelect = true;
|
||||||
context.backIsStart = true;
|
context.hasMode = false;
|
||||||
context.modeIsSelect = true;
|
|
||||||
context.hasSelect = true;
|
|
||||||
context.hasMode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ASUS Gamepad has triggers that sit far forward and are prone to false presses
|
// The ASUS Gamepad has triggers that sit far forward and are prone to false presses
|
||||||
@ -1016,10 +995,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
// Thrustmaster Score A gamepad home button reports directly to android as
|
// Thrustmaster Score A gamepad home button reports directly to android as
|
||||||
// KEY_HOMEPAGE event on another event channel
|
// KEY_HOMEPAGE event on another event channel
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (dev.getVendorId() == 0x044f && dev.getProductId() == 0xb328) {
|
||||||
if (dev.getVendorId() == 0x044f && dev.getProductId() == 0xb328) {
|
context.hasMode = false;
|
||||||
context.hasMode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
||||||
@ -2048,15 +2025,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
.build();
|
.build();
|
||||||
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
|
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
.setUsage(AudioAttributes.USAGE_GAME)
|
.setUsage(AudioAttributes.USAGE_GAME)
|
||||||
.build();
|
.build();
|
||||||
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
|
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
vibrator.vibrate(new long[]{0, onTime, offTime}, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
||||||
@ -3086,11 +3060,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendControllerArrival() {
|
public void sendControllerArrival() {
|
||||||
// Below KitKat we can't get enough information to report controller details accurately
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte type;
|
byte type;
|
||||||
switch (inputDevice.getVendorId()) {
|
switch (inputDevice.getVendorId()) {
|
||||||
case 0x045e: // Microsoft
|
case 0x045e: // Microsoft
|
||||||
|
@ -211,28 +211,22 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRecognizedInputDevice(UsbDevice device) {
|
public static boolean isRecognizedInputDevice(UsbDevice device) {
|
||||||
// On KitKat and later, we can determine if this VID and PID combo
|
// Determine if this VID and PID combo matches an existing input device
|
||||||
// matches an existing input device and defer to the built-in controller
|
// and defer to the built-in controller support in that case.
|
||||||
// support in that case. Prior to KitKat, we'll always return true to be safe.
|
for (int id : InputDevice.getDeviceIds()) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
InputDevice inputDev = InputDevice.getDevice(id);
|
||||||
for (int id : InputDevice.getDeviceIds()) {
|
if (inputDev == null) {
|
||||||
InputDevice inputDev = InputDevice.getDevice(id);
|
// Device was removed while looping
|
||||||
if (inputDev == null) {
|
continue;
|
||||||
// Device was removed while looping
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
|
||||||
inputDev.getProductId() == device.getProductId()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||||
}
|
inputDev.getProductId() == device.getProductId()) {
|
||||||
else {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean kernelSupportsXboxOne() {
|
public static boolean kernelSupportsXboxOne() {
|
||||||
|
@ -39,6 +39,7 @@ public class Xbox360Controller extends AbstractXboxController {
|
|||||||
0x20d6, // PowerA
|
0x20d6, // PowerA
|
||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
0x2f24, // GameSir
|
0x2f24, // GameSir
|
||||||
|
0x2dc8, // 8BitDo
|
||||||
};
|
};
|
||||||
|
|
||||||
public static boolean canClaimDevice(UsbDevice device) {
|
public static boolean canClaimDevice(UsbDevice device) {
|
||||||
|
@ -89,28 +89,26 @@ public class Xbox360WirelessDongle extends AbstractController {
|
|||||||
public boolean start() {
|
public boolean start() {
|
||||||
int controllerIndex = 0;
|
int controllerIndex = 0;
|
||||||
|
|
||||||
// On KitKat, there is a controller number associated with input devices.
|
// On Android, there is a controller number associated with input devices.
|
||||||
// We can use this to approximate the likely controller number. This won't
|
// We can use this to approximate the likely controller number. This won't
|
||||||
// be completely accurate because there's no guarantee the order of interfaces
|
// be completely accurate because there's no guarantee the order of interfaces
|
||||||
// matches the order that devices were enumerated by xpad, but it's probably
|
// matches the order that devices were enumerated by xpad, but it's probably
|
||||||
// better than nothing.
|
// better than nothing.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
for (int id : InputDevice.getDeviceIds()) {
|
||||||
for (int id : InputDevice.getDeviceIds()) {
|
InputDevice inputDev = InputDevice.getDevice(id);
|
||||||
InputDevice inputDev = InputDevice.getDevice(id);
|
if (inputDev == null) {
|
||||||
if (inputDev == null) {
|
// Device was removed while looping
|
||||||
// Device was removed while looping
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Newer xpad versions use a special product ID (0x02a1) for controllers
|
// Newer xpad versions use a special product ID (0x02a1) for controllers
|
||||||
// rather than copying the product ID of the dongle itself.
|
// rather than copying the product ID of the dongle itself.
|
||||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||||
(inputDev.getProductId() == device.getProductId() ||
|
(inputDev.getProductId() == device.getProductId() ||
|
||||||
inputDev.getProductId() == 0x02a1) &&
|
inputDev.getProductId() == 0x02a1) &&
|
||||||
inputDev.getControllerNumber() > 0) {
|
inputDev.getControllerNumber() > 0) {
|
||||||
controllerIndex = inputDev.getControllerNumber() - 1;
|
controllerIndex = inputDev.getControllerNumber() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,10 @@ public class VirtualControllerConfigurationLoader {
|
|||||||
private static final int START_BACK_WIDTH = 12;
|
private static final int START_BACK_WIDTH = 12;
|
||||||
private static final int START_BACK_HEIGHT = 7;
|
private static final int START_BACK_HEIGHT = 7;
|
||||||
|
|
||||||
|
// Make the Guide Menu be in the center of START and BACK menu
|
||||||
|
private static final int GUIDE_X = START_X-BACK_X;
|
||||||
|
private static final int GUIDE_Y = START_BACK_Y;
|
||||||
|
|
||||||
public static void createDefaultLayout(final VirtualController controller, final Context context) {
|
public static void createDefaultLayout(final VirtualController controller, final Context context) {
|
||||||
|
|
||||||
DisplayMetrics screen = context.getResources().getDisplayMetrics();
|
DisplayMetrics screen = context.getResources().getDisplayMetrics();
|
||||||
@ -333,6 +337,16 @@ public class VirtualControllerConfigurationLoader {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.showGuideButton){
|
||||||
|
controller.addElement(createDigitalButton(VirtualControllerElement.EID_GDB,
|
||||||
|
ControllerPacket.SPECIAL_BUTTON_FLAG, 0, 1, "GUIDE", -1, controller, context),
|
||||||
|
screenScale(GUIDE_X, height)+ rightDisplacement,
|
||||||
|
screenScale(GUIDE_Y, height),
|
||||||
|
screenScale(START_BACK_WIDTH, height),
|
||||||
|
screenScale(START_BACK_HEIGHT, height)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
controller.setOpacity(config.oscOpacity);
|
controller.setOpacity(config.oscOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ public abstract class VirtualControllerElement extends View {
|
|||||||
public static final int EID_RS = 13;
|
public static final int EID_RS = 13;
|
||||||
public static final int EID_LSB = 14;
|
public static final int EID_LSB = 14;
|
||||||
public static final int EID_RSB = 15;
|
public static final int EID_RSB = 15;
|
||||||
|
public static final int EID_GDB = 16;
|
||||||
|
|
||||||
protected VirtualController virtualController;
|
protected VirtualController virtualController;
|
||||||
protected final int elementId;
|
protected final int elementId;
|
||||||
|
@ -471,9 +471,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, refreshRate);
|
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, refreshRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adaptive playback can also be enabled by the whitelist on pre-KitKat devices
|
// Populate keys for adaptive playback
|
||||||
// so we don't fill these pre-KitKat
|
if (adaptivePlayback) {
|
||||||
if (adaptivePlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, initialWidth);
|
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, initialWidth);
|
||||||
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, initialHeight);
|
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, initialHeight);
|
||||||
}
|
}
|
||||||
|
@ -596,43 +596,37 @@ public class MediaCodecHelper {
|
|||||||
|
|
||||||
public static boolean decoderSupportsFusedIdrFrame(MediaCodecInfo decoderInfo, String mimeType) {
|
public static boolean decoderSupportsFusedIdrFrame(MediaCodecInfo decoderInfo, String mimeType) {
|
||||||
// If adaptive playback is supported, we can submit new CSD together with a keyframe
|
// If adaptive playback is supported, we can submit new CSD together with a keyframe
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
try {
|
||||||
try {
|
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)) {
|
||||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
LimeLog.info("Decoder supports fused IDR frames (FEATURE_AdaptivePlayback)");
|
||||||
{
|
return true;
|
||||||
LimeLog.info("Decoder supports fused IDR frames (FEATURE_AdaptivePlayback)");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Tolerate buggy codecs
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Tolerate buggy codecs
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) {
|
public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) {
|
||||||
// Possibly enable adaptive playback on KitKat and above
|
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
LimeLog.info("Decoder blacklisted for adaptive playback");
|
||||||
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
return false;
|
||||||
LimeLog.info("Decoder blacklisted for adaptive playback");
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
||||||
{
|
{
|
||||||
// This will make getCapabilities() return that adaptive playback is supported
|
// This will make getCapabilities() return that adaptive playback is supported
|
||||||
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Tolerate buggy codecs
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Tolerate buggy codecs
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -709,13 +703,6 @@ public class MediaCodecHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
||||||
// Google didn't have official support for HEVC (or more importantly, a CTS test) until
|
|
||||||
// Lollipop. I've seen some MediaTek devices on 4.4 crash when attempting to use HEVC,
|
|
||||||
// so I'm restricting HEVC usage to Lollipop and higher.
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Software decoders are terrible and we never want to use them.
|
// Software decoders are terrible and we never want to use them.
|
||||||
// We want to catch decoders like:
|
// We want to catch decoders like:
|
||||||
@ -785,15 +772,8 @@ public class MediaCodecHelper {
|
|||||||
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
|
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
|
||||||
LinkedList<MediaCodecInfo> infoList = new LinkedList<>();
|
LinkedList<MediaCodecInfo> infoList = new LinkedList<>();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||||
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
Collections.addAll(infoList, mcl.getCodecInfos());
|
||||||
Collections.addAll(infoList, mcl.getCodecInfos());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
|
||||||
infoList.add(MediaCodecList.getCodecInfoAt(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return infoList;
|
return infoList;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,35 @@ public class ComputerDatabaseManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a computer by name
|
||||||
|
* NOTE: It is perfectly valid for multiple computers to have the same name,
|
||||||
|
* this function will only return the first one it finds.
|
||||||
|
* Consider using getComputerByUUID instead.
|
||||||
|
* @param name The name of the computer
|
||||||
|
* @see ComputerDatabaseManager#getComputerByUUID(String) for alternative.
|
||||||
|
* @return The computer details, or null if no computer with that name exists
|
||||||
|
*/
|
||||||
|
public ComputerDetails getComputerByName(String name) {
|
||||||
|
try (final Cursor c = computerDb.query(
|
||||||
|
COMPUTER_TABLE_NAME, null, COMPUTER_NAME_COLUMN_NAME+"=?",
|
||||||
|
new String[]{ name }, null, null, null)
|
||||||
|
) {
|
||||||
|
if (!c.moveToFirst()) {
|
||||||
|
// No matching computer
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getComputerFromCursor(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a computer by UUID
|
||||||
|
* @param uuid The UUID of the computer
|
||||||
|
* @see ComputerDatabaseManager#getComputerByName(String) for alternative.
|
||||||
|
* @return The computer details, or null if no computer with that UUID exists
|
||||||
|
*/
|
||||||
public ComputerDetails getComputerByUUID(String uuid) {
|
public ComputerDetails getComputerByUUID(String uuid) {
|
||||||
try (final Cursor c = computerDb.query(
|
try (final Cursor c = computerDb.query(
|
||||||
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
|
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
|
||||||
|
@ -341,57 +341,53 @@ public class ComputerManagerService extends Service {
|
|||||||
// Acquire the default network lock since we could be changing global process state
|
// Acquire the default network lock since we could be changing global process state
|
||||||
defaultNetworkLock.lock();
|
defaultNetworkLock.lock();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
// On Lollipop or later, we can bind our process to the underlying interface
|
||||||
// On Lollipop or later, we can bind our process to the underlying interface
|
// to ensure our STUN request goes out on that interface or not at all (which is
|
||||||
// to ensure our STUN request goes out on that interface or not at all (which is
|
// preferable to getting a VPN endpoint address back).
|
||||||
// preferable to getting a VPN endpoint address back).
|
Network[] networks = connMgr.getAllNetworks();
|
||||||
Network[] networks = connMgr.getAllNetworks();
|
for (Network net : networks) {
|
||||||
for (Network net : networks) {
|
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
||||||
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
if (netCaps != null) {
|
||||||
if (netCaps != null) {
|
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
||||||
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||||
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
// This network looks like an underlying multicast-capable transport,
|
||||||
// This network looks like an underlying multicast-capable transport,
|
// so let's guess that it's probably where our mDNS response came from.
|
||||||
// so let's guess that it's probably where our mDNS response came from.
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (connMgr.bindProcessToNetwork(net)) {
|
||||||
if (connMgr.bindProcessToNetwork(net)) {
|
|
||||||
boundToNetwork = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
|
||||||
boundToNetwork = true;
|
boundToNetwork = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
||||||
|
boundToNetwork = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
||||||
if (!activeNetworkIsVpn || boundToNetwork) {
|
if (!activeNetworkIsVpn || boundToNetwork) {
|
||||||
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
||||||
if (stunResolvedAddress != null) {
|
if (stunResolvedAddress != null) {
|
||||||
// We don't know for sure what the external port is, so we will have to guess.
|
// We don't know for sure what the external port is, so we will have to guess.
|
||||||
// When we contact the PC (if we haven't already), it will update the port.
|
// When we contact the PC (if we haven't already), it will update the port.
|
||||||
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Unbind from the network
|
// Unbind from the network
|
||||||
if (boundToNetwork) {
|
if (boundToNetwork) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
connMgr.bindProcessToNetwork(null);
|
connMgr.bindProcessToNetwork(null);
|
||||||
|
} else {
|
||||||
|
ConnectivityManager.setProcessDefaultNetwork(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
ConnectivityManager.setProcessDefaultNetwork(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock the network state
|
// Unlock the network state
|
||||||
if (activeNetworkIsVpn) {
|
if (activeNetworkIsVpn) {
|
||||||
defaultNetworkLock.unlock();
|
defaultNetworkLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,14 +28,8 @@ public class DiskAssetLoader {
|
|||||||
|
|
||||||
public DiskAssetLoader(Context context) {
|
public DiskAssetLoader(Context context) {
|
||||||
this.cacheDir = context.getCacheDir();
|
this.cacheDir = context.getCacheDir();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
this.isLowRamDevice =
|
||||||
this.isLowRamDevice =
|
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
||||||
((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Use conservative low RAM behavior on very old devices
|
|
||||||
this.isLowRamDevice = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||||
|
@ -198,7 +198,7 @@ public class NvConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||||
if (activeNetworkInfo != null) {
|
if (activeNetworkInfo != null) {
|
||||||
switch (activeNetworkInfo.getType()) {
|
switch (activeNetworkInfo.getType()) {
|
||||||
|
@ -403,16 +403,7 @@ public class NvHTTP {
|
|||||||
try {
|
try {
|
||||||
SSLContext sc = SSLContext.getInstance("TLS");
|
SSLContext sc = SSLContext.getInstance("TLS");
|
||||||
sc.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom());
|
sc.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom());
|
||||||
|
return client.newBuilder().sslSocketFactory(sc.getSocketFactory(), trustManager).build();
|
||||||
// TLS 1.2 is not enabled by default prior to Android 5.0, so we'll need a custom
|
|
||||||
// SSLSocketFactory in order to connect to GFE 3.20.4 which requires TLSv1.2 or later.
|
|
||||||
// We don't just always use TLSv12SocketFactory because explicitly specifying TLS versions
|
|
||||||
// prevents later TLS versions from being negotiated even if client and server otherwise
|
|
||||||
// support them.
|
|
||||||
return client.newBuilder().sslSocketFactory(
|
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
|
|
||||||
sc.getSocketFactory() : new TLSv12SocketFactory(sc),
|
|
||||||
trustManager).build();
|
|
||||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -595,6 +586,12 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an app by ID
|
||||||
|
* @param appId The ID of the app
|
||||||
|
* @see #getAppByName(String) for alternative.
|
||||||
|
* @return app details, or null if no app with that ID exists
|
||||||
|
*/
|
||||||
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
|
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
|
||||||
LinkedList<NvApp> appList = getAppList();
|
LinkedList<NvApp> appList = getAppList();
|
||||||
for (NvApp appFromList : appList) {
|
for (NvApp appFromList : appList) {
|
||||||
@ -605,10 +602,15 @@ public class NvHTTP {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Only use this function if you know what you're doing.
|
/**
|
||||||
* It's totally valid to have two apps named the same thing,
|
* Get an app by name
|
||||||
* or even nothing at all! Look apps up by ID if at all possible
|
* NOTE: It is perfectly valid for multiple apps to have the same name,
|
||||||
* using the above function */
|
* this function will only return the first one it finds.
|
||||||
|
* Consider using getAppById instead.
|
||||||
|
* @param appName The name of the app
|
||||||
|
* @see #getAppById(int) for alternative.
|
||||||
|
* @return app details, or null if no app with that name exists
|
||||||
|
*/
|
||||||
public NvApp getAppByName(String appName) throws IOException, XmlPullParserException {
|
public NvApp getAppByName(String appName) throws IOException, XmlPullParserException {
|
||||||
LinkedList<NvApp> appList = getAppList();
|
LinkedList<NvApp> appList = getAppList();
|
||||||
for (NvApp appFromList : appList) {
|
for (NvApp appFromList : appList) {
|
||||||
@ -814,62 +816,4 @@ public class NvHTTP {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on example code from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
|
|
||||||
private static class TLSv12SocketFactory extends SSLSocketFactory {
|
|
||||||
private SSLSocketFactory internalSSLSocketFactory;
|
|
||||||
|
|
||||||
public TLSv12SocketFactory(SSLContext context) {
|
|
||||||
internalSSLSocketFactory = context.getSocketFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getDefaultCipherSuites() {
|
|
||||||
return internalSSLSocketFactory.getDefaultCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedCipherSuites() {
|
|
||||||
return internalSSLSocketFactory.getSupportedCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket() throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Socket enableTLSv12OnSocket(Socket socket) {
|
|
||||||
if (socket instanceof SSLSocket) {
|
|
||||||
// TLS 1.2 is not enabled by default prior to Android 5.0. We must enable it
|
|
||||||
// explicitly to ensure we can communicate with GFE 3.20.4 which blocks TLS 1.0.
|
|
||||||
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
|
|
||||||
}
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import com.limelight.R;
|
|||||||
import static com.limelight.binding.input.virtual_controller.VirtualControllerConfigurationLoader.OSC_PREFERENCE;
|
import static com.limelight.binding.input.virtual_controller.VirtualControllerConfigurationLoader.OSC_PREFERENCE;
|
||||||
|
|
||||||
public class ConfirmDeleteOscPreference extends DialogPreference {
|
public class ConfirmDeleteOscPreference extends DialogPreference {
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public ConfirmDeleteOscPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public ConfirmDeleteOscPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
@ -26,7 +25,6 @@ public class ConfirmDeleteOscPreference extends DialogPreference {
|
|||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public ConfirmDeleteOscPreference(Context context) {
|
public ConfirmDeleteOscPreference(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,10 @@ import android.provider.Settings;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
public class LanguagePreference extends ListPreference {
|
public class LanguagePreference extends ListPreference {
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ public class PreferenceConfiguration {
|
|||||||
private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
|
private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
|
||||||
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
|
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
|
||||||
private static final String ONLY_L3_R3_PREF_STRING = "checkbox_only_show_L3R3";
|
private static final String ONLY_L3_R3_PREF_STRING = "checkbox_only_show_L3R3";
|
||||||
|
private static final String SHOW_GUIDE_BUTTON_PREF_STRING = "checkbox_show_guide_button";
|
||||||
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
|
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
|
||||||
private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr";
|
private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr";
|
||||||
private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip";
|
private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip";
|
||||||
@ -83,6 +84,7 @@ public class PreferenceConfiguration {
|
|||||||
|
|
||||||
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
|
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
|
||||||
private static final boolean ONLY_L3_R3_DEFAULT = false;
|
private static final boolean ONLY_L3_R3_DEFAULT = false;
|
||||||
|
private static final boolean SHOW_GUIDE_BUTTON_DEFAULT = true;
|
||||||
private static final boolean DEFAULT_ENABLE_HDR = false;
|
private static final boolean DEFAULT_ENABLE_HDR = false;
|
||||||
private static final boolean DEFAULT_ENABLE_PIP = false;
|
private static final boolean DEFAULT_ENABLE_PIP = false;
|
||||||
private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false;
|
private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false;
|
||||||
@ -130,6 +132,7 @@ public class PreferenceConfiguration {
|
|||||||
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
|
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
|
||||||
public boolean onscreenController;
|
public boolean onscreenController;
|
||||||
public boolean onlyL3R3;
|
public boolean onlyL3R3;
|
||||||
|
public boolean showGuideButton;
|
||||||
public boolean enableHdr;
|
public boolean enableHdr;
|
||||||
public boolean enablePip;
|
public boolean enablePip;
|
||||||
public boolean enablePerfOverlay;
|
public boolean enablePerfOverlay;
|
||||||
@ -577,6 +580,7 @@ public class PreferenceConfiguration {
|
|||||||
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
|
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
|
||||||
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
|
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
|
||||||
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);
|
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);
|
||||||
|
config.showGuideButton = prefs.getBoolean(SHOW_GUIDE_BUTTON_PREF_STRING, SHOW_GUIDE_BUTTON_DEFAULT);
|
||||||
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
|
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
|
||||||
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
|
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
|
||||||
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
|
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
|
||||||
|
@ -511,29 +511,15 @@ public class StreamSettings extends Activity {
|
|||||||
// Never remove 720p
|
// Never remove 720p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
else {
|
||||||
// On Android 4.2 and later, we can get the true metrics via the
|
// We can get the true metrics via the getRealMetrics() function (unlike the lies
|
||||||
// getRealMetrics() function (unlike the lies that getWidth() and getHeight()
|
// that getWidth() and getHeight() tell to us).
|
||||||
// tell to us).
|
|
||||||
DisplayMetrics metrics = new DisplayMetrics();
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
display.getRealMetrics(metrics);
|
display.getRealMetrics(metrics);
|
||||||
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
||||||
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||||
addNativeResolutionEntries(width, height, false);
|
addNativeResolutionEntries(width, height, false);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
|
|
||||||
// to get the real screen dimensions.
|
|
||||||
try {
|
|
||||||
Method getRawHeightFunc = Display.class.getMethod("getRawHeight");
|
|
||||||
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
|
|
||||||
int width = (Integer) getRawWidthFunc.invoke(display);
|
|
||||||
int height = (Integer) getRawHeightFunc.invoke(display);
|
|
||||||
addNativeResolutionEntries(Math.max(width, height), Math.min(width, height), false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
||||||
// We give some extra room in case the FPS is rounded down
|
// We give some extra room in case the FPS is rounded down
|
||||||
@ -562,49 +548,29 @@ public class StreamSettings extends Activity {
|
|||||||
}
|
}
|
||||||
addNativeFrameRateEntry(maxSupportedFps);
|
addNativeFrameRateEntry(maxSupportedFps);
|
||||||
|
|
||||||
// Android L introduces proper 7.1 surround sound support. Remove the 7.1 option
|
|
||||||
// for earlier versions of Android to prevent AudioTrack initialization issues.
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
LimeLog.info("Excluding 7.1 surround sound option based on OS");
|
|
||||||
removeValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "71", new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
setValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "51");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Android L introduces the drop duplicate behavior of releaseOutputBuffer()
|
// Android L introduces the drop duplicate behavior of releaseOutputBuffer()
|
||||||
// that the unlock FPS option relies on to not massively increase latency.
|
// that the unlock FPS option relies on to not massively increase latency.
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
LimeLog.info("Excluding unlock FPS toggle based on OS");
|
@Override
|
||||||
PreferenceCategory category =
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
(PreferenceCategory) findPreference("category_advanced_settings");
|
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
||||||
category.removePreference(findPreference("checkbox_unlock_fps"));
|
// it's reflected in the new layout.
|
||||||
}
|
final Handler h = new Handler();
|
||||||
else {
|
h.postDelayed(new Runnable() {
|
||||||
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
// Ensure the activity is still open when this timeout expires
|
||||||
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
StreamSettings settingsActivity = (StreamSettings) SettingsFragment.this.getActivity();
|
||||||
// it's reflected in the new layout.
|
if (settingsActivity != null) {
|
||||||
final Handler h = new Handler();
|
settingsActivity.reloadSettings();
|
||||||
h.postDelayed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Ensure the activity is still open when this timeout expires
|
|
||||||
StreamSettings settingsActivity = (StreamSettings)SettingsFragment.this.getActivity();
|
|
||||||
if (settingsActivity != null) {
|
|
||||||
settingsActivity.reloadSettings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
// Allow the original preference change to take place
|
// Allow the original preference change to take place
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Remove HDR preference for devices below Nougat
|
// Remove HDR preference for devices below Nougat
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||||
@ -623,6 +589,7 @@ public class StreamSettings extends Activity {
|
|||||||
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
|
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
|
||||||
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
|
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
|
||||||
foundHdr10 = true;
|
foundHdr10 = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ public class WebLauncherPreference extends Preference {
|
|||||||
initialize(attrs);
|
initialize(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
initialize(attrs);
|
initialize(attrs);
|
||||||
|
@ -30,6 +30,6 @@ public class AdapterFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
callbacks.receiveAbsListView((AbsListView) getView().findViewById(R.id.fragmentView));
|
callbacks.receiveAbsListView(getView().findViewById(R.id.fragmentView));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ public class StreamView extends SurfaceView {
|
|||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(21)
|
|
||||||
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public class NetHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||||
if (activeNetworkInfo != null) {
|
if (activeNetworkInfo != null) {
|
||||||
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_VPN;
|
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_VPN;
|
||||||
|
@ -2,15 +2,12 @@ package com.limelight.utils;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
import android.content.pm.ShortcutManager;
|
import android.content.pm.ShortcutManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.limelight.AppView;
|
|
||||||
import com.limelight.ShortcutTrampoline;
|
|
||||||
import com.limelight.R;
|
import com.limelight.R;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
# Application.mk for Moonlight
|
# Application.mk for Moonlight
|
||||||
|
|
||||||
# Our minimum version is Android 4.1
|
# Our minimum version is Android 5.0
|
||||||
APP_PLATFORM := android-16
|
APP_PLATFORM := android-21
|
||||||
|
|
||||||
|
# We support 16KB pages
|
||||||
|
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||||
|
@ -58,6 +58,8 @@ LOCAL_LDLIBS := -llog
|
|||||||
LOCAL_STATIC_LIBRARIES := libopus libssl libcrypto cpufeatures
|
LOCAL_STATIC_LIBRARIES := libopus libssl libcrypto cpufeatures
|
||||||
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
||||||
|
|
||||||
|
LOCAL_BRANCH_PROTECTION := standard
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
$(call import-module,android/cpufeatures)
|
$(call import-module,android/cpufeatures)
|
1
app/src/main/jni/moonlight-core/Build.txt
Normal file
1
app/src/main/jni/moonlight-core/Build.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Static libraries were built from https://github.com/cgutman/moonlight-mobile-deps using AppVeyor CI
|
Binary file not shown.
Binary file not shown.
@ -1,100 +0,0 @@
|
|||||||
ANDROID_API_TARGET=21
|
|
||||||
PARALLEL_JOBS=$(nproc)
|
|
||||||
|
|
||||||
rm -r ./android
|
|
||||||
mkdir android
|
|
||||||
|
|
||||||
function build_one
|
|
||||||
{
|
|
||||||
PREFIX=$(pwd)/android/$CPU
|
|
||||||
SYSROOT=$NDK/platforms/android-$ANDROID_API_TARGET/arch-$SYSROOT_CPU
|
|
||||||
TOOLCHAIN_PATH=$NDK/toolchains/$TOOLCHAIN_DIR/prebuilt/linux-x86_64
|
|
||||||
export PATH=$PATH:$TOOLCHAIN_PATH/bin
|
|
||||||
./configure \
|
|
||||||
--build=x86_64-unknown-linux-gnu \
|
|
||||||
--host=$TOOLCHAIN_BIN_PREFIX \
|
|
||||||
--target=$TOOLCHAIN_BIN_PREFIX \
|
|
||||||
CFLAGS="--sysroot=$SYSROOT -O2 $ADDI_CFLAGS" \
|
|
||||||
$ADDI_CONFIGURE_FLAGS
|
|
||||||
make clean
|
|
||||||
make -j$PARALLEL_JOBS
|
|
||||||
mkdir android/$CPU
|
|
||||||
cp .libs/libopus.a android/$CPU
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_mips
|
|
||||||
{
|
|
||||||
CPU=mips
|
|
||||||
SYSROOT_CPU=mips
|
|
||||||
TOOLCHAIN_BIN_PREFIX=mipsel-linux-android
|
|
||||||
TOOLCHAIN_DIR=mipsel-linux-android-4.9
|
|
||||||
ADDI_CFLAGS="-mips32 -mhard-float -EL -mno-dsp"
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_mips64
|
|
||||||
{
|
|
||||||
CPU=mips64
|
|
||||||
SYSROOT_CPU=mips64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=mips64el-linux-android
|
|
||||||
TOOLCHAIN_DIR=mips64el-linux-android-4.9
|
|
||||||
ADDI_CFLAGS="-mips64r6"
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_x86
|
|
||||||
{
|
|
||||||
CPU=x86
|
|
||||||
SYSROOT_CPU=x86
|
|
||||||
TOOLCHAIN_BIN_PREFIX=i686-linux-android
|
|
||||||
TOOLCHAIN_DIR=x86-4.9
|
|
||||||
ADDI_CFLAGS="-march=i686 -mtune=atom -mstackrealign -msse -msse2 -msse3 -mssse3 -mfpmath=sse -m32"
|
|
||||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_x86_64
|
|
||||||
{
|
|
||||||
CPU=x86_64
|
|
||||||
SYSROOT_CPU=x86_64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=x86_64-linux-android
|
|
||||||
TOOLCHAIN_DIR=x86_64-4.9
|
|
||||||
ADDI_CFLAGS="-msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mpopcnt -m64"
|
|
||||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_armv7
|
|
||||||
{
|
|
||||||
CPU=arm
|
|
||||||
SYSROOT_CPU=arm
|
|
||||||
TOOLCHAIN_BIN_PREFIX=arm-linux-androideabi
|
|
||||||
TOOLCHAIN_DIR=arm-linux-androideabi-4.9
|
|
||||||
ADDI_CFLAGS="-marm -mfpu=vfpv3-d16"
|
|
||||||
ADDI_LDFLAGS=""
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point for NEON, EDSP, Media
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
# ARMv8 doesn't currently have assembly in the opus project. We still use fixed point
|
|
||||||
# anyway in the hopes that it will be more performant even without assembly.
|
|
||||||
function build_armv8
|
|
||||||
{
|
|
||||||
CPU=aarch64
|
|
||||||
SYSROOT_CPU=arm64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=aarch64-linux-android
|
|
||||||
TOOLCHAIN_DIR=aarch64-linux-android-4.9
|
|
||||||
ADDI_CFLAGS=""
|
|
||||||
ADDI_LDFLAGS=""
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point"
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
build_mips
|
|
||||||
build_mips64
|
|
||||||
build_x86
|
|
||||||
build_x86_64
|
|
||||||
build_armv7
|
|
||||||
build_armv8
|
|
@ -103,7 +103,7 @@ extern "C" {
|
|||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
|
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
|
||||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
* future versions of this code may change the size, so no assumptions should be made about it.
|
||||||
*
|
*
|
||||||
* The encoder state is always continuous in memory and only a shallow copy is sufficient
|
* The encoder state is always continuous in memory and only a shallow copy is sufficient
|
||||||
* to copy it (e.g. memcpy())
|
* to copy it (e.g. memcpy())
|
||||||
@ -198,7 +198,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
|
|||||||
* This must be one of 8000, 12000, 16000,
|
* This must be one of 8000, 12000, 16000,
|
||||||
* 24000, or 48000.
|
* 24000, or 48000.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||||
* @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
* @param [in] application <tt>int</tt>: Coding mode (one of @ref OPUS_APPLICATION_VOIP, @ref OPUS_APPLICATION_AUDIO, or @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||||
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
|
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
|
||||||
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
|
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
|
||||||
* can switch to a lower audio bandwidth or number of channels if the bitrate
|
* can switch to a lower audio bandwidth or number of channels if the bitrate
|
||||||
@ -222,7 +222,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
|
|||||||
* This must be one of 8000, 12000, 16000,
|
* This must be one of 8000, 12000, 16000,
|
||||||
* 24000, or 48000.
|
* 24000, or 48000.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||||
* @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
* @param [in] application <tt>int</tt>: Coding mode (one of OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, or OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||||
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
||||||
*/
|
*/
|
||||||
OPUS_EXPORT int opus_encoder_init(
|
OPUS_EXPORT int opus_encoder_init(
|
||||||
@ -357,7 +357,7 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
* error = opus_decoder_init(dec, Fs, channels);
|
* error = opus_decoder_init(dec, Fs, channels);
|
||||||
* @endcode
|
* @endcode
|
||||||
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
|
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
|
||||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
* future versions of this code may change the size, so no assumptions should be made about it.
|
||||||
*
|
*
|
||||||
* The decoder state is always continuous in memory and only a shallow copy is sufficient
|
* The decoder state is always continuous in memory and only a shallow copy is sufficient
|
||||||
* to copy it (e.g. memcpy())
|
* to copy it (e.g. memcpy())
|
||||||
@ -398,6 +398,21 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
*/
|
*/
|
||||||
typedef struct OpusDecoder OpusDecoder;
|
typedef struct OpusDecoder OpusDecoder;
|
||||||
|
|
||||||
|
/** Opus DRED decoder.
|
||||||
|
* This contains the complete state of an Opus DRED decoder.
|
||||||
|
* It is position independent and can be freely copied.
|
||||||
|
* @see opus_dred_decoder_create,opus_dred_decoder_init
|
||||||
|
*/
|
||||||
|
typedef struct OpusDREDDecoder OpusDREDDecoder;
|
||||||
|
|
||||||
|
|
||||||
|
/** Opus DRED state.
|
||||||
|
* This contains the complete state of an Opus DRED packet.
|
||||||
|
* It is position independent and can be freely copied.
|
||||||
|
* @see opus_dred_create,opus_dred_init
|
||||||
|
*/
|
||||||
|
typedef struct OpusDRED OpusDRED;
|
||||||
|
|
||||||
/** Gets the size of an <code>OpusDecoder</code> structure.
|
/** Gets the size of an <code>OpusDecoder</code> structure.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels.
|
* @param [in] channels <tt>int</tt>: Number of channels.
|
||||||
* This must be 1 or 2.
|
* This must be 1 or 2.
|
||||||
@ -511,6 +526,101 @@ OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
*/
|
*/
|
||||||
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
|
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
|
||||||
|
|
||||||
|
/** Gets the size of an <code>OpusDREDDecoder</code> structure.
|
||||||
|
* @returns The size in bytes.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_get_size(void);
|
||||||
|
|
||||||
|
/** Allocates and initializes an OpusDREDDecoder state.
|
||||||
|
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OpusDREDDecoder *opus_dred_decoder_create(int *error);
|
||||||
|
|
||||||
|
/** Initializes an <code>OpusDREDDecoder</code> state.
|
||||||
|
* @param[in] dec <tt>OpusDREDDecoder*</tt>: State to be initialized.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_init(OpusDREDDecoder *dec);
|
||||||
|
|
||||||
|
/** Frees an <code>OpusDREDDecoder</code> allocated by opus_dred_decoder_create().
|
||||||
|
* @param[in] dec <tt>OpusDREDDecoder*</tt>: State to be freed.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT void opus_dred_decoder_destroy(OpusDREDDecoder *dec);
|
||||||
|
|
||||||
|
/** Perform a CTL function on an Opus DRED decoder.
|
||||||
|
*
|
||||||
|
* Generally the request and subsequent arguments are generated
|
||||||
|
* by a convenience macro.
|
||||||
|
* @param dred_dec <tt>OpusDREDDecoder*</tt>: DRED Decoder state.
|
||||||
|
* @param request This and all remaining parameters should be replaced by one
|
||||||
|
* of the convenience macros in @ref opus_genericctls or
|
||||||
|
* @ref opus_decoderctls.
|
||||||
|
* @see opus_genericctls
|
||||||
|
* @see opus_decoderctls
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_ctl(OpusDREDDecoder *dred_dec, int request, ...);
|
||||||
|
|
||||||
|
/** Gets the size of an <code>OpusDRED</code> structure.
|
||||||
|
* @returns The size in bytes.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_get_size(void);
|
||||||
|
|
||||||
|
/** Allocates and initializes a DRED state.
|
||||||
|
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OpusDRED *opus_dred_alloc(int *error);
|
||||||
|
|
||||||
|
/** Frees an <code>OpusDRED</code> allocated by opus_dred_create().
|
||||||
|
* @param[in] dec <tt>OpusDRED*</tt>: State to be freed.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT void opus_dred_free(OpusDRED *dec);
|
||||||
|
|
||||||
|
/** Decode an Opus DRED packet.
|
||||||
|
* @param [in] dred_dec <tt>OpusDRED*</tt>: DRED Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] data <tt>char*</tt>: Input payload
|
||||||
|
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
|
||||||
|
* @param [in] max_dred_samples <tt>opus_int32</tt>: Maximum number of DRED samples that may be needed (if available in the packet).
|
||||||
|
* @param [in] sampling_rate <tt>opus_int32</tt>: Sampling rate used for max_dred_samples argument. Needs not match the actual sampling rate of the decoder.
|
||||||
|
* @param [out] dred_end <tt>opus_int32*</tt>: Number of non-encoded (silence) samples between the DRED timestamp and the last DRED sample.
|
||||||
|
* @param [in] defer_processing <tt>int</tt>: Flag (0 or 1). If set to one, the CPU-intensive part of the DRED decoding is deferred until opus_dred_process() is called.
|
||||||
|
* @returns Offset (positive) of the first decoded DRED samples, zero if no DRED is present, or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_parse(OpusDREDDecoder *dred_dec, OpusDRED *dred, const unsigned char *data, opus_int32 len, opus_int32 max_dred_samples, opus_int32 sampling_rate, int *dred_end, int defer_processing) OPUS_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/** Finish decoding an Opus DRED packet. The function only needs to be called if opus_dred_parse() was called with defer_processing=1.
|
||||||
|
* The source and destination will often be the same DRED state.
|
||||||
|
* @param [in] dred_dec <tt>OpusDRED*</tt>: DRED Decoder state
|
||||||
|
* @param [in] src <tt>OpusDRED*</tt>: Source DRED state to start the processing from.
|
||||||
|
* @param [out] dst <tt>OpusDRED*</tt>: Destination DRED state to store the updated state after processing.
|
||||||
|
* @returns @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_process(OpusDREDDecoder *dred_dec, const OpusDRED *src, OpusDRED *dst);
|
||||||
|
|
||||||
|
/** Decode audio from an Opus DRED packet with floating point output.
|
||||||
|
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
|
||||||
|
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
||||||
|
* is frame_size*channels*sizeof(opus_int16)
|
||||||
|
* @param [in] frame_size Number of samples per channel to decode in \a pcm.
|
||||||
|
* frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||||
|
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_decoder_dred_decode(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size);
|
||||||
|
|
||||||
|
/** Decode audio from an Opus DRED packet with floating point output.
|
||||||
|
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
|
||||||
|
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
||||||
|
* is frame_size*channels*sizeof(float)
|
||||||
|
* @param [in] frame_size Number of samples per channel to decode in \a pcm.
|
||||||
|
* frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||||
|
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_decoder_dred_decode_float(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size);
|
||||||
|
|
||||||
|
|
||||||
/** Parse an opus packet into one or more frames.
|
/** Parse an opus packet into one or more frames.
|
||||||
* Opus_decode will perform this operation internally so most applications do
|
* Opus_decode will perform this operation internally so most applications do
|
||||||
* not need to use this function.
|
* not need to use this function.
|
||||||
@ -583,6 +693,14 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned
|
|||||||
*/
|
*/
|
||||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/** Checks whether an Opus packet has LBRR.
|
||||||
|
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||||
|
* @param [in] len <tt>opus_int32</tt>: Length of packet
|
||||||
|
* @returns 1 is LBRR is present, 0 otherwise
|
||||||
|
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len);
|
||||||
|
|
||||||
/** Gets the number of samples of an Opus packet.
|
/** Gets the number of samples of an Opus packet.
|
||||||
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
|
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
|
||||||
* @param [in] packet <tt>char*</tt>: Opus packet
|
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||||
|
@ -1,342 +0,0 @@
|
|||||||
/* Copyright (c) 2007-2008 CSIRO
|
|
||||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
|
||||||
Copyright (c) 2008-2012 Gregory Maxwell
|
|
||||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
|
||||||
/*
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
- Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
- Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
||||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@file opus_custom.h
|
|
||||||
@brief Opus-Custom reference implementation API
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPUS_CUSTOM_H
|
|
||||||
#define OPUS_CUSTOM_H
|
|
||||||
|
|
||||||
#include "opus_defines.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CUSTOM_MODES
|
|
||||||
# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
|
||||||
#else
|
|
||||||
# define OPUS_CUSTOM_EXPORT
|
|
||||||
# ifdef OPUS_BUILD
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
|
|
||||||
# else
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @defgroup opus_custom Opus Custom
|
|
||||||
* @{
|
|
||||||
* Opus Custom is an optional part of the Opus specification and
|
|
||||||
* reference implementation which uses a distinct API from the regular
|
|
||||||
* API and supports frame sizes that are not normally supported.\ Use
|
|
||||||
* of Opus Custom is discouraged for all but very special applications
|
|
||||||
* for which a frame size different from 2.5, 5, 10, or 20 ms is needed
|
|
||||||
* (for either complexity or latency reasons) and where interoperability
|
|
||||||
* is less important.
|
|
||||||
*
|
|
||||||
* In addition to the interoperability limitations the use of Opus custom
|
|
||||||
* disables a substantial chunk of the codec and generally lowers the
|
|
||||||
* quality available at a given bitrate. Normally when an application needs
|
|
||||||
* a different frame size from the codec it should buffer to match the
|
|
||||||
* sizes but this adds a small amount of delay which may be important
|
|
||||||
* in some very low latency applications. Some transports (especially
|
|
||||||
* constant rate RF transports) may also work best with frames of
|
|
||||||
* particular durations.
|
|
||||||
*
|
|
||||||
* Libopus only supports custom modes if they are enabled at compile time.
|
|
||||||
*
|
|
||||||
* The Opus Custom API is similar to the regular API but the
|
|
||||||
* @ref opus_encoder_create and @ref opus_decoder_create calls take
|
|
||||||
* an additional mode parameter which is a structure produced by
|
|
||||||
* a call to @ref opus_custom_mode_create. Both the encoder and decoder
|
|
||||||
* must create a mode using the same sample rate (fs) and frame size
|
|
||||||
* (frame size) so these parameters must either be signaled out of band
|
|
||||||
* or fixed in a particular implementation.
|
|
||||||
*
|
|
||||||
* Similar to regular Opus the custom modes support on the fly frame size
|
|
||||||
* switching, but the sizes available depend on the particular frame size in
|
|
||||||
* use. For some initial frame sizes on a single on the fly size is available.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Contains the state of an encoder. One encoder state is needed
|
|
||||||
for each stream. It is initialized once at the beginning of the
|
|
||||||
stream. Do *not* re-initialize the state for every frame.
|
|
||||||
@brief Encoder state
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
|
||||||
|
|
||||||
/** State of the decoder. One decoder state is needed for each stream.
|
|
||||||
It is initialized once at the beginning of the stream. Do *not*
|
|
||||||
re-initialize the state for every frame.
|
|
||||||
@brief Decoder state
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
|
||||||
|
|
||||||
/** The mode contains all the information necessary to create an
|
|
||||||
encoder. Both the encoder and decoder need to be initialized
|
|
||||||
with exactly the same mode, otherwise the output will be
|
|
||||||
corrupted.
|
|
||||||
@brief Mode configuration
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomMode OpusCustomMode;
|
|
||||||
|
|
||||||
/** Creates a new mode struct. This will be passed to an encoder or
|
|
||||||
* decoder. The mode MUST NOT BE DESTROYED until the encoders and
|
|
||||||
* decoders that use it are destroyed as well.
|
|
||||||
* @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
|
|
||||||
* packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
|
|
||||||
* @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
|
|
||||||
* @return A newly created mode
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
|
|
||||||
|
|
||||||
/** Destroys a mode struct. Only call this after all encoders and
|
|
||||||
* decoders using this mode are destroyed as well.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
|
|
||||||
|
|
||||||
/* Encoder */
|
|
||||||
/** Gets the size of an OpusCustomEncoder structure.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @returns size
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
# ifdef CUSTOM_MODES
|
|
||||||
/** Initializes a previously allocated encoder state
|
|
||||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
|
||||||
* This is intended for applications which use their own allocator instead of malloc.
|
|
||||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
|
||||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* decoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates a new encoder state. Each stream needs its own encoder
|
|
||||||
* state (can't be shared across simultaneous streams).
|
|
||||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* decoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
|
||||||
* @return Newly created encoder state.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels,
|
|
||||||
int *error
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
|
|
||||||
/** Destroys a an encoder state.
|
|
||||||
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
|
|
||||||
|
|
||||||
/** Encodes a frame of audio.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
|
|
||||||
* Samples with a range beyond +/-1.0 are supported but will
|
|
||||||
* be clipped by decoders using the integer API and should
|
|
||||||
* only be used if it is known that the far end supports
|
|
||||||
* extended dynamic range. There must be exactly
|
|
||||||
* frame_size samples per channel.
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
|
||||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
|
||||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
|
||||||
* (can change from one frame to another)
|
|
||||||
* @return Number of bytes written to "compressed".
|
|
||||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
|
||||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
|
||||||
* decoding is possible.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const float *pcm,
|
|
||||||
int frame_size,
|
|
||||||
unsigned char *compressed,
|
|
||||||
int maxCompressedBytes
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Encodes a frame of audio.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
|
|
||||||
* There must be exactly frame_size samples per channel.
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
|
||||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
|
||||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
|
||||||
* (can change from one frame to another)
|
|
||||||
* @return Number of bytes written to "compressed".
|
|
||||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
|
||||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
|
||||||
* decoding is possible.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const opus_int16 *pcm,
|
|
||||||
int frame_size,
|
|
||||||
unsigned char *compressed,
|
|
||||||
int maxCompressedBytes
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Perform a CTL function on an Opus custom encoder.
|
|
||||||
*
|
|
||||||
* Generally the request and subsequent arguments are generated
|
|
||||||
* by a convenience macro.
|
|
||||||
* @see opus_encoderctls
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
|
|
||||||
/* Decoder */
|
|
||||||
|
|
||||||
/** Gets the size of an OpusCustomDecoder structure.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @returns size
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Initializes a previously allocated decoder state
|
|
||||||
* The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
|
|
||||||
* This is intended for applications which use their own allocator instead of malloc.
|
|
||||||
* @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
|
|
||||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* encoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
|
||||||
* be shared across simultaneous streams).
|
|
||||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
|
||||||
* stream (must be the same characteristics as used for the encoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
|
||||||
* @return Newly created decoder state.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels,
|
|
||||||
int *error
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Destroys a an decoder state.
|
|
||||||
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
|
|
||||||
|
|
||||||
/** Decode an opus custom frame with floating point output
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
|
||||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
|
||||||
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
|
||||||
* is frame_size*channels*sizeof(float)
|
|
||||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
|
||||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const unsigned char *data,
|
|
||||||
int len,
|
|
||||||
float *pcm,
|
|
||||||
int frame_size
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Decode an opus custom frame
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
|
||||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
|
||||||
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
|
||||||
* is frame_size*channels*sizeof(opus_int16)
|
|
||||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
|
||||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const unsigned char *data,
|
|
||||||
int len,
|
|
||||||
opus_int16 *pcm,
|
|
||||||
int frame_size
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Perform a CTL function on an Opus custom decoder.
|
|
||||||
*
|
|
||||||
* Generally the request and subsequent arguments are generated
|
|
||||||
* by a convenience macro.
|
|
||||||
* @see opus_genericctls
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/**@}*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* OPUS_CUSTOM_H */
|
|
@ -64,7 +64,7 @@ extern "C" {
|
|||||||
/**Export control for opus functions */
|
/**Export control for opus functions */
|
||||||
|
|
||||||
#ifndef OPUS_EXPORT
|
#ifndef OPUS_EXPORT
|
||||||
# if defined(WIN32)
|
# if defined(_WIN32)
|
||||||
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
|
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
|
||||||
# define OPUS_EXPORT __declspec(dllexport)
|
# define OPUS_EXPORT __declspec(dllexport)
|
||||||
# else
|
# else
|
||||||
@ -168,15 +168,33 @@ extern "C" {
|
|||||||
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
||||||
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
|
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
|
||||||
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
|
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
|
||||||
|
#define OPUS_GET_IN_DTX_REQUEST 4049
|
||||||
|
#define OPUS_SET_DRED_DURATION_REQUEST 4050
|
||||||
|
#define OPUS_GET_DRED_DURATION_REQUEST 4051
|
||||||
|
#define OPUS_SET_DNN_BLOB_REQUEST 4052
|
||||||
|
/*#define OPUS_GET_DNN_BLOB_REQUEST 4053 */
|
||||||
|
|
||||||
/** Defines for the presence of extended APIs. */
|
/** Defines for the presence of extended APIs. */
|
||||||
#define OPUS_HAVE_OPUS_PROJECTION_H
|
#define OPUS_HAVE_OPUS_PROJECTION_H
|
||||||
|
|
||||||
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
||||||
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
||||||
|
|
||||||
|
#ifdef DISABLE_PTR_CHECK
|
||||||
|
/* Disable checks to prevent ubsan from complaining about NULL checks
|
||||||
|
in test_opus_api. */
|
||||||
|
#define __opus_check_int_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_uint_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_uint8_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_val16_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_void_ptr(ptr) (ptr)
|
||||||
|
#else
|
||||||
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
|
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
|
||||||
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
|
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
|
||||||
|
#define __opus_check_uint8_ptr(ptr) ((ptr) + ((ptr) - (opus_uint8*)(ptr)))
|
||||||
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
|
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
|
||||||
|
#define __opus_check_void_ptr(x) ((void)((void *)0 == (x)), (x))
|
||||||
|
#endif
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
|
||||||
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
|
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
|
||||||
@ -481,7 +499,8 @@ extern "C" {
|
|||||||
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
||||||
* <dl>
|
* <dl>
|
||||||
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
|
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
|
||||||
* <dt>1</dt><dd>Enable inband FEC.</dd>
|
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
|
||||||
|
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
|
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
|
||||||
@ -490,7 +509,8 @@ extern "C" {
|
|||||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||||
* <dl>
|
* <dl>
|
||||||
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
|
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
|
||||||
* <dt>1</dt><dd>Inband FEC enabled.</dd>
|
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
|
||||||
|
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
|
||||||
@ -617,6 +637,18 @@ extern "C" {
|
|||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
|
/** If non-zero, enables Deep Redundancy (DRED) and use the specified maximum number of 10-ms redundant frames
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_SET_DRED_DURATION(x) OPUS_SET_DRED_DURATION_REQUEST, __opus_check_int(x)
|
||||||
|
/** Gets the encoder's configured Deep Redundancy (DRED) maximum number of frames.
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_GET_DRED_DURATION(x) OPUS_GET_DRED_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
|
/** Provide external DNN weights from binary object (only when explicitly built without the weights)
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_SET_DNN_BLOB(data, len) OPUS_SET_DNN_BLOB_REQUEST, __opus_check_void_ptr(data), __opus_check_int(len)
|
||||||
|
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
/** @defgroup opus_genericctls Generic CTLs
|
/** @defgroup opus_genericctls Generic CTLs
|
||||||
@ -715,6 +747,16 @@ extern "C" {
|
|||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
/** Gets the DTX state of the encoder.
|
||||||
|
* Returns whether the last encoded frame was either a comfort noise update
|
||||||
|
* during DTX or not encoded because of DTX.
|
||||||
|
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||||
|
* <dl>
|
||||||
|
* <dt>0</dt><dd>The encoder is not in DTX.</dd>
|
||||||
|
* <dt>1</dt><dd>The encoder is in DTX.</dd>
|
||||||
|
* </dl>
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ extern "C" {
|
|||||||
* <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
|
* <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
|
||||||
* channel ordering</a>. A decoder may wish to apply an additional permutation
|
* channel ordering</a>. A decoder may wish to apply an additional permutation
|
||||||
* to the mapping the encoder used to achieve a different output channel
|
* to the mapping the encoder used to achieve a different output channel
|
||||||
* order (e.g. for outputing in WAV order).
|
* order (e.g. for outputting in WAV order).
|
||||||
*
|
*
|
||||||
* Each multistream packet contains an Opus packet for each stream, and all of
|
* Each multistream packet contains an Opus packet for each stream, and all of
|
||||||
* the Opus packets in a single multistream packet must have the same
|
* the Opus packets in a single multistream packet must have the same
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -209,6 +209,8 @@
|
|||||||
<string name="summary_checkbox_vibrate_osc">Vibrates your device to emulate rumble for the on-screen controls</string>
|
<string name="summary_checkbox_vibrate_osc">Vibrates your device to emulate rumble for the on-screen controls</string>
|
||||||
<string name="title_only_l3r3">Only show L3 and R3</string>
|
<string name="title_only_l3r3">Only show L3 and R3</string>
|
||||||
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
||||||
|
<string name="title_show_guide_button">Show Guide Button</string>
|
||||||
|
<string name="summary_show_guide_button">Show the guide button on screen</string>
|
||||||
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
||||||
<string name="summary_reset_osc">Resets all on-screen controls to their default size and position</string>
|
<string name="summary_reset_osc">Resets all on-screen controls to their default size and position</string>
|
||||||
<string name="dialog_title_reset_osc">Reset Layout</string>
|
<string name="dialog_title_reset_osc">Reset Layout</string>
|
||||||
|
@ -164,6 +164,14 @@
|
|||||||
android:key="checkbox_only_show_L3R3"
|
android:key="checkbox_only_show_L3R3"
|
||||||
android:summary="@string/summary_only_l3r3"
|
android:summary="@string/summary_only_l3r3"
|
||||||
android:title="@string/title_only_l3r3" />
|
android:title="@string/title_only_l3r3" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
|
android:key="checkbox_show_guide_button"
|
||||||
|
android:summary="@string/summary_show_guide_button"
|
||||||
|
android:title="@string/title_show_guide_button" />
|
||||||
<com.limelight.preferences.SeekBarPreference
|
<com.limelight.preferences.SeekBarPreference
|
||||||
android:key="seekbar_osc_opacity"
|
android:key="seekbar_osc_opacity"
|
||||||
android:dependency="checkbox_show_onscreen_controls"
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.2.2'
|
classpath 'com.android.tools.build:gradle:8.5.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
Loading…
x
Reference in New Issue
Block a user