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 @@ -407,6 +407,7 @@ public void play(long position) {

protected void play(long position, @Nullable Integer forcedSubtitleIndex) {
String forcedAudioLanguage = videoQueueManager.getValue().getLastPlayedAudioLanguageIsoCode();
String forcedAudioCodec = videoQueueManager.getValue().getLastPlayedAudioCodec();
Timber.i("Play called from state: %s with pos: %d, sub index: %d and forced audio: %s", mPlaybackState, position, forcedSubtitleIndex, forcedAudioLanguage);

if (mFragment == null) {
Expand Down Expand Up @@ -496,7 +497,7 @@ public void onClick(DialogInterface dialog, int which) {
// undo setting mSeekPosition for liveTV
if (isLiveTv) mSeekPosition = -1;

VideoOptions internalOptions = buildExoPlayerOptions(forcedSubtitleIndex, forcedAudioLanguage, item);
VideoOptions internalOptions = buildExoPlayerOptions(forcedSubtitleIndex, forcedAudioLanguage, forcedAudioCodec, item);

playInternal(getCurrentlyPlayingItem(), position, internalOptions);
mPlaybackState = PlaybackState.BUFFERING;
Expand All @@ -515,6 +516,7 @@ public void onClick(DialogInterface dialog, int which) {
private VideoOptions buildExoPlayerOptions(
@Nullable Integer forcedSubtitleIndex,
@Nullable String forcedAudioLanguage,
@Nullable String forcedAudioCodec,
BaseItemDto item) {
VideoOptions internalOptions = new VideoOptions();
internalOptions.setItemId(item.getId());
Expand All @@ -530,14 +532,27 @@ private VideoOptions buildExoPlayerOptions(
internalOptions.setSubtitleStreamIndex(forcedSubtitleIndex);
}
MediaSourceInfo currentMediaSource = getCurrentMediaSource();
if (forcedAudioLanguage != null) {
// find the first audio stream with the requested language
for (MediaStream stream : currentMediaSource.getMediaStreams()) {
if (stream.getType() == MediaStreamType.AUDIO && forcedAudioLanguage.equals(stream.getLanguage())) {
internalOptions.setAudioStreamIndex(stream.getIndex());
break;
if (forcedAudioLanguage != null){
Integer matchingIndex = null;
if (forcedAudioCodec != null) {
// find the first audio stream with the requested language and codec
for (MediaStream stream : currentMediaSource.getMediaStreams()) {
if (stream.getType() == MediaStreamType.AUDIO && forcedAudioLanguage.equals(stream.getLanguage()) && forcedAudioCodec.equals(stream.getCodec())) {
matchingIndex = stream.getIndex();
break;
}
}
}
if (matchingIndex == null) {
// find the first audio stream with the requested language (fallback to language only)
for (MediaStream stream : currentMediaSource.getMediaStreams()) {
if (stream.getType() == MediaStreamType.AUDIO && forcedAudioLanguage.equals(stream.getLanguage())) {
matchingIndex = stream.getIndex();
break;
}
}
}
internalOptions.setAudioStreamIndex(matchingIndex);
}
if (!isLiveTv && currentMediaSource != null) {
internalOptions.setMediaSourceId(currentMediaSource.getId());
Expand Down Expand Up @@ -645,17 +660,43 @@ private void startItem(BaseItemDto item, long position, StreamInfo response) {

// get subtitle info - prefer saved language preference over server default
String lastSubtitleLanguage = videoQueueManager.getValue().getLastPlayedSubtitleLanguageIsoCode();
Boolean lastSubtitleForcedState = videoQueueManager.getValue().getLastPlayedSubtitleForcedState();
String lastSubtitleCodec = videoQueueManager.getValue().getLastPlayedSubtitleCodec();
String lastSubtitleTitle = videoQueueManager.getValue().getLastPlayedSubtitleTitle();
if (lastSubtitleLanguage != null) {
if (lastSubtitleLanguage.isEmpty()) {
// User explicitly disabled subtitles
mCurrentOptions.setSubtitleStreamIndex(null);
} else if (response.getMediaSource().getMediaStreams() != null) {
// Find subtitle stream matching saved language
Integer matchingIndex = null;
for (MediaStream stream : response.getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.SUBTITLE && lastSubtitleLanguage.equals(stream.getLanguage())) {
matchingIndex = stream.getIndex();
break;
// Try with all previous subtitle info (title, codec, tag, lang)
if (lastSubtitleCodec != null && lastSubtitleTitle != null) {
for (MediaStream stream : response.getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.SUBTITLE && lastSubtitleLanguage.equals(stream.getLanguage()) && lastSubtitleForcedState.equals(stream.isForced()) && lastSubtitleCodec.equals(stream.getCodec()) && lastSubtitleTitle.equals(stream.getTitle())) {
matchingIndex = stream.getIndex();
break;
}
}
}
// Fallback without title (codec, tag, lang)
if (matchingIndex == null) {
if (lastSubtitleCodec != null) {
for (MediaStream stream : response.getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.SUBTITLE && lastSubtitleLanguage.equals(stream.getLanguage()) && lastSubtitleForcedState.equals(stream.isForced()) && lastSubtitleCodec.equals(stream.getCodec())) {
matchingIndex = stream.getIndex();
break;
}
}
}
}
// Fallback to another Codec Tag (tag, lang)
if (matchingIndex == null) {
for (MediaStream stream : response.getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.SUBTITLE && lastSubtitleLanguage.equals(stream.getLanguage()) && lastSubtitleForcedState.equals(stream.isForced())) {
matchingIndex = stream.getIndex();
break;
}
}
}
mCurrentOptions.setSubtitleStreamIndex(matchingIndex);
Expand Down Expand Up @@ -756,6 +797,22 @@ private Integer lastChosenLanguageAudioTrack(MediaSourceInfo info) {
return null;

boolean videoFound = false;
for (MediaStream track : info.getMediaStreams()) {
if (track.getType() == MediaStreamType.VIDEO) {
videoFound = true;
} else {
if (videoFound
&& track.getType() == MediaStreamType.AUDIO
&& (track.getLanguage() != null
&& track.getLanguage().equals(videoQueueManager.getValue().getLastPlayedAudioLanguageIsoCode())
&& (track.getCodec() != null
&& track.getCodec().equals(videoQueueManager.getValue().getLastPlayedAudioCodec())))
)
return track.getIndex();
}
}

videoFound = false;
for (MediaStream track : info.getMediaStreams()) {
if (track.getType() == MediaStreamType.VIDEO) {
videoFound = true;
Expand Down Expand Up @@ -798,14 +855,13 @@ public void switchAudioStream(int index) {
return;
}

String lastAudioIsoCode = videoQueueManager.getValue().getLastPlayedAudioLanguageIsoCode();
String currentAudioIsoCode = currentMediaSource.getMediaStreams().get(index).getLanguage();

if (currentAudioIsoCode != null
&& (lastAudioIsoCode == null || !lastAudioIsoCode.equals(currentAudioIsoCode))) {
videoQueueManager.getValue().setLastPlayedAudioLanguageIsoCode(
currentAudioIsoCode
);
if (currentAudioIsoCode != null) {
videoQueueManager.getValue().setLastPlayedAudioLanguageIsoCode(currentAudioIsoCode);
String currentAudioCodec = currentMediaSource.getMediaStreams().get(index).getCodec();
if (currentAudioCodec != null) {
videoQueueManager.getValue().setLastPlayedAudioCodec(currentAudioCodec);
}
}

int currAudioIndex = getAudioStreamIndex();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ fun PlaybackController.disableDefaultSubtitles() {
@JvmOverloads
fun PlaybackController.setSubtitleIndex(index: Int, force: Boolean = false) {
Timber.i("Switching subtitles from index ${mCurrentOptions.subtitleStreamIndex} to $index")

// Already using this subtitle index
if (mCurrentOptions.subtitleStreamIndex == index && !force) return

Expand All @@ -64,9 +63,15 @@ fun PlaybackController.setSubtitleIndex(index: Int, force: Boolean = false) {
if (index == -1) {
// Use empty string to indicate "subtitles explicitly disabled" vs null meaning "no preference"
videoQueueManager.setLastPlayedSubtitleLanguageIsoCode("")
videoQueueManager.setLastPlayedSubtitleForcedState(false)
videoQueueManager.setLastPlayedSubtitleCodec(null)
videoQueueManager.setLastPlayedSubtitleTitle(null)
} else {
val stream = currentMediaSource.mediaStreams?.firstOrNull { it.type == MediaStreamType.SUBTITLE && it.index == index }
videoQueueManager.setLastPlayedSubtitleLanguageIsoCode(stream?.language)
videoQueueManager.setLastPlayedSubtitleForcedState(stream?.isForced ?: false)
videoQueueManager.setLastPlayedSubtitleCodec(stream?.codec)
videoQueueManager.setLastPlayedSubtitleTitle(stream?.title)
}

// Disable subtitles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ class VideoQueueManager {
private var _currentVideoQueue: List<BaseItemDto> = emptyList()
private var _currentMediaPosition = -1
private var _lastPlayedAudioLanguageIsoCode: String? = null
private var _lastPlayedAudioCodec: String? = null
private var _lastPlayedSubtitleLanguageIsoCode: String? = null
private var _lastPlayedSubtitleForcedState: Boolean = false
private var _lastPlayedSubtitleCodec: String? = null
private var _lastPlayedSubtitleTitle: String? = null

fun setCurrentVideoQueue(items: List<BaseItemDto>?) {
if (items.isNullOrEmpty()) return clearVideoQueue()
Expand All @@ -33,6 +37,14 @@ class VideoQueueManager {
_lastPlayedAudioLanguageIsoCode = isoCode
}

fun getLastPlayedAudioCodec(): String? {
return _lastPlayedAudioCodec
}

fun setLastPlayedAudioCodec(codec: String) {
_lastPlayedAudioCodec = codec
}

fun getLastPlayedSubtitleLanguageIsoCode(): String? {
return _lastPlayedSubtitleLanguageIsoCode
}
Expand All @@ -41,10 +53,38 @@ class VideoQueueManager {
_lastPlayedSubtitleLanguageIsoCode = isoCode
}

fun getLastPlayedSubtitleForcedState(): Boolean {
return _lastPlayedSubtitleForcedState
}

fun setLastPlayedSubtitleForcedState(state: Boolean) {
_lastPlayedSubtitleForcedState = state
}

fun getLastPlayedSubtitleCodec(): String? {
return _lastPlayedSubtitleCodec
}

fun setLastPlayedSubtitleCodec(codecTag: String?) {
_lastPlayedSubtitleCodec = codecTag
}

fun getLastPlayedSubtitleTitle(): String? {
return _lastPlayedSubtitleTitle
}

fun setLastPlayedSubtitleTitle(title: String?) {
_lastPlayedSubtitleTitle = title
}

fun clearVideoQueue() {
_currentVideoQueue = emptyList()
_currentMediaPosition = -1
_lastPlayedAudioLanguageIsoCode = null
_lastPlayedAudioCodec = null
_lastPlayedSubtitleLanguageIsoCode = null
_lastPlayedSubtitleForcedState = false
_lastPlayedSubtitleCodec = null
_lastPlayedSubtitleTitle = null
}
}