diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index b9a9df67..f4926e93 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -5,7 +5,9 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; public class PreferenceConfiguration { - static final String RES_FPS_PREF_STRING = "list_resolution_fps"; + static final String RESX_PREF_STRING = "resolution_x"; + static final String RESY_PREF_STRING = "resolution_y"; + private static final String FPS_PREF_STRING = "fps"; private static final String DECODER_PREF_STRING = "list_decoders"; static final String BITRATE_PREF_STRING = "seekbar_bitrate"; private static final String STRETCH_PREF_STRING = "checkbox_stretch_video"; @@ -21,10 +23,12 @@ public class PreferenceConfiguration { private static final int BITRATE_DEFAULT_720_60 = 10; private static final int BITRATE_DEFAULT_1080_30 = 10; private static final int BITRATE_DEFAULT_1080_60 = 20; + private static final int BITRATE_DEFAULT_MAX = 35; - private static final String DEFAULT_RES_FPS = "720p60"; + private static final int DEFAULT_RESX = 1280; + private static final int DEFAULT_RESY = 720; + private static final String DEFAULT_FPS = "60"; private static final String DEFAULT_DECODER = "auto"; - private static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60; private static final boolean DEFAULT_STRETCH = false; private static final boolean DEFAULT_SOPS = true; private static final boolean DEFAULT_DISABLE_TOASTS = false; @@ -45,49 +49,40 @@ public class PreferenceConfiguration { public String language; public boolean listMode, smallIconMode; - public static int getDefaultBitrate(String resFpsString) { - if (resFpsString.equals("720p30")) { - return BITRATE_DEFAULT_720_30; - } - else if (resFpsString.equals("720p60")) { - return BITRATE_DEFAULT_720_60; - } - else if (resFpsString.equals("1080p30")) { - return BITRATE_DEFAULT_1080_30; - } - else if (resFpsString.equals("1080p60")) { - return BITRATE_DEFAULT_1080_60; - } - else { - // Should never get here - return DEFAULT_BITRATE; - } - } - public static boolean getDefaultSmallMode(Context context) { // Use small mode on anything smaller than a 7" tablet return context.getResources().getConfiguration().smallestScreenWidthDp < 600; } + private static int getFpsInt(SharedPreferences prefs) { + try { + return Integer.parseInt(prefs.getString(FPS_PREF_STRING, DEFAULT_FPS)); + } catch (NumberFormatException e) { + return Integer.parseInt(DEFAULT_FPS); + } + } + public static int getDefaultBitrate(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS); - if (str.equals("720p30")) { + long width = prefs.getInt(RESX_PREF_STRING, DEFAULT_RESX); + long height = prefs.getInt(RESY_PREF_STRING, DEFAULT_RESY); + + long product = width * height * getFpsInt(prefs); + if (product <= 1280 * 720 * 30) { return BITRATE_DEFAULT_720_30; } - else if (str.equals("720p60")) { + else if (product <= 1280 * 720 * 60) { return BITRATE_DEFAULT_720_60; } - else if (str.equals("1080p30")) { + else if (product <= 1920 * 1080 * 30) { return BITRATE_DEFAULT_1080_30; } - else if (str.equals("1080p60")) { + else if (product <= 1920 * 1080 * 60) { return BITRATE_DEFAULT_1080_60; } else { - // Should never get here - return DEFAULT_BITRATE; + return BITRATE_DEFAULT_MAX; } } @@ -115,33 +110,9 @@ public class PreferenceConfiguration { PreferenceConfiguration config = new PreferenceConfiguration(); config.bitrate = prefs.getInt(BITRATE_PREF_STRING, getDefaultBitrate(context)); - String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS); - if (str.equals("720p30")) { - config.width = 1280; - config.height = 720; - config.fps = 30; - } - else if (str.equals("720p60")) { - config.width = 1280; - config.height = 720; - config.fps = 60; - } - else if (str.equals("1080p30")) { - config.width = 1920; - config.height = 1080; - config.fps = 30; - } - else if (str.equals("1080p60")) { - config.width = 1920; - config.height = 1080; - config.fps = 60; - } - else { - // Should never get here - config.width = 1280; - config.height = 720; - config.fps = 60; - } + config.width = prefs.getInt(RESX_PREF_STRING, DEFAULT_RESX); + config.height = prefs.getInt(RESY_PREF_STRING, DEFAULT_RESY); + config.fps = getFpsInt(prefs); config.decoder = getDecoderValue(context); diff --git a/app/src/main/java/com/limelight/preferences/ResolutionPreference.java b/app/src/main/java/com/limelight/preferences/ResolutionPreference.java new file mode 100644 index 00000000..3016f5de --- /dev/null +++ b/app/src/main/java/com/limelight/preferences/ResolutionPreference.java @@ -0,0 +1,208 @@ +package com.limelight.preferences; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.RadioButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import com.limelight.R; + +public class ResolutionPreference extends DialogPreference { + private RadioButton a4_3; + private RadioButton a16_9; + private RadioButton a16_10; + private SeekBar resolutionSeekBar; + private TextView resolutionText; + + private int resolutionX; + private int resolutionY; + + public ResolutionPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.dialog_resolution); + setPositiveButtonText(android.R.string.ok); + setNegativeButtonText(android.R.string.cancel); + + setDialogIcon(null); + } + + private int getPreferenceState() { + int checkboxState; + int sliderState; + + if (a4_3.isChecked()) { + checkboxState = 1; + } + else if (a16_10.isChecked()) { + checkboxState = 2; + } + else { + checkboxState = 0; + } + + sliderState = resolutionSeekBar.getProgress(); + + return checkboxState << 24 | sliderState; + } + + private void setPreferenceState(int state) { + int checkboxState; + int sliderState; + + checkboxState = state >> 24; + sliderState = state & 0x00FFFFFF; + + a4_3.setChecked(false); + a16_10.setChecked(false); + a16_9.setChecked(false); + + if (checkboxState == 1) { + a4_3.setChecked(true); + } + else if (checkboxState == 2) { + a16_10.setChecked(true); + } + else { + a16_9.setChecked(true); + } + + resolutionSeekBar.setProgress(sliderState); + } + + private void updateResolution() { + double aspectFactor; + int step = resolutionSeekBar.getProgress() + 1; + + if (a4_3.isChecked()) { + aspectFactor = 4.0/3.0; + + switch (step) { + case 1: + // 640x480 + resolutionY = 480; + break; + case 2: + // 800x600 + resolutionY = 600; + break; + case 3: + // 1024x768 + resolutionY = 768; + break; + case 4: + // 1600x1200 + resolutionY = 1200; + break; + } + } + else if (a16_9.isChecked()) { + aspectFactor = 16.0/9.0; + + switch (step) { + case 1: + // 1280x720 + resolutionY = 720; + break; + case 2: + // 1920x1080 + resolutionY = 1080; + break; + case 3: + // 2560x1440 + resolutionY = 1440; + break; + case 4: + // 3840x2160 + resolutionY = 2160; + break; + } + } + else /* if (a16_10.isChecked() */ { + aspectFactor = 16.0/10.0; + + switch (step) { + case 1: + // 1280x800 + resolutionY = 800; + break; + case 2: + // 1920x1200 + resolutionY = 1200; + break; + case 3: + // 2560x1600 + resolutionY = 1600; + break; + case 4: + // 3840x2400 + resolutionY = 2400; + break; + } + } + + resolutionX = (int)(resolutionY * aspectFactor); + + resolutionText.setText(resolutionX+"x"+resolutionY); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + SharedPreferences.Editor e = getPreferenceManager().getSharedPreferences().edit(); + e.putInt(PreferenceConfiguration.RESX_PREF_STRING, resolutionX); + e.putInt(PreferenceConfiguration.RESY_PREF_STRING, resolutionY); + persistInt(getPreferenceState()); + e.commit(); + } + } + + @Override + protected View onCreateDialogView() { + View v = super.onCreateDialogView(); + + a4_3 = (RadioButton) v.findViewById(R.id.aspect_4_3); + a16_9 = (RadioButton) v.findViewById(R.id.aspect_16_9); + a16_10 = (RadioButton) v.findViewById(R.id.aspect_16_10); + resolutionText = (TextView) v.findViewById(R.id.resolutionText); + resolutionSeekBar = (SeekBar) v.findViewById(R.id.resolutionSeekbar); + + CompoundButton.OnCheckedChangeListener ccListener = new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + updateResolution(); + } + }; + a4_3.setOnCheckedChangeListener(ccListener); + a16_9.setOnCheckedChangeListener(ccListener); + a16_10.setOnCheckedChangeListener(ccListener); + + resolutionSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + updateResolution(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + + // Check the correct checkbox + setPreferenceState(getPersistedInt(0)); + + // Set initial resolution value + updateResolution(); + + return v; + } +} diff --git a/app/src/main/java/com/limelight/preferences/StreamSettings.java b/app/src/main/java/com/limelight/preferences/StreamSettings.java index 47982480..983e486f 100644 --- a/app/src/main/java/com/limelight/preferences/StreamSettings.java +++ b/app/src/main/java/com/limelight/preferences/StreamSettings.java @@ -51,26 +51,6 @@ public class StreamSettings extends Activity { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); - - // Add a listener to the FPS and resolution preference - // so the bitrate can be auto-adjusted - Preference pref = findPreference(PreferenceConfiguration.RES_FPS_PREF_STRING); - pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity()); - String valueStr = (String) newValue; - - // Write the new bitrate value - prefs.edit() - .putInt(PreferenceConfiguration.BITRATE_PREF_STRING, - PreferenceConfiguration.getDefaultBitrate(valueStr)) - .apply(); - - // Allow the original preference change to take place - return true; - } - }); } } } diff --git a/app/src/main/res/layout/dialog_resolution.xml b/app/src/main/res/layout/dialog_resolution.xml new file mode 100644 index 00000000..d259596d --- /dev/null +++ b/app/src/main/res/layout/dialog_resolution.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 44a32405..415c09e1 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,16 +1,12 @@ - - 720p 30 FPS - 720p 60 FPS - 1080p 30 FPS - 1080p 60 FPS + + 30 FPS + 60 FPS - - 720p30 - 720p60 - 1080p30 - 1080p60 + + 30 + 60 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5258ef4..76aa5c8b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,8 +85,10 @@ Basic Settings - Select resolution and FPS target - Setting values too high for your device may cause lag or crashing + Select stream resolution + Some resolutions may not be supported on your device + Select target FPS + Some FPS values may not be supported with high resolutions on your device Select target video bitrate Lower bitrate to reduce stuttering. Raise bitrate to increase image quality. Mbps @@ -115,4 +117,9 @@ Advanced Settings Change decoder Software decoding may improve video latency at lower streaming settings + + + 4:3 + 16:9 + 16:10 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b56f0d15..83ade8ba 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -2,13 +2,17 @@ + + android:title="@string/title_fps_list" + android:summary="@string/summary_fps_list" + android:entries="@array/fps_names" + android:entryValues="@array/fps_values" + android:defaultValue="60" />