mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-06-24 21:25:23 +00:00
Fixed issue causing FCast Receiver to freeze. Added support to request headers on Android implementation.
This commit is contained in:
parent
bc84f7b767
commit
9b14e665b5
3 changed files with 37 additions and 9 deletions
|
@ -8,7 +8,8 @@ data class PlayMessage(
|
||||||
val url: String? = null,
|
val url: String? = null,
|
||||||
val content: String? = null,
|
val content: String? = null,
|
||||||
val time: Double? = null,
|
val time: Double? = null,
|
||||||
val speed: Double? = null
|
val speed: Double? = null,
|
||||||
|
val headers: Map<String, String>? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
@ -2,7 +2,11 @@ package com.futo.fcast.receiver
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.net.*
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -14,19 +18,29 @@ import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import com.google.android.exoplayer2.*
|
import com.google.android.exoplayer2.ExoPlayer
|
||||||
|
import com.google.android.exoplayer2.MediaItem
|
||||||
|
import com.google.android.exoplayer2.PlaybackException
|
||||||
|
import com.google.android.exoplayer2.PlaybackParameters
|
||||||
|
import com.google.android.exoplayer2.Player
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
||||||
import com.google.android.exoplayer2.source.dash.DashMediaSource
|
import com.google.android.exoplayer2.source.dash.DashMediaSource
|
||||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
import com.google.android.exoplayer2.ui.StyledPlayerView
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSource
|
import com.google.android.exoplayer2.upstream.DefaultDataSource
|
||||||
import kotlinx.coroutines.*
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||||
|
import com.google.android.exoplayer2.upstream.HttpDataSource
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
|
|
||||||
class PlayerActivity : AppCompatActivity() {
|
class PlayerActivity : AppCompatActivity() {
|
||||||
private lateinit var _playerControlView: StyledPlayerView
|
private lateinit var _playerControlView: StyledPlayerView
|
||||||
private lateinit var _imageSpinner: ImageView
|
private lateinit var _imageSpinner: ImageView
|
||||||
|
@ -320,7 +334,15 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
throw IllegalArgumentException("Either URL or content must be provided.")
|
throw IllegalArgumentException("Either URL or content must be provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataSourceFactory = DefaultDataSource.Factory(this)
|
val dataSourceFactory = if (playMessage.headers != null) {
|
||||||
|
val httpDataSourceFactory: HttpDataSource.Factory = DefaultHttpDataSource.Factory()
|
||||||
|
httpDataSourceFactory.setDefaultRequestProperties(playMessage.headers)
|
||||||
|
DefaultDataSource.Factory(this, httpDataSourceFactory)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DefaultDataSource.Factory(this)
|
||||||
|
}
|
||||||
|
|
||||||
val mediaItem = mediaItemBuilder.build()
|
val mediaItem = mediaItemBuilder.build()
|
||||||
val mediaSource = when (playMessage.container) {
|
val mediaSource = when (playMessage.container) {
|
||||||
"application/dash+xml" -> DashMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
"application/dash+xml" -> DashMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||||
|
|
|
@ -12,6 +12,7 @@ class TcpListenerService(private val _networkService: NetworkService, private va
|
||||||
private var _listenThread: Thread? = null
|
private var _listenThread: Thread? = null
|
||||||
private var _clientThreads: ArrayList<Thread> = arrayListOf()
|
private var _clientThreads: ArrayList<Thread> = arrayListOf()
|
||||||
private var _sessions: ArrayList<FCastSession> = arrayListOf()
|
private var _sessions: ArrayList<FCastSession> = arrayListOf()
|
||||||
|
private var _serverSocket: ServerSocket? = null
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
Log.i(TAG, "Starting TcpListenerService")
|
Log.i(TAG, "Starting TcpListenerService")
|
||||||
|
@ -36,6 +37,9 @@ class TcpListenerService(private val _networkService: NetworkService, private va
|
||||||
|
|
||||||
_stopped = true
|
_stopped = true
|
||||||
|
|
||||||
|
_serverSocket?.close()
|
||||||
|
_serverSocket = null
|
||||||
|
|
||||||
_listenThread?.join()
|
_listenThread?.join()
|
||||||
_listenThread = null
|
_listenThread = null
|
||||||
|
|
||||||
|
@ -59,13 +63,13 @@ class TcpListenerService(private val _networkService: NetworkService, private va
|
||||||
|
|
||||||
while (!_stopped) {
|
while (!_stopped) {
|
||||||
try {
|
try {
|
||||||
val serverSocket = ServerSocket()
|
_serverSocket = ServerSocket()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverSocket.bind(InetSocketAddress(PORT))
|
_serverSocket!!.bind(InetSocketAddress(PORT))
|
||||||
|
|
||||||
while (!_stopped) {
|
while (!_stopped) {
|
||||||
val clientSocket = serverSocket.accept() ?: break
|
val clientSocket = _serverSocket!!.accept() ?: break
|
||||||
val clientThread = Thread {
|
val clientThread = Thread {
|
||||||
try {
|
try {
|
||||||
Log.i(TAG, "New connection received from ${clientSocket.remoteSocketAddress}")
|
Log.i(TAG, "New connection received from ${clientSocket.remoteSocketAddress}")
|
||||||
|
@ -97,7 +101,8 @@ class TcpListenerService(private val _networkService: NetworkService, private va
|
||||||
Log.e(TAG, "Failed to accept client connection due to an error, sleeping 1 second then restarting", e)
|
Log.e(TAG, "Failed to accept client connection due to an error, sleeping 1 second then restarting", e)
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
} finally {
|
} finally {
|
||||||
serverSocket.close()
|
_serverSocket?.close()
|
||||||
|
_serverSocket = null
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
Log.e(TAG, "Failed to create server socket, sleeping 1 second then restarting", e)
|
Log.e(TAG, "Failed to create server socket, sleeping 1 second then restarting", e)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue