mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-02 22:30:40 +00:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
ea59f8dccb
12 changed files with 145 additions and 84 deletions
|
@ -5,7 +5,6 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" tools:ignore="ScopedStorage" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" tools:ignore="ScopedStorage" />
|
||||||
|
|
|
@ -77,10 +77,14 @@ class AdvancedOrientationListener(private val activity: Activity, private val li
|
||||||
lastStableOrientation = newOrientation
|
lastStableOrientation = newOrientation
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
delay(stabilityThresholdTime)
|
try {
|
||||||
if (newOrientation == lastStableOrientation) {
|
delay(stabilityThresholdTime)
|
||||||
lastOrientation = newOrientation
|
if (newOrientation == lastStableOrientation) {
|
||||||
onOrientationChanged.emit(newOrientation)
|
lastOrientation = newOrientation
|
||||||
|
onOrientationChanged.emit(newOrientation)
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.i(TAG, "Failed to trigger onOrientationChanged", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,4 +115,8 @@ class AdvancedOrientationListener(private val activity: Activity, private val li
|
||||||
fun stopListening() {
|
fun stopListening() {
|
||||||
sensorManager.unregisterListener(sensorListener)
|
sensorManager.unregisterListener(sensorListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "AdvancedOrientationListener"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,7 +487,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
class CommentSettings {
|
class CommentSettings {
|
||||||
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
|
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
|
||||||
@DropdownFieldOptionsId(R.array.comment_sections)
|
@DropdownFieldOptionsId(R.array.comment_sections)
|
||||||
var defaultCommentSection: Int = 0;
|
var defaultCommentSection: Int = 1;
|
||||||
|
|
||||||
@FormField(R.string.bad_reputation_comments_fading, FieldForm.TOGGLE, R.string.bad_reputation_comments_fading_description, 0)
|
@FormField(R.string.bad_reputation_comments_fading, FieldForm.TOGGLE, R.string.bad_reputation_comments_fading_description, 0)
|
||||||
var badReputationCommentsFading: Boolean = true;
|
var badReputationCommentsFading: Boolean = true;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.content.pm.ActivityInfo
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import android.view.OrientationEventListener
|
import android.view.OrientationEventListener
|
||||||
import com.futo.platformplayer.constructs.Event1
|
import com.futo.platformplayer.constructs.Event1
|
||||||
|
import com.futo.platformplayer.logging.Logger
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -34,10 +35,14 @@ class SimpleOrientationListener(
|
||||||
lastStableOrientation = newOrientation
|
lastStableOrientation = newOrientation
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
delay(stabilityThresholdTime)
|
try {
|
||||||
if (newOrientation == lastStableOrientation) {
|
delay(stabilityThresholdTime)
|
||||||
lastOrientation = newOrientation
|
if (newOrientation == lastStableOrientation) {
|
||||||
onOrientationChanged.emit(newOrientation)
|
lastOrientation = newOrientation
|
||||||
|
onOrientationChanged.emit(newOrientation)
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.i(TAG, "Failed to trigger onOrientationChanged", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,4 +57,8 @@ class SimpleOrientationListener(
|
||||||
fun stopListening() {
|
fun stopListening() {
|
||||||
orientationListener.disable()
|
orientationListener.disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "SimpleOrientationListener"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -147,8 +147,6 @@ fun InputStream.copyToOutputStream(inputStreamLength: Long, outputStream: Output
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun Activity.setNavigationBarColorAndIcons() {
|
fun Activity.setNavigationBarColorAndIcons() {
|
||||||
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.black);
|
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.black);
|
||||||
if (Settings.instance.playback.allowVideoToGoUnderCutout)
|
|
||||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
window.insetsController?.setSystemBarsAppearance(0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
|
window.insetsController?.setSystemBarsAppearance(0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.os.StrictMode.VmPolicy
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.WindowManager
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.ActivityResult
|
||||||
|
@ -112,7 +113,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
|
|
||||||
private lateinit var _overlayContainer: FrameLayout;
|
private lateinit var _overlayContainer: FrameLayout;
|
||||||
private lateinit var _toastView: ToastView;
|
private lateinit var _toastView: ToastView;
|
||||||
private lateinit var _multicastLock: WifiManager.MulticastLock
|
|
||||||
|
|
||||||
//Segment Containers
|
//Segment Containers
|
||||||
private lateinit var _fragContainerTopBar: FragmentContainerView;
|
private lateinit var _fragContainerTopBar: FragmentContainerView;
|
||||||
|
@ -247,12 +247,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
Logger.i(TAG, "Acquiring multicast lock")
|
|
||||||
val wifiManager = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
|
|
||||||
_multicastLock = wifiManager.createMulticastLock("mdnsLock")
|
|
||||||
_multicastLock.setReferenceCounted(true)
|
|
||||||
_multicastLock.acquire()
|
|
||||||
|
|
||||||
Logger.i(TAG, "MainActivity Starting");
|
Logger.i(TAG, "MainActivity Starting");
|
||||||
StateApp.instance.setGlobalContext(this, lifecycleScope);
|
StateApp.instance.setGlobalContext(this, lifecycleScope);
|
||||||
StateApp.instance.mainAppStarting(this);
|
StateApp.instance.mainAppStarting(this);
|
||||||
|
@ -260,7 +254,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
setNavigationBarColorAndIcons();
|
setNavigationBarColorAndIcons();
|
||||||
|
if (Settings.instance.playback.allowVideoToGoUnderCutout)
|
||||||
|
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
StatePlatform.instance.updateAvailableClients(this@MainActivity);
|
StatePlatform.instance.updateAvailableClients(this@MainActivity);
|
||||||
|
@ -977,7 +972,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
Logger.v(TAG, "onDestroy")
|
Logger.v(TAG, "onDestroy")
|
||||||
_multicastLock.release()
|
|
||||||
StateApp.instance.mainAppDestroyed(this);
|
StateApp.instance.mainAppDestroyed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.futo.platformplayer.fragment.mainactivity.main
|
||||||
|
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -10,6 +11,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import android.view.WindowInsetsController
|
import android.view.WindowInsetsController
|
||||||
|
import android.view.WindowManager
|
||||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -426,22 +428,42 @@ class VideoDetailFragment : MainFragment {
|
||||||
onMaximized.clear();
|
onMaximized.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun hideSystemUI() {
|
private fun hideSystemUI() {
|
||||||
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
activity?.window?.insetsController?.let { controller ->
|
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
|
||||||
controller.hide(WindowInsets.Type.statusBars())
|
activity?.window?.insetsController?.let { controller ->
|
||||||
controller.hide(WindowInsets.Type.systemBars())
|
controller.hide(WindowInsets.Type.statusBars())
|
||||||
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
controller.hide(WindowInsets.Type.systemBars())
|
||||||
|
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
activity?.window?.setFlags(
|
||||||
|
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
|
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||||
|
)
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
activity?.window?.decorView?.systemUiVisibility = (
|
||||||
|
View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||||
|
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
|
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSystemUI() {
|
private fun showSystemUI() {
|
||||||
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
activity?.window?.insetsController?.let { controller ->
|
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
|
||||||
controller.show(WindowInsets.Type.statusBars())
|
activity?.window?.insetsController?.let { controller ->
|
||||||
controller.show(WindowInsets.Type.systemBars())
|
controller.show(WindowInsets.Type.statusBars())
|
||||||
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
|
controller.show(WindowInsets.Type.systemBars())
|
||||||
|
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ class MDNSListener {
|
||||||
private fun receiveLoop(client: DatagramSocket) {
|
private fun receiveLoop(client: DatagramSocket) {
|
||||||
Logger.i(TAG, "Started receive loop")
|
Logger.i(TAG, "Started receive loop")
|
||||||
|
|
||||||
val buffer = ByteArray(1024)
|
val buffer = ByteArray(8972)
|
||||||
val packet = DatagramPacket(buffer, buffer.size)
|
val packet = DatagramPacket(buffer, buffer.size)
|
||||||
while (_started) {
|
while (_started) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.futo.platformplayer.constructs.Event1
|
||||||
|
|
||||||
|
|
||||||
class MediaControlReceiver : BroadcastReceiver() {
|
class MediaControlReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
val act = intent?.getStringExtra(EXTRA_MEDIA_ACTION);
|
val act = intent?.getStringExtra(EXTRA_MEDIA_ACTION);
|
||||||
Logger.i(TAG, "Received MediaControl Event $act");
|
Logger.i(TAG, "Received MediaControl Event $act");
|
||||||
|
|
|
@ -55,9 +55,15 @@ class MediaPlaybackService : Service() {
|
||||||
private var _notificationChannel: NotificationChannel? = null;
|
private var _notificationChannel: NotificationChannel? = null;
|
||||||
private var _mediaSession: MediaSessionCompat? = null;
|
private var _mediaSession: MediaSessionCompat? = null;
|
||||||
private var _hasFocus: Boolean = false;
|
private var _hasFocus: Boolean = false;
|
||||||
|
private var _isTransientLoss: Boolean = false;
|
||||||
private var _focusRequest: AudioFocusRequest? = null;
|
private var _focusRequest: AudioFocusRequest? = null;
|
||||||
private var _audioFocusLossTime_ms: Long? = null
|
private var _audioFocusLossTime_ms: Long? = null
|
||||||
private var _playbackState = PlaybackStateCompat.STATE_NONE;
|
private var _playbackState = PlaybackStateCompat.STATE_NONE;
|
||||||
|
private var _lastAudioFocusAttempt_ms: Long? = null
|
||||||
|
private val isPlaying get() = _playbackState != PlaybackStateCompat.STATE_PAUSED &&
|
||||||
|
_playbackState != PlaybackStateCompat.STATE_STOPPED &&
|
||||||
|
_playbackState != PlaybackStateCompat.STATE_NONE &&
|
||||||
|
_playbackState != PlaybackStateCompat.STATE_ERROR
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
Logger.v(TAG, "onStartCommand");
|
Logger.v(TAG, "onStartCommand");
|
||||||
|
@ -159,12 +165,7 @@ class MediaPlaybackService : Service() {
|
||||||
Logger.v(TAG, "closeMediaSession");
|
Logger.v(TAG, "closeMediaSession");
|
||||||
stopForeground(STOP_FOREGROUND_REMOVE);
|
stopForeground(STOP_FOREGROUND_REMOVE);
|
||||||
|
|
||||||
val focusRequest = _focusRequest;
|
abandonAudioFocus()
|
||||||
if (focusRequest != null) {
|
|
||||||
_audioManager?.abandonAudioFocusRequest(focusRequest);
|
|
||||||
_focusRequest = null;
|
|
||||||
}
|
|
||||||
_hasFocus = false;
|
|
||||||
|
|
||||||
val notifManager = _notificationManager;
|
val notifManager = _notificationManager;
|
||||||
Logger.i(TAG, "Cancelling playback notification (notifManager: ${notifManager != null})");
|
Logger.i(TAG, "Cancelling playback notification (notifManager: ${notifManager != null})");
|
||||||
|
@ -335,29 +336,73 @@ class MediaPlaybackService : Service() {
|
||||||
.setState(state, pos, 1f, SystemClock.elapsedRealtime())
|
.setState(state, pos, 1f, SystemClock.elapsedRealtime())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
if(_focusRequest == null)
|
|
||||||
setAudioFocus();
|
|
||||||
|
|
||||||
_playbackState = state;
|
_playbackState = state;
|
||||||
|
try {
|
||||||
|
setAudioFocus()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.e(TAG, "Failed to set audio focus", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: (TBD) This code probably more fitting inside FutoVideoPlayer, as this service is generally only used for global events
|
//TODO: (TBD) This code probably more fitting inside FutoVideoPlayer, as this service is generally only used for global events
|
||||||
private fun setAudioFocus() {
|
private fun setAudioFocus() {
|
||||||
Log.i(TAG, "Requested audio focus.");
|
if (!isPlaying) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
if (_hasFocus || _isTransientLoss) {
|
||||||
.setAcceptsDelayedFocusGain(true)
|
return;
|
||||||
.setOnAudioFocusChangeListener(_audioFocusChangeListener)
|
}
|
||||||
.build()
|
|
||||||
|
|
||||||
_focusRequest = focusRequest;
|
val now = System.currentTimeMillis()
|
||||||
val result = _audioManager?.requestAudioFocus(focusRequest)
|
val lastAudioFocusAttempt_ms = _lastAudioFocusAttempt_ms
|
||||||
|
if (lastAudioFocusAttempt_ms == null || now - lastAudioFocusAttempt_ms > 1000) {
|
||||||
|
_lastAudioFocusAttempt_ms = now
|
||||||
|
} else {
|
||||||
|
Log.v(TAG, "Skipped trying to get audio focus because gaining audio focus was recently attempted.");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_focusRequest == null) {
|
||||||
|
val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
||||||
|
.setAcceptsDelayedFocusGain(true)
|
||||||
|
.setOnAudioFocusChangeListener(_audioFocusChangeListener)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
_focusRequest = focusRequest;
|
||||||
|
Log.i(TAG, "Created audio focus request.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Requesting audio focus.");
|
||||||
|
|
||||||
|
val result = _audioManager?.requestAudioFocus(_focusRequest!!)
|
||||||
Log.i(TAG, "Audio focus request result $result");
|
Log.i(TAG, "Audio focus request result $result");
|
||||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
//TODO: Handle when not possible to get audio focus
|
_hasFocus = true
|
||||||
_hasFocus = true;
|
_isTransientLoss = false
|
||||||
Log.i(TAG, "Audio focus received");
|
Log.i(TAG, "Audio focus received");
|
||||||
|
} else if (result == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
|
||||||
|
_hasFocus = false
|
||||||
|
_isTransientLoss = false
|
||||||
|
Log.i(TAG, "Audio focus delayed, waiting for focus")
|
||||||
|
} else {
|
||||||
|
_hasFocus = false
|
||||||
|
_isTransientLoss = false
|
||||||
|
Log.i(TAG, "Audio focus not granted, retrying later")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Audio focus requested.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun abandonAudioFocus() {
|
||||||
|
val focusRequest = _focusRequest;
|
||||||
|
if (focusRequest != null) {
|
||||||
|
Logger.i(TAG, "Audio focus abandoned")
|
||||||
|
_audioManager?.abandonAudioFocusRequest(focusRequest);
|
||||||
|
_focusRequest = null;
|
||||||
|
}
|
||||||
|
_hasFocus = false;
|
||||||
|
_isTransientLoss = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _audioFocusChangeListener =
|
private val _audioFocusChangeListener =
|
||||||
|
@ -365,9 +410,8 @@ class MediaPlaybackService : Service() {
|
||||||
try {
|
try {
|
||||||
when (focusChange) {
|
when (focusChange) {
|
||||||
AudioManager.AUDIOFOCUS_GAIN -> {
|
AudioManager.AUDIOFOCUS_GAIN -> {
|
||||||
//Do not start playing on gaining audo focus
|
|
||||||
//MediaControlReceiver.onPlayReceived.emit();
|
|
||||||
_hasFocus = true;
|
_hasFocus = true;
|
||||||
|
_isTransientLoss = false;
|
||||||
Log.i(TAG, "Audio focus gained (restartPlaybackAfterLoss = ${Settings.instance.playback.restartPlaybackAfterLoss}, _audioFocusLossTime_ms = $_audioFocusLossTime_ms)");
|
Log.i(TAG, "Audio focus gained (restartPlaybackAfterLoss = ${Settings.instance.playback.restartPlaybackAfterLoss}, _audioFocusLossTime_ms = $_audioFocusLossTime_ms)");
|
||||||
|
|
||||||
if (Settings.instance.playback.restartPlaybackAfterLoss == 1) {
|
if (Settings.instance.playback.restartPlaybackAfterLoss == 1) {
|
||||||
|
@ -385,40 +429,28 @@ class MediaPlaybackService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
||||||
MediaControlReceiver.onPauseReceived.emit();
|
if (isPlaying) {
|
||||||
if (_playbackState != PlaybackStateCompat.STATE_PAUSED &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_STOPPED &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_NONE &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_ERROR) {
|
|
||||||
_audioFocusLossTime_ms = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Audio focus transient loss");
|
|
||||||
}
|
|
||||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
|
|
||||||
Log.i(TAG, "Audio focus transient loss, can duck");
|
|
||||||
}
|
|
||||||
AudioManager.AUDIOFOCUS_LOSS -> {
|
|
||||||
if (_playbackState != PlaybackStateCompat.STATE_PAUSED &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_STOPPED &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_NONE &&
|
|
||||||
_playbackState != PlaybackStateCompat.STATE_ERROR) {
|
|
||||||
_audioFocusLossTime_ms = System.currentTimeMillis()
|
_audioFocusLossTime_ms = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasFocus = false;
|
_hasFocus = false;
|
||||||
|
_isTransientLoss = true;
|
||||||
MediaControlReceiver.onPauseReceived.emit();
|
MediaControlReceiver.onPauseReceived.emit();
|
||||||
Log.i(TAG, "Audio focus lost");
|
Log.i(TAG, "Audio focus transient loss (_audioFocusLossTime_ms = ${_audioFocusLossTime_ms})");
|
||||||
|
}
|
||||||
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
|
||||||
val runningAppProcesses = activityManager.runningAppProcesses
|
Log.i(TAG, "Audio focus transient loss, can duck");
|
||||||
for (processInfo in runningAppProcesses) {
|
_hasFocus = true;
|
||||||
// Check the importance of the running app process
|
_isTransientLoss = true;
|
||||||
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
}
|
||||||
// This app is in the foreground, which might have caused the loss of audio focus
|
AudioManager.AUDIOFOCUS_LOSS -> {
|
||||||
Log.i("AudioFocus", "App ${processInfo.processName} might have caused the loss of audio focus")
|
if (isPlaying) {
|
||||||
}
|
_audioFocusLossTime_ms = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaControlReceiver.onPauseReceived.emit();
|
||||||
|
abandonAudioFocus();
|
||||||
|
Log.i(TAG, "Audio focus lost");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(ex: Throwable) {
|
} catch(ex: Throwable) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 850acb49a8d988f45b893ef848d559dd74d0db1f
|
Subproject commit 31490e10f9ef661d6365c0cf4d0fcedf9d807a69
|
|
@ -1 +1 @@
|
||||||
Subproject commit 850acb49a8d988f45b893ef848d559dd74d0db1f
|
Subproject commit 31490e10f9ef661d6365c0cf4d0fcedf9d807a69
|
Loading…
Add table
Add a link
Reference in a new issue