diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index 27d477f..defbeba 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -148,6 +148,15 @@ JNIEXPORT jboolean JNICALL JNI_FCN(quitReasonIsStopped)(JNIEnv *env, jobject obj return value == CHIAKI_QUIT_REASON_STOPPED; } +JNIEXPORT jobject JNICALL JNI_FCN(videoProfilePreset)(JNIEnv *env, jobject obj, jint resolution_preset, jint fps_preset) +{ + ChiakiConnectVideoProfile profile = { 0 }; + chiaki_connect_video_profile_preset(&profile, (ChiakiVideoResolutionPreset)resolution_preset, (ChiakiVideoFPSPreset)fps_preset); + jclass profile_class = E->FindClass(env, BASE_PACKAGE"/ConnectVideoProfile"); + jmethodID profile_ctor = E->GetMethodID(env, profile_class, "", "(IIII)V"); + return E->NewObject(env, profile_class, profile_ctor, profile.width, profile.height, profile.max_fps, profile.bitrate); +} + typedef struct android_chiaki_session_t { ChiakiSession session; diff --git a/android/app/src/main/java/com/metallic/chiaki/TestStartActivity.kt b/android/app/src/main/java/com/metallic/chiaki/TestStartActivity.kt index 4392899..6c1e23c 100644 --- a/android/app/src/main/java/com/metallic/chiaki/TestStartActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/TestStartActivity.kt @@ -26,9 +26,9 @@ import android.view.Window import androidx.appcompat.app.AppCompatActivity import androidx.core.content.edit import androidx.core.widget.addTextChangedListener +import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.lib.ConnectInfo -import com.metallic.chiaki.lib.ConnectVideoProfile import com.metallic.chiaki.stream.StreamActivity import kotlinx.android.synthetic.main.activity_test_start.* @@ -75,7 +75,7 @@ class TestStartActivity : AppCompatActivity(), RevealActivity val connectInfo = ConnectInfo(hostEditText.text.toString(), registKey, morning, - ConnectVideoProfile(1280, 720, 60, 10000)) + Preferences(this).videoProfile) Intent(this, StreamActivity::class.java).let { it.putExtra(StreamActivity.EXTRA_CONNECT_INFO, connectInfo) diff --git a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt index 2805d3a..684ffc5 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt @@ -18,11 +18,17 @@ package com.metallic.chiaki.common import android.content.Context +import android.content.SharedPreferences import androidx.annotation.StringRes import androidx.preference.PreferenceManager import com.metallic.chiaki.R +import com.metallic.chiaki.lib.ConnectVideoProfile import com.metallic.chiaki.lib.VideoFPSPreset import com.metallic.chiaki.lib.VideoResolutionPreset +import io.reactivex.Observable +import io.reactivex.subjects.BehaviorSubject +import kotlin.math.max +import kotlin.math.min class Preferences(context: Context) { @@ -49,6 +55,13 @@ class Preferences(context: Context) } private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + when(key) + { + resolutionKey -> bitrateAutoSubject.onNext(bitrateAuto) + } + }.also { sharedPreferences.registerOnSharedPreferenceChangeListener(it) } + private val resources = context.resources val logVerboseKey get() = resources.getString(R.string.preferences_log_verbose_key) @@ -65,8 +78,26 @@ class Preferences(context: Context) val fpsKey get() = resources.getString(R.string.preferences_fps_key) var fps - get() =sharedPreferences.getString(fpsKey, fpsDefault.value)?.let { value -> + get() = sharedPreferences.getString(fpsKey, fpsDefault.value)?.let { value -> FPS.values().firstOrNull { it.value == value } } ?: fpsDefault set(value) { sharedPreferences.edit().putString(fpsKey, value.value).apply() } + + fun validateBitrate(bitrate: Int) = max(2000, min(50000, bitrate)) + val bitrateKey get() = resources.getString(R.string.preferences_bitrate_key) + var bitrate + get() = sharedPreferences.getInt(bitrateKey, 0).let { if(it == 0) null else validateBitrate(it) } + set(value) { sharedPreferences.edit().putInt(bitrateKey, if(value != null) validateBitrate(value) else 0).apply() } + val bitrateAuto get() = videoProfileDefaultBitrate.bitrate + private val bitrateAutoSubject by lazy { BehaviorSubject.createDefault(bitrateAuto) } + val bitrateAutoObservable: Observable get() = bitrateAutoSubject + + private val videoProfileDefaultBitrate get() = ConnectVideoProfile.preset(resolution.preset, fps.preset) + val videoProfile get() = videoProfileDefaultBitrate.let { + val bitrate = bitrate + if(bitrate == null) + it + else + ConnectVideoProfile(it.width, it.height, it.maxFPS, bitrate) + } } \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index 9a3afc6..cd84d83 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -29,6 +29,13 @@ data class ConnectVideoProfile( val maxFPS: Int, val bitrate: Int ): Parcelable +{ + companion object + { + fun preset(resolutionPreset: VideoResolutionPreset, fpsPreset: VideoFPSPreset) + = ChiakiNative.videoProfilePreset(resolutionPreset.value, fpsPreset.value) + } +} @Parcelize data class ConnectInfo( @@ -50,6 +57,7 @@ private class ChiakiNative @JvmStatic external fun errorCodeToString(value: Int): String @JvmStatic external fun quitReasonToString(value: Int): String @JvmStatic external fun quitReasonIsStopped(value: Int): Boolean + @JvmStatic external fun videoProfilePreset(resolutionPreset: Int, fpsPreset: Int): ConnectVideoProfile @JvmStatic external fun sessionCreate(result: CreateResult, connectInfo: ConnectInfo, javaSession: Session) @JvmStatic external fun sessionFree(ptr: Long) @JvmStatic external fun sessionStart(ptr: Long): Int diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt index 5ef7575..0d17e1f 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt @@ -19,11 +19,13 @@ package com.metallic.chiaki.settings import android.content.res.Resources import android.os.Bundle +import android.text.InputType import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.preference.* import com.metallic.chiaki.R import com.metallic.chiaki.common.Preferences +import com.metallic.chiaki.common.ext.toLiveData import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase @@ -47,6 +49,7 @@ class DataStore(val preferences: Preferences): PreferenceDataStore() { preferences.resolutionKey -> preferences.resolution.value preferences.fpsKey -> preferences.fps.value + preferences.bitrateKey -> preferences.bitrate?.toString() ?: "" else -> defValue } @@ -64,6 +67,7 @@ class DataStore(val preferences: Preferences): PreferenceDataStore() val fps = Preferences.FPS.values().firstOrNull { it.value == value } ?: return preferences.fps = fps } + preferences.bitrateKey -> preferences.bitrate = value?.toIntOrNull() } } } @@ -74,13 +78,14 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment { val context = context ?: return - val preferences = Preferences(context) + val viewModel = ViewModelProviders + .of(this, viewModelFactory { SettingsViewModel(getDatabase(context), Preferences(context)) }) + .get(SettingsViewModel::class.java) + + val preferences = viewModel.preferences preferenceManager.preferenceDataStore = DataStore(preferences) setPreferencesFromResource(R.xml.preferences, rootKey) - - val registeredHostsPreference = preferenceScreen.findPreference("registered_hosts") - preferenceScreen.findPreference(getString(R.string.preferences_resolution_key))?.let { it.entryValues = Preferences.resolutionAll.map { res -> res.value }.toTypedArray() it.entries = Preferences.resolutionAll.map { res -> getString(res.title) }.toTypedArray() @@ -91,13 +96,23 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment it.entries = Preferences.fpsAll.map { fps -> getString(fps.title) }.toTypedArray() } - val bitratePreference = preferenceScreen.findPreference("bitrate") - bitratePreference?.summaryProvider = Preference.SummaryProvider { it.text } - - val viewModel = ViewModelProviders - .of(this, viewModelFactory { SettingsViewModel(getDatabase(context!!)) }) - .get(SettingsViewModel::class.java) + val bitratePreference = preferenceScreen.findPreference(getString(R.string.preferences_bitrate_key)) + val bitrateSummaryProvider = Preference.SummaryProvider { + preferences.bitrate?.toString() ?: getString(R.string.preferences_bitrate_auto, preferences.bitrateAuto) + } + bitratePreference?.let { + it.summaryProvider = bitrateSummaryProvider + it.setOnBindEditTextListener { editText -> + editText.hint = getString(R.string.preferences_bitrate_auto, preferences.bitrateAuto) + editText.inputType = InputType.TYPE_CLASS_NUMBER + editText.setText(preferences.bitrate?.toString() ?: "") + } + } + viewModel.bitrateAuto.observe(this, Observer { + bitratePreference?.summaryProvider = bitrateSummaryProvider + }) + val registeredHostsPreference = preferenceScreen.findPreference("registered_hosts") viewModel.registeredHostsCount.observe(this, Observer { registeredHostsPreference?.summary = getString(R.string.preferences_registered_hosts_summary, it) }) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsViewModel.kt index f3578ee..e69662a 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsViewModel.kt @@ -19,11 +19,16 @@ package com.metallic.chiaki.settings import androidx.lifecycle.ViewModel import com.metallic.chiaki.common.AppDatabase +import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.common.ext.toLiveData -class SettingsViewModel(val database: AppDatabase): ViewModel() +class SettingsViewModel(val database: AppDatabase, val preferences: Preferences): ViewModel() { val registeredHostsCount by lazy { database.registeredHostDao().count().toLiveData() } + + val bitrateAuto by lazy { + preferences.bitrateAutoObservable.toLiveData() + } } \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 9d04c1e..9a0db76 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -60,4 +60,5 @@ 30 60 stream_bitrate + Auto (%d)