Merge pull request 'manage-stream-resolution' (#10) from manage-stream-resolution into master

Reviewed-on: https://codeberg.org/Schoumi/PeerTubeLive/pulls/10
This commit is contained in:
Schoumi 2021-07-27 15:53:33 +02:00
commit 6031e37959
12 changed files with 138 additions and 58 deletions

View File

@ -10,7 +10,7 @@ android {
defaultConfig {
applicationId "fr.mobdev.peertubelive"
minSdkVersion 19
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"

View File

@ -58,6 +58,8 @@ class CreateLiveActivity : AppCompatActivity() {
binding.privacyList.visibility = View.GONE
binding.saveReplayLayout.visibility = View.GONE
binding.saveReplayInfo.visibility = View.GONE
binding.resolution.visibility = View.GONE
binding.resolutionList.visibility = View.GONE
startLive = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
setResult(it.resultCode)
@ -93,7 +95,9 @@ class CreateLiveActivity : AppCompatActivity() {
val nsfw = binding.nsfw.isChecked
val replay = binding.saveReplay.isChecked
val streamSettings = StreamSettings(title,channel,privacy,category,language,licence,description,comments,download,nsfw,replay)
val resolution = StreamData.STREAM_RESOLUTION.values()[binding.resolutionList.selectedItemPosition]
val streamSettings = StreamSettings(title,channel,privacy,category,language,licence,description,comments,download,nsfw,replay,resolution)
DatabaseManager.updateStreamSettings(this,streamSettings)
if(title.isEmpty())
{
@ -262,6 +266,8 @@ class CreateLiveActivity : AppCompatActivity() {
binding.privacyList.visibility = View.VISIBLE
binding.saveReplayLayout.visibility = View.VISIBLE
binding.saveReplayInfo.visibility = View.VISIBLE
binding.resolution.visibility = View.VISIBLE
binding.resolutionList.visibility = View.VISIBLE
restoreSettings()
}
}
@ -284,8 +290,9 @@ class CreateLiveActivity : AppCompatActivity() {
InstanceManager.createLive(this,oAuthData.baseUrl!!,oAuthData,streamSettings,object : InstanceManager.InstanceListener {
override fun onSuccess(args: Bundle?) {
if(args != null) {
val streamData = args.getParcelable<StreamData>(InstanceManager.EXTRA_DATA)!!
val urlKey = args.getParcelable<StreamData>(InstanceManager.EXTRA_DATA)!!
val intent = Intent(this@CreateLiveActivity, StreamActivity::class.java)
val streamData = StreamData(urlKey.url,urlKey.key,streamSettings.resolution)
intent.putExtra(InstanceManager.EXTRA_DATA,streamData)
dialog.dismiss()
startLive.launch(intent)
@ -381,6 +388,8 @@ class CreateLiveActivity : AppCompatActivity() {
}
}
}
binding.resolutionList.setSelection(settings.resolution.ordinal)
}
}

View File

@ -50,6 +50,9 @@ class MainActivity : AppCompatActivity() {
StreamActivity.STOP -> {
alertBuilder.setMessage(R.string.stop_reason)
}
StreamActivity.NETWORK_ERROR -> {
alertBuilder.setMessage(R.string.network_reason)
}
}
alertBuilder.setPositiveButton(android.R.string.ok,null)
alertBuilder.show()

View File

@ -19,7 +19,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import com.pedro.encoder.input.video.CameraHelper
import com.pedro.rtplibrary.rtmp.RtmpCamera1
import com.pedro.rtplibrary.rtmp.RtmpCamera2
import net.ossrs.rtmp.ConnectCheckerRtmp
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.databinding.StreamBinding
@ -30,7 +30,7 @@ class StreamActivity : AppCompatActivity() {
private lateinit var binding: StreamBinding
private lateinit var rtmpCamera1 : RtmpCamera1
private lateinit var rtmpCamera2 : RtmpCamera2
private lateinit var streamData: StreamData
private lateinit var orientationEventListener: OrientationEventListener
private lateinit var lockReceiver: BroadcastReceiver
@ -47,6 +47,7 @@ class StreamActivity : AppCompatActivity() {
const val LOCK :Int = 2
const val BACK :Int = 3
const val STOP :Int = 4
const val NETWORK_ERROR :Int = 5
}
@ -84,7 +85,7 @@ class StreamActivity : AppCompatActivity() {
if (lastScreenOrientation != screenOrientation && orientationCounter > 30) {
screenOrientation = lastScreenOrientation
rtmpCamera1.glInterface.setStreamRotation(screenOrientation)
rtmpCamera2.glInterface.setStreamRotation(screenOrientation)
if (screenOrientation == 90) {
localOrientation = 270
@ -104,24 +105,24 @@ class StreamActivity : AppCompatActivity() {
binding.stop.setOnClickListener {
askStopLive(STOP)
}
binding.switchCamera.setOnClickListener { rtmpCamera1.switchCamera() }
binding.switchCamera.setOnClickListener { rtmpCamera2.switchCamera() }
binding.muteMicro.setOnClickListener {
if (rtmpCamera1.isAudioMuted) {
rtmpCamera1.enableAudio()
if (rtmpCamera2.isAudioMuted) {
rtmpCamera2.enableAudio()
binding.muteMicro.setImageResource(R.drawable.baseline_volume_up_24)
}
else {
rtmpCamera1.disableAudio()
rtmpCamera2.disableAudio()
binding.muteMicro.setImageResource(R.drawable.baseline_volume_off_24)
}
}
binding.flash.setOnClickListener {
if (rtmpCamera1.isLanternEnabled) {
rtmpCamera1.disableLantern()
if (rtmpCamera2.isLanternEnabled) {
rtmpCamera2.disableLantern()
binding.flash.setImageResource(R.drawable.baseline_flash_off_24)
}
else {
rtmpCamera1.enableLantern()
rtmpCamera2.enableLantern()
binding.flash.setImageResource(R.drawable.baseline_flash_on_24)
}
}
@ -148,11 +149,11 @@ class StreamActivity : AppCompatActivity() {
}
override fun surfaceDestroyed(p0: SurfaceHolder) {
if (this@StreamActivity::rtmpCamera1.isInitialized) {
if (rtmpCamera1.isStreaming) {
rtmpCamera1.stopStream()
if (this@StreamActivity::rtmpCamera2.isInitialized) {
if (rtmpCamera2.isStreaming) {
rtmpCamera2.stopStream()
}
rtmpCamera1.stopPreview()
rtmpCamera2.stopPreview()
}
}
@ -257,7 +258,9 @@ class StreamActivity : AppCompatActivity() {
override fun onConnectionFailedRtmp(reason: String) {
runOnUiThread {
Toast.makeText(binding.root.context, "Connection failed", Toast.LENGTH_SHORT).show();
rtmpCamera1.stopStream()
rtmpCamera2.stopStream()
setResult(NETWORK_ERROR)
finish()
}
}
@ -286,36 +289,48 @@ class StreamActivity : AppCompatActivity() {
}
}
rtmpCamera1 = RtmpCamera1(binding.surfaceView, connectChecker)
rtmpCamera2 = RtmpCamera2(binding.surfaceView, connectChecker)
var resolutions = rtmpCamera1.resolutionsBack
var width: Int
var height: Int
if(resolutions[0].width > resolutions[0].height) {
width = resolutions[0].width
height = resolutions[0].height
} else {
width = resolutions[0].height
height = resolutions[0].width
var width = 1920
var height = 1080
when (streamData.resolution) {
StreamData.STREAM_RESOLUTION.p2160 -> {
width = 3840
height = 2160
}
for(res in resolutions) {
if (width * height < res.width * res.width) {
if(res.width > res.height) {
width = res.width
height = res.height
} else {
width = res.height
height = res.width
StreamData.STREAM_RESOLUTION.p1440 -> {
width = 2560
height = 1440
}
StreamData.STREAM_RESOLUTION.p1080 -> {
width = 1920
height = 1080
}
StreamData.STREAM_RESOLUTION.p720 -> {
width = 1280
height = 720
}
StreamData.STREAM_RESOLUTION.p480 -> {
width = 640
height = 480
}
StreamData.STREAM_RESOLUTION.p360 -> {
width = 480
height = 360
}
}
rtmpCamera1.startPreview(width,height)
rtmpCamera2.startPreview(CameraHelper.Facing.BACK, width,height)
//start stream
if (rtmpCamera1.prepareAudio() && rtmpCamera1.prepareVideo(width,height,30,3000*1024,false,CameraHelper.getCameraOrientation(this))) {
rtmpCamera1.startStream(streamData.url+"/"+streamData.key)
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

@ -5,6 +5,7 @@ import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import fr.mobdev.peertubelive.objects.StreamData
class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, 2) {
@ -30,6 +31,7 @@ class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null
const val SETS_DOWNLOAD : String = "Download"
const val SETS_REPLAY : String = "Replay"
const val SETS_NSFW : String = "Nsfw"
const val SETS_RESOLUTION: String = "Resolution"
}
override fun onCreate(db: SQLiteDatabase?) {
@ -39,7 +41,7 @@ class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null
db?.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_STREAM_SETTINGS (id INTEGER PRIMARY KEY, $SETS_TITLE TEXT, $SETS_CATEGORY INTEGER, $SETS_PRIVACY INTEGER, " +
"$SETS_LANGUAGE TEXT, $SETS_LICENCE INTEGER, $SETS_COMMENTS INTEGER, " +
"$SETS_DOWNLOAD INTEGER, $SETS_REPLAY INTEGER, $SETS_NSFW INTEGER);")
"$SETS_DOWNLOAD INTEGER, $SETS_REPLAY INTEGER, $SETS_NSFW INTEGER, $SETS_RESOLUTION INTEGER);")
val values = ContentValues()
values.put("id",1)
@ -48,6 +50,7 @@ class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null
values.put(SETS_DOWNLOAD,true)
values.put(SETS_NSFW,false)
values.put(SETS_REPLAY,false)
values.put(SETS_RESOLUTION,StreamData.STREAM_RESOLUTION.p1080.ordinal)
db?.insert(TABLE_STREAM_SETTINGS,null,values)
}

View File

@ -4,6 +4,7 @@ import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import fr.mobdev.peertubelive.objects.OAuthData
import fr.mobdev.peertubelive.objects.StreamData
import fr.mobdev.peertubelive.objects.StreamSettings
object DatabaseManager {
@ -103,8 +104,9 @@ object DatabaseManager {
val comments: Boolean = cursor.getInt(col++) == 1
val download: Boolean = cursor.getInt(col++) == 1
val saveReplay: Boolean = cursor.getInt(col++) == 1
val nsfw: Boolean = cursor.getInt(col) == 1
streamSettings = StreamSettings(title,0,privacy,category,language,licence,null,comments,download,nsfw,saveReplay)
val nsfw: Boolean = cursor.getInt(col++) == 1
val resolution: StreamData.STREAM_RESOLUTION = StreamData.STREAM_RESOLUTION.values()[cursor.getInt(col)]
streamSettings = StreamSettings(title,0,privacy,category,language,licence,null,comments,download,nsfw,saveReplay,resolution)
}
cursor?.close()
return streamSettings
@ -123,6 +125,7 @@ object DatabaseManager {
values.put(DatabaseHelper.SETS_REPLAY,streamSettings.saveReplay)
values.put(DatabaseHelper.SETS_LANGUAGE,streamSettings.language)
values.put(DatabaseHelper.SETS_LICENCE,streamSettings.licence)
values.put(DatabaseHelper.SETS_RESOLUTION,streamSettings.resolution.ordinal)
val whereClause = "id = ?"

View File

@ -422,7 +422,7 @@ object InstanceManager {
val rtmp = json.getString(RTMP_URL)
val key = json.getString(STREAM_KEY)
StreamData(rtmp,key)
StreamData(rtmp,key,null)
} else {
null

View File

@ -3,10 +3,11 @@ package fr.mobdev.peertubelive.objects
import android.os.Parcel
import android.os.Parcelable
class StreamData(val url: String?, val key: String?): Parcelable {
class StreamData(val url: String?, val key: String?, val resolution: STREAM_RESOLUTION?): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString()
parcel.readString(),
STREAM_RESOLUTION.values()[(parcel.readInt())]
) {
}
@ -17,6 +18,7 @@ class StreamData(val url: String?, val key: String?): Parcelable {
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(url)
dest.writeString(key)
dest.writeInt(resolution?.ordinal!!)
}
companion object CREATOR : Parcelable.Creator<StreamData> {
@ -29,4 +31,14 @@ class StreamData(val url: String?, val key: String?): Parcelable {
}
}
enum class STREAM_RESOLUTION
{
p2160,
p1440,
p1080,
p720,
p480,
p360
}
}

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) : 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(),
@ -17,7 +17,8 @@ class StreamSettings(
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte()
parcel.readByte() != 0.toByte(),
StreamData.STREAM_RESOLUTION.values()[(parcel.readInt())]
) {
}
@ -37,6 +38,7 @@ class StreamSettings(
parcel.writeByte(if (download) 1 else 0)
parcel.writeByte(if (nsfw) 1 else 0)
parcel.writeByte(if (saveReplay) 1 else 0)
parcel.writeInt(resolution?.ordinal!!)
}
override fun describeContents(): Int {

View File

@ -127,12 +127,32 @@
android:layout_margin="5dp"
/>
<TextView
android:id="@+id/resolution"
android:text="@string/stream_resolution"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/privacy_list"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="5dp"/>
<Spinner
android:id="@+id/resolution_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:entries="@array/stream_resolution"
app:layout_constraintTop_toBottomOf="@id/resolution"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="5dp"
/>
<LinearLayout
android:id="@+id/save_replay_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/privacy_list"
app:layout_constraintTop_toBottomOf="@id/resolution_list"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
>

View File

@ -25,6 +25,7 @@
<string name="lock_reason">Votre direct s\'est terminé car le téléphone a été verrouillé</string>
<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>
<!-- buttons -->
<string name="choose_channel">Chaîne</string>
<string name="go_live">Démarrer le direct!</string>
@ -55,6 +56,7 @@
<string name="stream_ended">Direct terminé</string>
<string name="end_stream">Arrêter le direct</string>
<string name="creating">Patientez pendant la creation du direct</string>
<string name="stream_resolution">Résolution du direct</string>
<!-- placeholders -->
<string name="exemple_instance">ex: peertube.fr, https://peertube.fr</string>
<!-- category -->

View File

@ -20,11 +20,12 @@
<string name="delete_account">Delete the %s account associated with the %s server\?</string>
<string name="tags_rules">Maximum 5 tags, each between 2 and 30 characters, separate by comma</string>
<string name="save_replay_info">If you enable this option, your live will be terminated if you exceed your video quota</string>
<string name="back_reason">Your live has ended after you pressed back button</string>
<string name="background_reason">Your live has ended because the app has gone to background</string>
<string name="lock_reason">Your live has ended because the phone was locked</string>
<string name="stop_reason">Your live has ended</string>
<string name="back_reason">Your livestream ended after you pressed back button</string>
<string name="background_reason">Your livestream ended because the app has gone to background</string>
<string name="lock_reason">Your livestream ended because the phone was locked</string>
<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>
<!-- buttons -->
<string name="choose_channel">Channel</string>
<string name="go_live">Start livestream</string>
@ -55,6 +56,7 @@
<string name="stream_ended">Livestream ended</string>
<string name="end_stream">Stop livestream</string>
<string name="creating">Wait for live creation</string>
<string name="stream_resolution">Livestream Resolution</string>
<!-- placeholders -->
<string name="exemple_instance">e.g. peertube.fr, https://peertube.fr</string>
<!-- category -->
@ -283,4 +285,13 @@
<string name="unlisted">Unlisted</string>
<string name="privacy_private">Private</string>
<string name="internal">Internal</string>
<array name="stream_resolution">
<item>2160p</item>
<item>1440p</item>
<item>1080p</item>
<item>720p</item>
<item>480p</item>
<item>360p</item>
</array>
</resources>