Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented advanced settings screen (buffering and HTTP settings) #928

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import androidx.navigation.NavHostController
import androidx.navigation.navigation
import dev.anilbeesetti.nextplayer.settings.Setting
import dev.anilbeesetti.nextplayer.settings.navigation.aboutPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.advancedPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.appearancePreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.audioPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.decoderPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.folderPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.mediaLibraryPreferencesScreen
import dev.anilbeesetti.nextplayer.settings.navigation.navigateToAboutPreferences
import dev.anilbeesetti.nextplayer.settings.navigation.navigateToAdvancedPreferences
import dev.anilbeesetti.nextplayer.settings.navigation.navigateToAppearancePreferences
import dev.anilbeesetti.nextplayer.settings.navigation.navigateToAudioPreferences
import dev.anilbeesetti.nextplayer.settings.navigation.navigateToDecoderPreferences
Expand Down Expand Up @@ -42,6 +44,7 @@ fun NavGraphBuilder.settingsNavGraph(
Setting.DECODER -> navController.navigateToDecoderPreferences()
Setting.AUDIO -> navController.navigateToAudioPreferences()
Setting.SUBTITLE -> navController.navigateToSubtitlePreferences()
Setting.ADVANCED -> navController.navigateToAdvancedPreferences()
Setting.ABOUT -> navController.navigateToAboutPreferences()
}
}
Expand All @@ -68,6 +71,9 @@ fun NavGraphBuilder.settingsNavGraph(
subtitlePreferencesScreen(
onNavigateUp = navController::navigateUp
)
advancedPreferencesScreen(
onNavigateUp = navController::navigateUp
)
aboutPreferencesScreen(
onNavigateUp = navController::navigateUp
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,20 @@ data class PlayerPreferences(
val applyEmbeddedStyles: Boolean = true,

// Decoder Preferences
val decoderPriority: DecoderPriority = DecoderPriority.PREFER_DEVICE
)
val decoderPriority: DecoderPriority = DecoderPriority.PREFER_DEVICE,

// Network Preferences
val minBufferMs: Int = DEFAULT_MIN_BUFFER_MS,
val maxBufferMs: Int = DEFAULT_MAX_BUFFER_MS,
val bufferForPlaybackMs: Int = DEFAULT_BUFFER_FOR_PLAYBACK_MS,
val bufferForPlaybackAfterRebuffer: Int = DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
val httpUserAgent: String? = null,
val httpHeaders: Map<String, String> = emptyMap()
) {
companion object {
const val DEFAULT_MIN_BUFFER_MS = 50_000
const val DEFAULT_MAX_BUFFER_MS = 50_000
const val DEFAULT_BUFFER_FOR_PLAYBACK_MS = 2500
const val DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 5000
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import androidx.compose.material.icons.rounded.FormatBold
import androidx.compose.material.icons.rounded.FormatSize
import androidx.compose.material.icons.rounded.Headset
import androidx.compose.material.icons.rounded.HeadsetOff
import androidx.compose.material.icons.rounded.Http
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Link
import androidx.compose.material.icons.rounded.LocalMovies
Expand All @@ -47,6 +48,7 @@ import androidx.compose.material.icons.rounded.Replay10
import androidx.compose.material.icons.rounded.ResetTv
import androidx.compose.material.icons.rounded.ScreenRotationAlt
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material.icons.rounded.SettingsSuggest
import androidx.compose.material.icons.rounded.Share
import androidx.compose.material.icons.rounded.SmartButton
import androidx.compose.material.icons.rounded.Speed
Expand All @@ -55,6 +57,7 @@ import androidx.compose.material.icons.rounded.Style
import androidx.compose.material.icons.rounded.Subtitles
import androidx.compose.material.icons.rounded.Swipe
import androidx.compose.material.icons.rounded.SwipeVertical
import androidx.compose.material.icons.rounded.Timelapse
import androidx.compose.material.icons.rounded.Timer
import androidx.compose.material.icons.rounded.Title
import androidx.compose.material.icons.rounded.TouchApp
Expand All @@ -70,6 +73,7 @@ object NextIcons {
val Background = Icons.Rounded.FlipToBack
val Bold = Icons.Rounded.FormatBold
val Brightness = Icons.Rounded.BrightnessHigh
val Buffer = Icons.Rounded.Timelapse
val Calendar = Icons.Rounded.CalendarMonth
val Caption = Icons.Rounded.ClosedCaption
val Check = Icons.Rounded.Check
Expand All @@ -91,12 +95,15 @@ object NextIcons {
val FontSize = Icons.Rounded.FormatSize
val Headset = Icons.Rounded.Headset
val HeadsetOff = Icons.Rounded.HeadsetOff
val HttpUserAgent = Icons.Rounded.Http
val HttpHeaders = Icons.Rounded.Http
val Info = Icons.Rounded.Info
val Language = Icons.Rounded.Translate
val Length = Icons.Rounded.Straighten
val Link = Icons.Rounded.Link
val Location = Icons.Rounded.LocationOn
val Movie = Icons.Rounded.LocalMovies
val Advanced = Icons.Rounded.SettingsSuggest
val Pip = Icons.Rounded.PictureInPictureAlt
val Pinch = Icons.Rounded.Pinch
val Play = Icons.Rounded.PlayArrow
Expand Down
17 changes: 17 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
<string name="subtitle_background_desc">Enable background to subtitle text</string>
<string name="decoder">Decoder</string>
<string name="decoder_desc">Decoder priority, playback decoder options</string>
<string name="advanced">Advanced</string>
<string name="advanced_desc">Buffer sizes, network request options</string>
<string name="video_software_decoders">Software video decoders</string>
<string name="video_software_decoders_desc">Use application software video decoders (experimental)</string>
<string name="decoder_priority">Decoder priority</string>
Expand All @@ -140,6 +142,7 @@
<string name="controller_timeout">Controller timeout</string>
<string name="seek_increment">Seek increment</string>
<string name="seconds">%1$s seconds</string>
<string name="milliseconds">%1$s milliseconds</string>
<string name="share">Share</string>
<string name="delete">Delete</string>
<string name="delete_file">The following file will be deleted permanently</string>
Expand Down Expand Up @@ -199,4 +202,18 @@
<string name="open_network_stream">Open network stream</string>
<string name="exit">Exit</string>
<string name="play_next_video">Play next video</string>
<string name="min_buffer_title">Min buffer</string>
<string name="min_buffer_description">The minimum duration of media that the player will attempt to ensure is buffered at all times</string>
<string name="max_buffer_title">Max buffer</string>
<string name="max_buffer_description">The maximum duration of media that the player will attempt to buffer</string>
<string name="buffer_for_playback_title">Buffer for playback</string>
<string name="buffer_for_playback_description">The duration of media that must be buffered for playback to start or resume following a user action such as a seek</string>
<string name="buffer_for_playback_after_rebuffer_title">Buffer for playback after rebuffer</string>
<string name="buffer_for_playback_after_rebuffer_description">The duration of media that must be buffered for playback to resume after a rebuffer. A rebuffer is defined to be caused by buffer depletion rather than a user action.</string>
<string name="reset_to_default">Default</string>
<string name="http_user_agent_title">HTTP User-Agent</string>
<string name="http_user_agent_placeholder">Example: Mozilla/5.0…</string>
<string name="http_headers_title">HTTP headers</string>
<string name="http_headers_placeholder">Example: key1=value1,key2=value2,…</string>
<string name="empty">Empty</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.Tracks
import androidx.media3.common.VideoSize
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.session.MediaSession
import androidx.media3.ui.AspectRatioFrameLayout
Expand Down Expand Up @@ -325,7 +329,7 @@ class PlayerActivity : AppCompatActivity() {

@RequiresApi(Build.VERSION_CODES.O)
private fun updatePictureInPictureParams(): PictureInPictureParams {
var params: PictureInPictureParams = PictureInPictureParams.Builder()
val params: PictureInPictureParams = PictureInPictureParams.Builder()
.setAspectRatio(Rational(16, 9))
.build()

Expand Down Expand Up @@ -354,11 +358,28 @@ class PlayerActivity : AppCompatActivity() {
)
}

val httpDataSourceFactory = DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(playerPreferences.httpHeaders)
playerPreferences.httpUserAgent.let { httpDataSourceFactory.setUserAgent(it) }

val dataSourceFactory = DefaultDataSource.Factory(applicationContext, httpDataSourceFactory)

val loadControl = DefaultLoadControl.Builder()
.setBufferDurationsMs(
playerPreferences.minBufferMs,
playerPreferences.maxBufferMs,
playerPreferences.bufferForPlaybackMs,
playerPreferences.bufferForPlaybackAfterRebuffer
)
.build()

player = ExoPlayer.Builder(applicationContext)
.setRenderersFactory(renderersFactory)
.setTrackSelector(trackSelector)
.setAudioAttributes(getAudioAttributes(), playerPreferences.requireAudioFocus)
.setHandleAudioBecomingNoisy(playerPreferences.pauseOnHeadsetDisconnect)
.setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory))
.setLoadControl(loadControl)
.build()

try {
Expand Down Expand Up @@ -603,7 +624,7 @@ class PlayerActivity : AppCompatActivity() {
val alertDialog = MaterialAlertDialogBuilder(this@PlayerActivity).apply {
setTitle(getString(coreUiR.string.error_playing_video))
setMessage(error.message ?: getString(coreUiR.string.unknown_error))
setNegativeButton(getString(coreUiR.string.exit)) { dialog, _ ->
setNegativeButton(getString(coreUiR.string.exit)) { _, _ ->
finish()
}
if (playlistManager.hasNext()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import dev.anilbeesetti.nextplayer.core.data.models.VideoState
import dev.anilbeesetti.nextplayer.core.data.repository.MediaRepository
import dev.anilbeesetti.nextplayer.core.data.repository.PreferencesRepository
import dev.anilbeesetti.nextplayer.core.domain.GetSortedPlaylistUseCase
import dev.anilbeesetti.nextplayer.core.model.ApplicationPreferences
import dev.anilbeesetti.nextplayer.core.model.PlayerPreferences
import dev.anilbeesetti.nextplayer.core.model.Resume
import dev.anilbeesetti.nextplayer.core.model.VideoZoom
import dev.anilbeesetti.nextplayer.feature.player.extensions.isSchemaContent
import javax.inject.Inject
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import timber.log.Timber

private const val END_POSITION_OFFSET = 5L
Expand All @@ -41,13 +41,13 @@ class PlayerViewModel @Inject constructor(
val playerPrefs = preferencesRepository.playerPreferences.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = PlayerPreferences()
initialValue = runBlocking { preferencesRepository.playerPreferences.first() }
)

val appPrefs = preferencesRepository.applicationPreferences.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = ApplicationPreferences()
initialValue = runBlocking { preferencesRepository.applicationPreferences.first() }
)

suspend fun updateState(uri: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ fun SettingsScreen(
icon = NextIcons.Subtitle,
onClick = { onItemClick(Setting.SUBTITLE) }
)
ClickablePreferenceItem(
title = stringResource(R.string.advanced),
description = stringResource(R.string.advanced_desc),
icon = NextIcons.Advanced,
onClick = { onItemClick(Setting.ADVANCED) }
)
ClickablePreferenceItem(
title = stringResource(id = R.string.about_name),
description = stringResource(id = R.string.about_description),
Expand All @@ -113,5 +119,6 @@ enum class Setting {
DECODER,
AUDIO,
SUBTITLE,
ADVANCED,
ABOUT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.anilbeesetti.nextplayer.settings.navigation

import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import dev.anilbeesetti.nextplayer.core.ui.designsystem.animatedComposable
import dev.anilbeesetti.nextplayer.settings.screens.advanced.AdvancedPreferencesScreen

const val advancedPreferencesNavigationRoute = "advanced_preferences_route"

fun NavController.navigateToAdvancedPreferences(navOptions: NavOptions? = androidx.navigation.navOptions { launchSingleTop = true }) {
this.navigate(advancedPreferencesNavigationRoute, navOptions)
}

fun NavGraphBuilder.advancedPreferencesScreen(onNavigateUp: () -> Unit) {
animatedComposable(route = advancedPreferencesNavigationRoute) {
AdvancedPreferencesScreen(onNavigateUp = onNavigateUp)
}
}
Loading
Loading