Skip to content
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 @@ -391,7 +391,10 @@ sealed interface AppPreference<Pref, T> {
defaultValue = true,
getter = { it.playbackPreferences.overrides.ac3Supported },
setter = { prefs, value ->
prefs.updatePlaybackOverrides { ac3Supported = value }
prefs.updatePlaybackOverrides {
ac3Supported = value
if (!value) spdifArcSurroundAudio = false
}
},
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
Expand All @@ -402,7 +405,10 @@ sealed interface AppPreference<Pref, T> {
defaultValue = false,
getter = { it.playbackPreferences.overrides.downmixStereo },
setter = { prefs, value ->
prefs.updatePlaybackOverrides { downmixStereo = value }
prefs.updatePlaybackOverrides {
downmixStereo = value
if (value) spdifArcSurroundAudio = false
}
},
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
Expand Down Expand Up @@ -455,6 +461,28 @@ sealed interface AppPreference<Pref, T> {
summaryOff = R.string.disabled,
)

val SpdifArcSurroundAudio =
AppSwitchPreference<AppPreferences>(
title = R.string.spdif_arc_surround_audio,
defaultValue = false,
getter = { it.playbackPreferences.overrides.spdifArcSurroundAudio },
setter = { prefs, value ->
if (value) {
prefs.updatePlaybackOverrides {
spdifArcSurroundAudio = true
ac3Supported = true
downmixStereo = false
}
} else {
prefs.updatePlaybackOverrides {
spdifArcSurroundAudio = false
}
}
},
summaryOn = R.string.spdif_arc_surround_audio_summary_on,
summaryOff = R.string.spdif_arc_surround_audio_summary_off,
)

val CinemaMode =
AppSwitchPreference<AppPreferences>(
title = R.string.cinema_mode,
Expand Down Expand Up @@ -1108,6 +1136,7 @@ private val ExoPlayerSettings =
AppPreference.FfmpegPreference,
AppPreference.DownMixStereo,
AppPreference.Ac3Supported,
AppPreference.SpdifArcSurroundAudio,
AppPreference.AssSubtitleMode,
AppPreference.DirectPlayPgs,
AppPreference.DirectPlayDoviProfile7,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class AppPreferencesSerializer
AppPreference.FfmpegPreference.defaultValue
assPlaybackMode =
AppPreference.AssSubtitleMode.defaultValue
spdifArcSurroundAudio =
AppPreference.SpdifArcSurroundAudio.defaultValue
}.build()

mpvOptions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class DeviceProfileService
decodeAv1 = prefs.overrides.decodeAv1,
jellyfinTenEleven =
serverVersion != null && serverVersion >= ServerVersion(10, 11, 0),
spdifArcSurroundAudio = prefs.overrides.spdifArcSurroundAudio,
)
if (deviceProfile == null || this@DeviceProfileService.configuration != newConfig) {
this@DeviceProfileService.configuration = newConfig
Expand All @@ -64,6 +65,7 @@ class DeviceProfileService
dolbyVisionELDirectPlay = newConfig.dolbyVisionELDirectPlay,
decodeAv1 = prefs.overrides.decodeAv1,
jellyfinTenEleven = newConfig.jellyfinTenEleven,
spdifArcSurroundAudio = newConfig.spdifArcSurroundAudio,
)
}
this@DeviceProfileService.deviceProfile!!
Expand All @@ -83,4 +85,5 @@ data class DeviceProfileConfiguration(
val dolbyVisionELDirectPlay: Boolean,
val decodeAv1: Boolean,
val jellyfinTenEleven: Boolean,
val spdifArcSurroundAudio: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.github.damontecres.wholphin.util.BlockingList
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.PlaybackItemState
import com.github.damontecres.wholphin.util.TrackActivityPlaybackListener
import com.github.damontecres.wholphin.util.profile.Codec
import com.github.damontecres.wholphin.util.profile.supportedAudioCodecs
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
Expand All @@ -44,6 +45,7 @@ import org.jellyfin.sdk.api.client.extensions.universalAudioApi
import org.jellyfin.sdk.api.sockets.subscribe
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.ImageType
import org.jellyfin.sdk.model.api.MediaStreamType
import org.jellyfin.sdk.model.api.PlayMethod
import org.jellyfin.sdk.model.api.PlaystateCommand
import org.jellyfin.sdk.model.api.PlaystateMessage
Expand Down Expand Up @@ -72,6 +74,7 @@ class MusicService
private val playerFactory: PlayerFactory,
private val serverRepository: ServerRepository,
private val imageUrlService: ImageUrlService,
private val userPreferencesService: UserPreferencesService,
) {
private val _state = MutableStateFlow(MusicServiceState.EMPTY)
val state: StateFlow<MusicServiceState> = _state
Expand Down Expand Up @@ -198,7 +201,7 @@ class MusicService
val mediaItems =
items
.filter { it.type == BaseItemKind.AUDIO }
.map(::convert)
.map { convert(it) }
withContext(Dispatchers.Main) {
player.setMediaItems(mediaItems)
player.shuffleModeEnabled = shuffled
Expand Down Expand Up @@ -250,7 +253,7 @@ class MusicService
list
.getBlocking(it)
?.takeIf { it.type == BaseItemKind.AUDIO }
?.let(::convert)
?.let { convert(it) }
} else {
Timber.v("Skipping $remaining")
remaining--
Expand All @@ -266,12 +269,39 @@ class MusicService
/**
* Converts a [BaseItem] into a [MediaItem] setting an [AudioItem] as its tag
*/
private fun convert(audio: BaseItem): MediaItem {
private suspend fun convert(audio: BaseItem): MediaItem {
val spdifMode =
userPreferencesService
.getCurrent()
.appPreferences.playbackPreferences.overrides.spdifArcSurroundAudio

val needsAc3Transcode =
spdifMode &&
audio.data.mediaSources
?.firstOrNull()
?.mediaStreams
?.any { stream ->
stream.type == MediaStreamType.AUDIO &&
(stream.channels ?: 0) > 2 &&
stream.codec != Codec.Audio.AC3
} ?: false

val url =
api.universalAudioApi.getUniversalAudioStreamUrl(
itemId = audio.id,
container = audioFormats,
)
if (needsAc3Transcode) {
api.universalAudioApi.getUniversalAudioStreamUrl(
itemId = audio.id,
container = listOf("mka"),
transcodingContainer = "mka",
maxAudioChannels = 6,
transcodingAudioChannels = 6,
audioCodec = Codec.Audio.AC3,
)
} else {
api.universalAudioApi.getUniversalAudioStreamUrl(
itemId = audio.id,
container = audioFormats,
)
}
Timber.i("url=%s", url)
val imageUrl =
audio.data.albumId?.let { albumId ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import com.github.damontecres.wholphin.services.ScreensaverService
import com.github.damontecres.wholphin.services.StreamChoiceService
import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.ui.formatBitrate
import com.github.damontecres.wholphin.ui.gt
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.launchIO
Expand Down Expand Up @@ -653,7 +654,8 @@ class PlaybackViewModel
} else {
mpvDeviceProfile
},
maxAudioChannels = null,
maxAudioChannels =
if (preferences.appPreferences.playbackPreferences.overrides.spdifArcSurroundAudio) 6 else null,
audioStreamIndex = audioIndex,
subtitleStreamIndex = subtitleIndex,
mediaSourceId = currentItemPlayback.sourceId?.toServerString(),
Expand Down Expand Up @@ -844,12 +846,24 @@ class PlaybackViewModel
userInitiated: Boolean,
): Boolean =
withContext(Dispatchers.IO) {
// TODO there's probably no reason why we can't add external subtitles?
Timber.v("changeStreams direct play")

// Don't attempt DirectPlay if audio transcoding is required
if (preferences.appPreferences.playbackPreferences.overrides.spdifArcSurroundAudio && audioIndex != null) {
currentPlayback.mediaSourceInfo.mediaStreams
.orEmpty()
.firstOrNull { it.index == audioIndex }
?.let {
if (it.channels.gt(2) && it.codec != Codec.Audio.AC3) {
return@withContext false
}
}
}

val source = currentPlayback.mediaSourceInfo
val externalSubtitle = source.findExternalSubtitle(subtitleIndex)

// TODO there's probably no reason why we can't add external subtitles?
if (externalSubtitle == null) {
val result =
withContext(Dispatchers.Main) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ fun createDeviceProfile(
dolbyVisionELDirectPlay: Boolean,
decodeAv1: Boolean,
jellyfinTenEleven: Boolean,
spdifArcSurroundAudio: Boolean = false,
) = buildDeviceProfile {
val allowedAudioCodecs =
when {
Expand Down Expand Up @@ -142,7 +143,11 @@ fun createDeviceProfile(
if (supportsHevc) videoCodec(Codec.Video.HEVC)
videoCodec(Codec.Video.H264)

audioCodec(*allowedAudioCodecs)
if (spdifArcSurroundAudio) {
audioCodec(Codec.Audio.AC3)
} else {
audioCodec(*allowedAudioCodecs)
}

copyTimestamps = false
enableSubtitlesInManifest = true
Expand All @@ -156,7 +161,11 @@ fun createDeviceProfile(
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS

audioCodec(Codec.Audio.AAC)
if (spdifArcSurroundAudio) {
audioCodec(Codec.Audio.AC3)
} else {
audioCodec(Codec.Audio.AAC)
}
}

// / Direct play profiles
Expand Down Expand Up @@ -415,6 +424,29 @@ fun createDeviceProfile(
}
}

// SPDIF/ARC mode: restrict non-AC3 multichannel audio to stereo
// to force server to transcode only multichannel to AC3
if (spdifArcSurroundAudio) {
supportedAudioCodecs
.filterNot { it == Codec.Audio.AC3 }
.forEach { audioCodec ->
codecProfile {
type = CodecType.VIDEO_AUDIO
codec = audioCodec
conditions {
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals 2
}
}
codecProfile {
type = CodecType.AUDIO
codec = audioCodec
conditions {
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals 2
}
}
}
}

// / HDR exclude list

// TODO Use VideoRangeType enum with Jellyfin 10.11 based SDK
Expand Down Expand Up @@ -522,7 +554,12 @@ fun createDeviceProfile(
type = CodecType.VIDEO_AUDIO

conditions {
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals if (downMixAudio) 2 else 8
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals
when {
spdifArcSurroundAudio -> 6
downMixAudio -> 2
else -> 8
}
}
}

Expand Down
1 change: 1 addition & 0 deletions app/src/main/proto/WholphinDataStore.proto
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ message PlaybackOverrides{
bool direct_play_dolby_vision_e_l = 6;
bool decode_av1 = 7;
AssPlaybackMode ass_playback_mode = 8;
bool spdif_arc_surround_audio = 9;
}

message PlaybackPreferences {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -788,4 +788,7 @@
<item></item><!-- Intentionally blank -->
<item></item><!-- Intentionally blank -->
</array>
<string name="spdif_arc_surround_audio">SPDIF/ARC Surround Audio</string>
<string name="spdif_arc_surround_audio_summary_on">Force all audio to AC3 5.1 for SPDIF/ARC output</string>
<string name="spdif_arc_surround_audio_summary_off">Use default audio settings</string>
</resources>
Loading