diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 639681c..27bbb3e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -58,6 +58,7 @@ dependencies { implementation(libs.material) implementation(libs.constraintlayout) implementation(libs.lifecycle.runtime.ktx) + implementation(libs.preference) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 399f267..d8a95ea 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,19 +1,17 @@ - - - + android:required="false" /> + @@ -38,6 +37,15 @@ android:name="android.app.lib_name" android:value="" /> + + + + \ No newline at end of file diff --git a/app/src/main/java/io/github/thibaultbee/streampack/app/MainActivity.kt b/app/src/main/java/io/github/thibaultbee/streampack/app/MainActivity.kt index a39f3f6..ea22c98 100644 --- a/app/src/main/java/io/github/thibaultbee/streampack/app/MainActivity.kt +++ b/app/src/main/java/io/github/thibaultbee/streampack/app/MainActivity.kt @@ -2,19 +2,23 @@ package io.github.thibaultbee.streampack.app import android.Manifest import android.annotation.SuppressLint +import android.content.Intent import android.content.pm.ActivityInfo import android.os.Bundle import android.util.Log +import android.view.WindowManager.LayoutParams +import androidx.activity.result.ActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.annotation.RequiresPermission import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import io.github.thibaultbee.streampack.app.databinding.ActivityMainBinding -import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.defaultCameraId -import io.github.thibaultbee.streampack.core.streamers.lifecycle.StreamerActivityLifeCycleObserver import io.github.thibaultbee.streampack.app.utils.PermissionsManager import io.github.thibaultbee.streampack.app.utils.showDialog import io.github.thibaultbee.streampack.app.utils.toast +import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.defaultCameraId +import io.github.thibaultbee.streampack.core.streamers.lifecycle.StreamerActivityLifeCycleObserver import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { @@ -70,6 +74,24 @@ class MainActivity : AppCompatActivity() { } private fun bindProperties() { + + + val getContent = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) + { + val streamResolution = SettingsActivity.getResolution(applicationContext) + val (w, h) = streamResolution.split("|").map { it.toInt() }.let { it[0] to it[1] } + val streamBitrate = SettingsActivity.getBitrate(applicationContext) + + lifecycleScope.launch { + viewModel.setVideoConfig(w, h, streamBitrate.toInt()) + } + } + + binding.settingsButton.setOnClickListener { view -> + val intent: Intent = Intent(this, SettingsActivity::class.java) + getContent.launch(intent) + } + binding.liveButton.setOnCheckedChangeListener { view, isChecked -> if (view.isPressed) { if (isChecked) { @@ -77,9 +99,13 @@ class MainActivity : AppCompatActivity() { * Dispatch from main thread is forced to avoid making network call on main thread * with coroutines. */ + // lifecycleScope.launch { + val streamUrl = SettingsActivity.getServer(applicationContext) + // } lifecycleScope.launch { try { - viewModel.startStream() + window.addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON) + viewModel.startStream(streamUrl) } catch (e: Exception) { binding.liveButton.isChecked = false Log.e(TAG, "Failed to connect", e) @@ -88,6 +114,7 @@ class MainActivity : AppCompatActivity() { } } else { lifecycleScope.launch { + window.clearFlags(LayoutParams.FLAG_KEEP_SCREEN_ON) viewModel.stopStream() } } @@ -197,4 +224,4 @@ class MainActivity : AppCompatActivity() { companion object { private const val TAG = "MainActivity" } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/github/thibaultbee/streampack/app/MainViewModel.kt b/app/src/main/java/io/github/thibaultbee/streampack/app/MainViewModel.kt index 9915382..bed36e6 100644 --- a/app/src/main/java/io/github/thibaultbee/streampack/app/MainViewModel.kt +++ b/app/src/main/java/io/github/thibaultbee/streampack/app/MainViewModel.kt @@ -1,31 +1,42 @@ package io.github.thibaultbee.streampack.app +import android.app.AlertDialog import android.Manifest +import android.content.DialogInterface import android.media.AudioFormat import android.media.MediaFormat +import android.text.InputType +import android.util.Log import android.util.Size +import android.widget.EditText import androidx.annotation.RequiresPermission +import androidx.core.content.ContentProviderCompat.requireContext import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import io.github.thibaultbee.streampack.app.data.rotation.RotationRepository +import io.github.thibaultbee.streampack.core.configuration.mediadescriptor.MediaDescriptor import io.github.thibaultbee.streampack.core.elements.sources.audio.audiorecord.MicrophoneSourceFactory +import io.github.thibaultbee.streampack.core.elements.sources.video.camera.ICameraSource import io.github.thibaultbee.streampack.core.interfaces.setCameraId import io.github.thibaultbee.streampack.core.interfaces.startStream +import io.github.thibaultbee.streampack.core.pipelines.inputs.IVideoInput import io.github.thibaultbee.streampack.core.streamers.single.AudioConfig import io.github.thibaultbee.streampack.core.streamers.single.SingleStreamer import io.github.thibaultbee.streampack.core.streamers.single.VideoConfig import io.github.thibaultbee.streampack.core.utils.extensions.isClosedException +import io.github.thibaultbee.streampack.ext.rtmp.configuration.mediadescriptor.RtmpMediaDescriptor import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch + class MainViewModel( private val rotationRepository: RotationRepository, - val streamer: SingleStreamer + val streamer: SingleStreamer, ) : ViewModel() { private val defaultDispatcher = Dispatchers.Default @@ -70,13 +81,13 @@ class MainViewModel( * * Replace with a valid URL. */ - suspend fun startStream() { + suspend fun startStream(streamUrl: String) { _isTryingConnectionLiveData.postValue(true) try { /** * For SRT, use srt://my.server.url:9998?streamid=myStreamId&passphrase=myPassphrase */ - streamer.startStream("rtmp://my.server.url:1935/app/streamKey") + streamer.startStream(streamUrl) } finally { _isTryingConnectionLiveData.postValue(false) } @@ -133,6 +144,27 @@ class MainViewModel( streamer.setVideoConfig(videoConfig) } + /** + * Sets the video configuration. + * + * You can verify the device supported configuration with [SingleStreamer.getInfo]. + */ + suspend fun setVideoConfig(w: Int, h: Int,fps: Int) { + /** + * There are other parameters in the [VideoConfig] such as: + * - bitrate + * - profile + * - level + * - gopSize + * They will be initialized with an appropriate default value. + */ + val videoConfig = VideoConfig( + mimeType = MediaFormat.MIMETYPE_VIDEO_AVC, resolution = Size(w, h), fps = fps + ) + + streamer.setVideoConfig(videoConfig) + } + /** * Sets the microphone as the audio source. */ diff --git a/app/src/main/java/io/github/thibaultbee/streampack/app/SettingsActivity.kt b/app/src/main/java/io/github/thibaultbee/streampack/app/SettingsActivity.kt new file mode 100644 index 0000000..be4863a --- /dev/null +++ b/app/src/main/java/io/github/thibaultbee/streampack/app/SettingsActivity.kt @@ -0,0 +1,42 @@ +package io.github.thibaultbee.streampack.app + +import android.content.Context +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.preference.EditTextPreference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager + +class SettingsActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + PreferenceManager.setDefaultValues(this, R.xml.root_preferences, false); + setContentView(R.layout.settings_activity) + if (savedInstanceState == null) { + supportFragmentManager + .beginTransaction() + .replace(R.id.settings, SettingsFragment()) + .commit() + } + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + + class SettingsFragment : PreferenceFragmentCompat() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.root_preferences, rootKey) + } + } + + companion object { + fun getServer(context: Context): String = + PreferenceManager.getDefaultSharedPreferences(context).getString("pref_server", "") ?: "" + + fun getResolution(context: Context): String = + PreferenceManager.getDefaultSharedPreferences(context).getString("pref_resolution", "") ?: "" + + fun getBitrate(context: Context): String = + PreferenceManager.getDefaultSharedPreferences(context).getString("pref_bitrate", "") ?: "" + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..872bb62 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 91f9aa5..29974ed 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -15,6 +15,21 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cf..345888d 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,6 @@ - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index eca70cf..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..9010873 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..97e223f Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..90bf9f3 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..694cfe1 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..cba2974 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d6..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..5efec9c Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e592021 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..5a37132 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp deleted file mode 100644 index 62b611d..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..8bdd411 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a307..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..e079f7e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..b4228a4 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..7e939c7 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a695..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..98dc885 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..15a245c Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4a56c4b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..3c8ec3d Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9287f50..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..ffd1dea Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d642..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..38d4718 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..598075f Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..de0a985 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9126ae3..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..9cfae81 --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,28 @@ + + + 480px360p + 720px480p + 1080px720p + + + 480|360 + 720|480 + 1080|720 + + + 1080|720 + + + 15 fps + 25 fps + 50 fps + + + 15 + 25 + 50 + + + 25 + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 29f88b4..64934e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,11 @@ - My Streaming App + Pico Streaming App Denied Accept + Settings + + + Server + Sync + \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml new file mode 100644 index 0000000..5224024 --- /dev/null +++ b/app/src/main/res/xml/root_preferences.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e97391f..c9174db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,7 @@ kotlin = "2.3.0" lifecycleRuntimeKtx = "2.10.0" material = "1.13.0" streampack = "3.1.1" +preference = "1.2.0" [libraries] appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } @@ -24,6 +25,7 @@ streampack-core = { group = "io.github.thibaultbee.streampack", name = "streampa streampack-ui = { group = "io.github.thibaultbee.streampack", name = "streampack-ui", version.ref = "streampack" } streampack-rtmp = { group = "io.github.thibaultbee.streampack", name = "streampack-rtmp", version.ref = "streampack" } streampack-srt = { group = "io.github.thibaultbee.streampack", name = "streampack-srt", version.ref = "streampack" } +preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }