Manage instance live configuration: live enabled and allow replay

fixes #11
This commit is contained in:
Schoumi 2021-07-27 20:20:08 +02:00
parent 6031e37959
commit f9ea80bb3d
8 changed files with 149 additions and 23 deletions

View File

@ -5,21 +5,16 @@ import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ProgressBar
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.databinding.ChannelListBinding
import fr.mobdev.peertubelive.databinding.CreateLiveBinding
import fr.mobdev.peertubelive.manager.DatabaseManager
import fr.mobdev.peertubelive.manager.InstanceManager
import fr.mobdev.peertubelive.objects.ChannelData
import fr.mobdev.peertubelive.objects.OAuthData
import fr.mobdev.peertubelive.objects.StreamData
import fr.mobdev.peertubelive.objects.StreamSettings
import fr.mobdev.peertubelive.objects.*
import fr.mobdev.peertubelive.utils.TranslationUtils
import java.util.ArrayList
@ -35,9 +30,10 @@ class CreateLiveActivity : AppCompatActivity() {
private lateinit var privacies: MutableMap<String, Int>
private lateinit var languages: MutableMap<String, String>
private lateinit var oAuthData: OAuthData
private lateinit var configData: ConfigData
private var inError: Boolean = false
private var showAdvancedSettings = true
private lateinit var binding: ChannelListBinding
private lateinit var binding: CreateLiveBinding
private lateinit var startLive: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
@ -45,7 +41,7 @@ class CreateLiveActivity : AppCompatActivity() {
oAuthData = intent.getParcelableExtra(OAUTH_DATA)!!
binding = DataBindingUtil.setContentView(this,R.layout.channel_list)
binding = DataBindingUtil.setContentView(this,R.layout.create_live)
binding.error.visibility = View.GONE
binding.channelList.visibility = View.GONE
@ -60,6 +56,7 @@ class CreateLiveActivity : AppCompatActivity() {
binding.saveReplayInfo.visibility = View.GONE
binding.resolution.visibility = View.GONE
binding.resolutionList.visibility = View.GONE
binding.liveDisabled.visibility = View.GONE
startLive = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
setResult(it.resultCode)
@ -93,7 +90,9 @@ class CreateLiveActivity : AppCompatActivity() {
val comments = binding.commentsEnabled.isChecked
val download = binding.downloadEnabled.isChecked
val nsfw = binding.nsfw.isChecked
val replay = binding.saveReplay.isChecked
var replay: Boolean? = null
if (configData.saveReplayEnabled)
replay = binding.saveReplay.isChecked
val resolution = StreamData.STREAM_RESOLUTION.values()[binding.resolutionList.selectedItemPosition]
@ -108,6 +107,22 @@ class CreateLiveActivity : AppCompatActivity() {
}
}
InstanceManager.getLiveConfig(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
override fun onSuccess(args: Bundle?) {
configData = args?.getParcelable<ConfigData>(InstanceManager.EXTRA_DATA)!!
updateView(null)
}
override fun onError(error: String?) {
inError = true
updateView(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
this@CreateLiveActivity.oAuthData.updateData(oauthData)
}
})
InstanceManager.getCategoryList(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
override fun onSuccess(args: Bundle?) {
val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
@ -223,7 +238,16 @@ class CreateLiveActivity : AppCompatActivity() {
private fun updateView(error: String?) {
if(!inError) {
if(this::channels.isInitialized && this::categories.isInitialized && this::privacies.isInitialized && this::languages.isInitialized && this::licences.isInitialized) {
if (this::configData.isInitialized && !configData.liveEnabled) {
runOnUiThread {
binding.loadingProgress.visibility = View.GONE
binding.loadingChannels.visibility = View.GONE
binding.liveDisabled.visibility = View.VISIBLE
}
return
}
if(this::configData.isInitialized && configData.liveEnabled && this::channels.isInitialized && this::categories.isInitialized
&& this::privacies.isInitialized && this::languages.isInitialized && this::licences.isInitialized) {
val channelAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
for (channel in channels) {
channelAdapter.add(channel.name)
@ -264,8 +288,10 @@ class CreateLiveActivity : AppCompatActivity() {
binding.advanceSettings.visibility = View.VISIBLE
binding.privacy.visibility = View.VISIBLE
binding.privacyList.visibility = View.VISIBLE
binding.saveReplayLayout.visibility = View.VISIBLE
binding.saveReplayInfo.visibility = View.VISIBLE
if (configData.saveReplayEnabled) {
binding.saveReplayLayout.visibility = View.VISIBLE
binding.saveReplayInfo.visibility = View.VISIBLE
}
binding.resolution.visibility = View.VISIBLE
binding.resolutionList.visibility = View.VISIBLE
restoreSettings()
@ -346,7 +372,8 @@ class CreateLiveActivity : AppCompatActivity() {
binding.commentsEnabled.isChecked = settings.comments
binding.downloadEnabled.isChecked = settings.download
binding.nsfw.isChecked = settings.nsfw
binding.saveReplay.isChecked = settings.saveReplay
if (settings.saveReplay != null)
binding.saveReplay.isChecked = settings.saveReplay
binding.liveTitle.setText(settings.title)
if (settings.privacy != 0) {

View File

@ -330,7 +330,6 @@ class StreamActivity : AppCompatActivity() {
if (rtmpCamera2.prepareAudio() && rtmpCamera2.prepareVideo(width,height,30, (width*height*30*0.076).toInt(),false,CameraHelper.getCameraOrientation(this))) {
rtmpCamera2.startStream(streamData.url+"/"+streamData.key)
} else {
println("error")
/**This device cant init encoders, this could be for 2 reasons: The encoder selected doesnt support any configuration setted or your device hasnt a H264 or AAC encoder (in this case you can see log error valid encoder not found) */
}
}

View File

@ -3,10 +3,7 @@ package fr.mobdev.peertubelive.manager
import android.content.Context
import android.os.Bundle
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.objects.ChannelData
import fr.mobdev.peertubelive.objects.OAuthData
import fr.mobdev.peertubelive.objects.StreamData
import fr.mobdev.peertubelive.objects.StreamSettings
import fr.mobdev.peertubelive.objects.*
import org.json.JSONObject
import java.lang.Exception
import java.util.*
@ -25,6 +22,7 @@ object InstanceManager {
private const val GET_PRIVACY_ENDPOINT: String = "/videos/privacies"
private const val GET_LICENCE_ENDPOINT: String = "/videos/licences"
private const val GET_LANGUAGES_ENDPOINT: String = "/videos/languages"
private const val GET_CONFIG_ENDPOINT: String = "/config"
private const val GET_VIDEOS: String = "/users/me/videos"
internal const val EXTRA_DATA: String = "EXTRA_DATA"
@ -38,6 +36,9 @@ object InstanceManager {
private const val UUID: String = "uuid"
private const val RTMP_URL: String = "rtmpUrl"
private const val STREAM_KEY: String = "streamKey"
private const val CONFIG_LIVE: String = "live"
private const val CONFIG_LIVE_ENABLED: String = "enabled"
private const val CONFIG_LIVE_SAVE_REPLAY: String = "allowReplay"
fun registerAccount(context: Context, url: String, username: String, password: String, listener: InstanceListener) {
val registerUrl = url + BASE_API_ENDPOINT+ REGISTER_CLIENT_ENDPOINT
@ -148,8 +149,9 @@ object InstanceManager {
formData += prepareFormData(boundary,"licence",streamSettings.licence.toString(),false)
formData += prepareFormData(boundary,"commentsEnabled",streamSettings.comments.toString(),false)
formData += prepareFormData(boundary,"nsfw",streamSettings.nsfw.toString(),false)
formData += prepareFormData(boundary,"downloadEnabled",streamSettings.download.toString(),false)
formData += prepareFormData(boundary,"saveReplay",streamSettings.saveReplay.toString(),true)
formData += prepareFormData(boundary,"downloadEnabled",streamSettings.download.toString(),streamSettings.saveReplay == null)
if (streamSettings.saveReplay != null)
formData += prepareFormData(boundary,"saveReplay",streamSettings.saveReplay.toString(),true)
data.putString(CONTENT_TYPE,"multipart/form-data; boundary=$boundary")
data.putString(CONTENT_DATA,formData)
val internalListener = object: InstanceListener {
@ -365,6 +367,36 @@ object InstanceManager {
oauthManager.get(context,userInfoUrl,null,internalListener)
}
fun getLiveConfig(context: Context, url: String, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_CONFIG_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val configData = extractConfigData(response)
if (configData == null) {
listener.onError(context.getString(R.string.json_error))
return
}
args.putParcelable(EXTRA_DATA, configData)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,null,internalListener)
}
private fun extractChannelData(response: String): ArrayList<ChannelData>? {
try {
val json = JSONObject(response)
@ -433,6 +465,28 @@ object InstanceManager {
}
}
private fun extractConfigData(response: String): ConfigData? {
try {
val json = JSONObject(response)
return if (json.has(CONFIG_LIVE)) {
val live = json.getJSONObject(CONFIG_LIVE)
return if(live.has(CONFIG_LIVE_ENABLED) && live.has(CONFIG_LIVE_SAVE_REPLAY)) {
val liveEnabled = live.getBoolean(CONFIG_LIVE_ENABLED)
val saveReplayEnabled = live.getBoolean(CONFIG_LIVE_SAVE_REPLAY)
ConfigData(liveEnabled,saveReplayEnabled)
} else {
null
}
} else {
null
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
private fun <T> extractMapData(response: String, type: T): HashMap<String,T>? {
return try {
val json = JSONObject(response)

View File

@ -0,0 +1,31 @@
package fr.mobdev.peertubelive.objects;
import android.os.Parcel
import android.os.Parcelable
class ConfigData(val liveEnabled: Boolean, val saveReplayEnabled: Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte()
) {
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeByte(if (liveEnabled) 1 else 0)
dest.writeByte(if (saveReplayEnabled) 1 else 0)
}
companion object CREATOR : Parcelable.Creator<StreamData> {
override fun createFromParcel(parcel: Parcel): StreamData {
return StreamData(parcel)
}
override fun newArray(size: Int): Array<StreamData?> {
return arrayOfNulls(size)
}
}
}

View File

@ -5,7 +5,7 @@ import android.os.Parcelable
class StreamSettings(
val title: String, val channel: Long, val privacy: Int, val category: Int?, val language: String?, val licence: Int?, val description: String?,
val comments: Boolean, val download: Boolean, val nsfw: Boolean, val saveReplay: Boolean, val resolution: StreamData.STREAM_RESOLUTION) : Parcelable {
val comments: Boolean, val download: Boolean, val nsfw: Boolean, val saveReplay: Boolean?, val resolution: StreamData.STREAM_RESOLUTION) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readLong(),
@ -37,7 +37,8 @@ class StreamSettings(
parcel.writeByte(if (comments) 1 else 0)
parcel.writeByte(if (download) 1 else 0)
parcel.writeByte(if (nsfw) 1 else 0)
parcel.writeByte(if (saveReplay) 1 else 0)
if (saveReplay!= null)
parcel.writeByte(if (saveReplay) 1 else 0)
parcel.writeInt(resolution?.ordinal!!)
}

View File

@ -50,6 +50,18 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<TextView
android:id="@+id/live_disabled"
android:textColor="#FF0000"
android:layout_gravity="center"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/live_disabled"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/error"

View File

@ -26,6 +26,7 @@
<string name="stop_reason">Votre direct est terminé</string>
<string name="ask_end_stream">Voulez-vous arrêter le direct\?</string>
<string name="network_reason">Votre direct s\'est terminé à cause d\'un problème réseau</string>
<string name="live_disabled">Cette instance a désactivé les directs.</string>
<!-- buttons -->
<string name="choose_channel">Chaîne</string>
<string name="go_live">Démarrer le direct!</string>

View File

@ -26,6 +26,7 @@
<string name="stop_reason">Your livestream ended</string>
<string name="ask_end_stream">Do you want to stop the live?</string>
<string name="network_reason">Your livestream ended because of a network problem</string>
<string name="live_disabled">This instance has disabled livestream.</string>
<!-- buttons -->
<string name="choose_channel">Channel</string>
<string name="go_live">Start livestream</string>