From 57bc32b7528b932b7165bd913f29741916950231 Mon Sep 17 00:00:00 2001 From: qnga <32197639+qnga@users.noreply.github.com> Date: Sat, 8 Jul 2023 16:58:24 +0200 Subject: [PATCH] Various changes on media3-based navigators (#363) --- ...avigator.kt => TimeBasedMediaNavigator.kt} | 6 ++--- .../media3/audio/AudioEngineProvider.kt | 2 +- ...udiobookNavigator.kt => AudioNavigator.kt} | 20 ++++++++--------- .../media3/audio/AudioNavigatorFactory.kt | 4 ++-- .../media3/exoplayer/ExoPlayerAliases.kt | 4 ++-- ...ioNavigator.kt => GuidedMediaNavigator.kt} | 22 +++++++++---------- .../r2/navigator/media3/tts/TtsNavigator.kt | 10 ++++++++- .../media3/tts/android/AndroidTtsEngine.kt | 22 +++++++++++-------- .../r2/testapp/reader/AudioReaderFragment.kt | 8 +++---- 9 files changed, 55 insertions(+), 43 deletions(-) rename readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/{AudioNavigator.kt => TimeBasedMediaNavigator.kt} (88%) rename readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/{AudiobookNavigator.kt => AudioNavigator.kt} (91%) rename readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/{GuidedAudioNavigator.kt => GuidedMediaNavigator.kt} (80%) diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/AudioNavigator.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/TimeBasedMediaNavigator.kt similarity index 88% rename from readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/AudioNavigator.kt rename to readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/TimeBasedMediaNavigator.kt index 41227cacb4..8c5d89e5e7 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/AudioNavigator.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/TimeBasedMediaNavigator.kt @@ -11,11 +11,11 @@ import kotlinx.coroutines.flow.StateFlow import org.readium.r2.shared.ExperimentalReadiumApi /** - * A [MediaNavigator] which can play audio files. + * A [MediaNavigator] whose locations provide time offsets. */ @ExperimentalReadiumApi -interface AudioNavigator : MediaNavigator { +interface TimeBasedMediaNavigator : MediaNavigator { /** * Location of the navigator. diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioEngineProvider.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioEngineProvider.kt index 39a352c128..21ea7681a6 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioEngineProvider.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioEngineProvider.kt @@ -14,7 +14,7 @@ import org.readium.r2.shared.publication.Metadata import org.readium.r2.shared.publication.Publication /** - * To be implemented by adapters for third-party audio engines which can be used with [AudiobookNavigator]. + * To be implemented by adapters for third-party audio engines which can be used with [AudioNavigator]. */ @ExperimentalReadiumApi interface AudioEngineProvider, diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudiobookNavigator.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioNavigator.kt similarity index 91% rename from readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudiobookNavigator.kt rename to readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioNavigator.kt index 94f541cd0e..172c30c9ed 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudiobookNavigator.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioNavigator.kt @@ -16,9 +16,9 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.StateFlow import org.readium.r2.navigator.extensions.sum import org.readium.r2.navigator.extensions.time -import org.readium.r2.navigator.media3.api.AudioNavigator import org.readium.r2.navigator.media3.api.Media3Adapter import org.readium.r2.navigator.media3.api.MediaNavigator +import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator import org.readium.r2.navigator.preferences.Configurable import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.extensions.mapStateIn @@ -30,13 +30,13 @@ import timber.log.Timber @ExperimentalReadiumApi @OptIn(ExperimentalTime::class) -class AudiobookNavigator> private constructor( +class AudioNavigator> private constructor( override val publication: Publication, private val audioEngine: AudioEngine, override val readingOrder: ReadingOrder, ) : - MediaNavigator, - AudioNavigator, + MediaNavigator, + TimeBasedMediaNavigator, Media3Adapter, Configurable by audioEngine { @@ -48,7 +48,7 @@ class AudiobookNavigator = publication.readingOrder, initialPreferences: P? = null, initialLocator: Locator? = null, - ): AudiobookNavigator? { + ): AudioNavigator? { if (readingOrder.isEmpty()) { return null } @@ -71,7 +71,7 @@ class AudiobookNavigator - ) : AudioNavigator.ReadingOrder { + ) : TimeBasedMediaNavigator.ReadingOrder { data class Item( val href: Href, override val duration: Duration? - ) : AudioNavigator.ReadingOrder.Item + ) : TimeBasedMediaNavigator.ReadingOrder.Item } data class Playback( @@ -109,7 +109,7 @@ class AudiobookNavigator? { - return AudiobookNavigator( + ): AudioNavigator? { + return AudioNavigator( publication = publication, audioEngineProvider = audioEngineProvider, initialPreferences = initialPreferences, diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/exoplayer/ExoPlayerAliases.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/exoplayer/ExoPlayerAliases.kt index 792af970b5..9230ce5a2f 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/exoplayer/ExoPlayerAliases.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/exoplayer/ExoPlayerAliases.kt @@ -6,12 +6,12 @@ package org.readium.r2.navigator.media3.exoplayer +import org.readium.r2.navigator.media3.audio.AudioNavigator import org.readium.r2.navigator.media3.audio.AudioNavigatorFactory -import org.readium.r2.navigator.media3.audio.AudiobookNavigator import org.readium.r2.shared.ExperimentalReadiumApi @OptIn(ExperimentalReadiumApi::class) typealias ExoPlayerNavigatorFactory = AudioNavigatorFactory @OptIn(ExperimentalReadiumApi::class) -typealias ExoPlayerNavigator = AudiobookNavigator +typealias ExoPlayerNavigator = AudioNavigator diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedAudioNavigator.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedMediaNavigator.kt similarity index 80% rename from readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedAudioNavigator.kt rename to readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedMediaNavigator.kt index ea66c750f9..1c01c0c68b 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedAudioNavigator.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedMediaNavigator.kt @@ -9,11 +9,11 @@ package org.readium.r2.navigator.media3.syncmedia import androidx.media3.common.Player import kotlin.time.Duration import kotlinx.coroutines.flow.StateFlow -import org.readium.r2.navigator.media3.api.AudioNavigator import org.readium.r2.navigator.media3.api.Media3Adapter import org.readium.r2.navigator.media3.api.MediaNavigator import org.readium.r2.navigator.media3.api.TextAwareMediaNavigator -import org.readium.r2.navigator.media3.audio.AudiobookNavigator +import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator +import org.readium.r2.navigator.media3.audio.AudioNavigator import org.readium.r2.navigator.preferences.Configurable import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Link @@ -22,12 +22,12 @@ import org.readium.r2.shared.publication.Publication import org.readium.r2.shared.util.Href @ExperimentalReadiumApi -class GuidedAudioNavigator>( - private val audioNavigator: AudiobookNavigator, +class GuidedMediaNavigator>( + private val audioNavigator: AudioNavigator, ) : - MediaNavigator, - AudioNavigator, - TextAwareMediaNavigator, + MediaNavigator, + TimeBasedMediaNavigator, + TextAwareMediaNavigator, Media3Adapter, Configurable { @@ -41,7 +41,7 @@ class GuidedAudioNavigator - ) : AudioNavigator.ReadingOrder, TextAwareMediaNavigator.ReadingOrder { + ) : TimeBasedMediaNavigator.ReadingOrder, TextAwareMediaNavigator.ReadingOrder { data class Item( val href: Href, override val duration: Duration? - ) : AudioNavigator.ReadingOrder.Item, TextAwareMediaNavigator.ReadingOrder.Item + ) : TimeBasedMediaNavigator.ReadingOrder.Item, TextAwareMediaNavigator.ReadingOrder.Item } override val publication: Publication = diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/TtsNavigator.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/TtsNavigator.kt index b54fc5c4a4..a0b9953998 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/TtsNavigator.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/TtsNavigator.kt @@ -44,7 +44,7 @@ class TtsNavigator, MediaNavigator, TextAwareMediaNavigator, Media3Adapter, - Configurable by player { + Configurable { companion object { @@ -247,6 +247,14 @@ class TtsNavigator, return true } + override val settings: StateFlow = + player.settings + + override fun submitPreferences(preferences: P) { + player.submitPreferences(preferences) + player.restartUtterance() + } + private fun navigatorPlayback(playback: TtsPlayer.Playback, utterance: TtsPlayer.Utterance) = Playback( state = playback.state.toState(), diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/android/AndroidTtsEngine.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/android/AndroidTtsEngine.kt index 46f2b6dfa8..f909547422 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/android/AndroidTtsEngine.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/android/AndroidTtsEngine.kt @@ -400,19 +400,23 @@ class AndroidTtsEngine private constructor( utteranceLanguage: Language?, voices: Set ): Boolean { - var language = utteranceLanguage + val language = utteranceLanguage .takeUnless { settings.overrideContentLanguage } + // We take utterance language if data are missing but not if the language is not supported + ?.takeIf { isLanguageAvailable(it.locale) != LANG_NOT_SUPPORTED } ?: settings.language + .takeIf { isLanguageAvailable(it.locale) != LANG_NOT_SUPPORTED } + ?: defaultVoice?.locale?.let { Language(it) } - utteranceListener?.onError(id, Error.LanguageMissingData(language)) - return false + if (language == null) { + // We don't know what to do. + utteranceListener?.onError(id, Error.Unknown) + return false + } - when (isLanguageAvailable(language.locale)) { - LANG_MISSING_DATA -> { - utteranceListener?.onError(id, Error.LanguageMissingData(language)) - return false - } - LANG_NOT_SUPPORTED -> language = Language(defaultVoice.locale) + if (isLanguageAvailable(language.locale) < LANG_AVAILABLE) { + utteranceListener?.onError(id, Error.LanguageMissingData(language)) + return false } val preferredVoiceWithRegion = diff --git a/test-app/src/main/java/org/readium/r2/testapp/reader/AudioReaderFragment.kt b/test-app/src/main/java/org/readium/r2/testapp/reader/AudioReaderFragment.kt index df5b54970c..a7322e9288 100644 --- a/test-app/src/main/java/org/readium/r2/testapp/reader/AudioReaderFragment.kt +++ b/test-app/src/main/java/org/readium/r2/testapp/reader/AudioReaderFragment.kt @@ -23,8 +23,8 @@ import kotlin.time.DurationUnit import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import org.readium.r2.navigator.media3.api.AudioNavigator import org.readium.r2.navigator.media3.api.MediaNavigator +import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator import org.readium.r2.navigator.media3.exoplayer.ExoPlayerPreferences import org.readium.r2.navigator.media3.exoplayer.ExoPlayerSettings import org.readium.r2.navigator.preferences.Configurable @@ -40,7 +40,7 @@ import timber.log.Timber @OptIn(ExperimentalReadiumApi::class) class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListener { - override lateinit var navigator: AudioNavigator<*, *, *> + override lateinit var navigator: TimeBasedMediaNavigator<*, *, *> private var binding: FragmentAudiobookBinding by viewLifecycle() private var seekingItem: Int? = null @@ -88,7 +88,7 @@ class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListene .launchIn(viewLifecycleOwner.lifecycleScope) } - private fun onPlaybackChanged(playback: AudioNavigator.Playback) { + private fun onPlaybackChanged(playback: TimeBasedMediaNavigator.Playback) { Timber.v("onPlaybackChanged $playback") if (playback.state is MediaNavigator.State.Error) { onPlayerError() @@ -111,7 +111,7 @@ class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListene } } - private fun updateTimeline(playback: AudioNavigator.Playback) { + private fun updateTimeline(playback: TimeBasedMediaNavigator.Playback) { val currentItem = navigator.readingOrder.items[playback.index] binding.timelineBar.max = currentItem.duration?.inWholeSeconds?.toInt() ?: 0 binding.timelineDuration.text = currentItem.duration?.formatElapsedTime()