Skip to content

Commit 57bc32b

Browse files
authored
Various changes on media3-based navigators (#363)
1 parent c868166 commit 57bc32b

File tree

9 files changed

+55
-43
lines changed

9 files changed

+55
-43
lines changed

readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/AudioNavigator.kt renamed to readium/navigator/src/main/java/org/readium/r2/navigator/media3/api/TimeBasedMediaNavigator.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import kotlinx.coroutines.flow.StateFlow
1111
import org.readium.r2.shared.ExperimentalReadiumApi
1212

1313
/**
14-
* A [MediaNavigator] which can play audio files.
14+
* A [MediaNavigator] whose locations provide time offsets.
1515
*/
1616
@ExperimentalReadiumApi
17-
interface AudioNavigator<L : AudioNavigator.Location, P : AudioNavigator.Playback,
18-
R : AudioNavigator.ReadingOrder> : MediaNavigator<L, P, R> {
17+
interface TimeBasedMediaNavigator<L : TimeBasedMediaNavigator.Location, P : TimeBasedMediaNavigator.Playback,
18+
R : TimeBasedMediaNavigator.ReadingOrder> : MediaNavigator<L, P, R> {
1919

2020
/**
2121
* Location of the navigator.

readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioEngineProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import org.readium.r2.shared.publication.Metadata
1414
import org.readium.r2.shared.publication.Publication
1515

1616
/**
17-
* To be implemented by adapters for third-party audio engines which can be used with [AudiobookNavigator].
17+
* To be implemented by adapters for third-party audio engines which can be used with [AudioNavigator].
1818
*/
1919
@ExperimentalReadiumApi
2020
interface AudioEngineProvider<S : Configurable.Settings, P : Configurable.Preferences<P>,

readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudiobookNavigator.kt renamed to readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioNavigator.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import kotlinx.coroutines.MainScope
1616
import kotlinx.coroutines.flow.StateFlow
1717
import org.readium.r2.navigator.extensions.sum
1818
import org.readium.r2.navigator.extensions.time
19-
import org.readium.r2.navigator.media3.api.AudioNavigator
2019
import org.readium.r2.navigator.media3.api.Media3Adapter
2120
import org.readium.r2.navigator.media3.api.MediaNavigator
21+
import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator
2222
import org.readium.r2.navigator.preferences.Configurable
2323
import org.readium.r2.shared.ExperimentalReadiumApi
2424
import org.readium.r2.shared.extensions.mapStateIn
@@ -30,13 +30,13 @@ import timber.log.Timber
3030

3131
@ExperimentalReadiumApi
3232
@OptIn(ExperimentalTime::class)
33-
class AudiobookNavigator<S : Configurable.Settings, P : Configurable.Preferences<P>> private constructor(
33+
class AudioNavigator<S : Configurable.Settings, P : Configurable.Preferences<P>> private constructor(
3434
override val publication: Publication,
3535
private val audioEngine: AudioEngine<S, P>,
3636
override val readingOrder: ReadingOrder,
3737
) :
38-
MediaNavigator<AudiobookNavigator.Location, AudiobookNavigator.Playback, AudiobookNavigator.ReadingOrder>,
39-
AudioNavigator<AudiobookNavigator.Location, AudiobookNavigator.Playback, AudiobookNavigator.ReadingOrder>,
38+
MediaNavigator<AudioNavigator.Location, AudioNavigator.Playback, AudioNavigator.ReadingOrder>,
39+
TimeBasedMediaNavigator<AudioNavigator.Location, AudioNavigator.Playback, AudioNavigator.ReadingOrder>,
4040
Media3Adapter,
4141
Configurable<S, P> by audioEngine {
4242

@@ -48,7 +48,7 @@ class AudiobookNavigator<S : Configurable.Settings, P : Configurable.Preferences
4848
readingOrder: List<Link> = publication.readingOrder,
4949
initialPreferences: P? = null,
5050
initialLocator: Locator? = null,
51-
): AudiobookNavigator<S, P>? {
51+
): AudioNavigator<S, P>? {
5252
if (readingOrder.isEmpty()) {
5353
return null
5454
}
@@ -71,7 +71,7 @@ class AudiobookNavigator<S : Configurable.Settings, P : Configurable.Preferences
7171
initialPreferences ?: audioEngineProvider.createEmptyPreferences()
7272
) ?: return null
7373

74-
return AudiobookNavigator(publication, audioEngine, actualReadingOrder)
74+
return AudioNavigator(publication, audioEngine, actualReadingOrder)
7575
}
7676

7777
private fun duration(link: Link, publication: Publication): Duration? {
@@ -90,17 +90,17 @@ class AudiobookNavigator<S : Configurable.Settings, P : Configurable.Preferences
9090
data class Location(
9191
override val href: Href,
9292
override val offset: Duration,
93-
) : AudioNavigator.Location
93+
) : TimeBasedMediaNavigator.Location
9494

9595
data class ReadingOrder(
9696
override val duration: Duration?,
9797
override val items: List<Item>
98-
) : AudioNavigator.ReadingOrder {
98+
) : TimeBasedMediaNavigator.ReadingOrder {
9999

100100
data class Item(
101101
val href: Href,
102102
override val duration: Duration?
103-
) : AudioNavigator.ReadingOrder.Item
103+
) : TimeBasedMediaNavigator.ReadingOrder.Item
104104
}
105105

106106
data class Playback(
@@ -109,7 +109,7 @@ class AudiobookNavigator<S : Configurable.Settings, P : Configurable.Preferences
109109
override val index: Int,
110110
override val offset: Duration,
111111
override val buffered: Duration?,
112-
) : AudioNavigator.Playback
112+
) : TimeBasedMediaNavigator.Playback
113113

114114
sealed class State {
115115

readium/navigator/src/main/java/org/readium/r2/navigator/media3/audio/AudioNavigatorFactory.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class AudioNavigatorFactory<S : Configurable.Settings, P : Configurable.Preferen
4444
suspend fun createNavigator(
4545
initialPreferences: P? = null,
4646
initialLocator: Locator? = null
47-
): AudiobookNavigator<S, P>? {
48-
return AudiobookNavigator(
47+
): AudioNavigator<S, P>? {
48+
return AudioNavigator(
4949
publication = publication,
5050
audioEngineProvider = audioEngineProvider,
5151
initialPreferences = initialPreferences,

readium/navigator/src/main/java/org/readium/r2/navigator/media3/exoplayer/ExoPlayerAliases.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
package org.readium.r2.navigator.media3.exoplayer
88

9+
import org.readium.r2.navigator.media3.audio.AudioNavigator
910
import org.readium.r2.navigator.media3.audio.AudioNavigatorFactory
10-
import org.readium.r2.navigator.media3.audio.AudiobookNavigator
1111
import org.readium.r2.shared.ExperimentalReadiumApi
1212

1313
@OptIn(ExperimentalReadiumApi::class)
1414
typealias ExoPlayerNavigatorFactory = AudioNavigatorFactory<ExoPlayerSettings, ExoPlayerPreferences, ExoPlayerPreferencesEditor>
1515

1616
@OptIn(ExperimentalReadiumApi::class)
17-
typealias ExoPlayerNavigator = AudiobookNavigator<ExoPlayerSettings, ExoPlayerPreferences>
17+
typealias ExoPlayerNavigator = AudioNavigator<ExoPlayerSettings, ExoPlayerPreferences>

readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedAudioNavigator.kt renamed to readium/navigator/src/main/java/org/readium/r2/navigator/media3/syncmedia/GuidedMediaNavigator.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ package org.readium.r2.navigator.media3.syncmedia
99
import androidx.media3.common.Player
1010
import kotlin.time.Duration
1111
import kotlinx.coroutines.flow.StateFlow
12-
import org.readium.r2.navigator.media3.api.AudioNavigator
1312
import org.readium.r2.navigator.media3.api.Media3Adapter
1413
import org.readium.r2.navigator.media3.api.MediaNavigator
1514
import org.readium.r2.navigator.media3.api.TextAwareMediaNavigator
16-
import org.readium.r2.navigator.media3.audio.AudiobookNavigator
15+
import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator
16+
import org.readium.r2.navigator.media3.audio.AudioNavigator
1717
import org.readium.r2.navigator.preferences.Configurable
1818
import org.readium.r2.shared.ExperimentalReadiumApi
1919
import org.readium.r2.shared.publication.Link
@@ -22,12 +22,12 @@ import org.readium.r2.shared.publication.Publication
2222
import org.readium.r2.shared.util.Href
2323

2424
@ExperimentalReadiumApi
25-
class GuidedAudioNavigator<S : Configurable.Settings, P : Configurable.Preferences<P>>(
26-
private val audioNavigator: AudiobookNavigator<S, P>,
25+
class GuidedMediaNavigator<S : Configurable.Settings, P : Configurable.Preferences<P>>(
26+
private val audioNavigator: AudioNavigator<S, P>,
2727
) :
28-
MediaNavigator<GuidedAudioNavigator.Location, GuidedAudioNavigator.Playback, GuidedAudioNavigator.ReadingOrder>,
29-
AudioNavigator<GuidedAudioNavigator.Location, GuidedAudioNavigator.Playback, GuidedAudioNavigator.ReadingOrder>,
30-
TextAwareMediaNavigator<GuidedAudioNavigator.Location, GuidedAudioNavigator.Playback, GuidedAudioNavigator.ReadingOrder>,
28+
MediaNavigator<GuidedMediaNavigator.Location, GuidedMediaNavigator.Playback, GuidedMediaNavigator.ReadingOrder>,
29+
TimeBasedMediaNavigator<GuidedMediaNavigator.Location, GuidedMediaNavigator.Playback, GuidedMediaNavigator.ReadingOrder>,
30+
TextAwareMediaNavigator<GuidedMediaNavigator.Location, GuidedMediaNavigator.Playback, GuidedMediaNavigator.ReadingOrder>,
3131
Media3Adapter,
3232
Configurable<S, P> {
3333

@@ -41,7 +41,7 @@ class GuidedAudioNavigator<S : Configurable.Settings, P : Configurable.Preferenc
4141
override val range: IntRange?,
4242
override val utteranceLocator: Locator,
4343
override val tokenLocator: Locator?,
44-
) : AudioNavigator.Location,
44+
) : TimeBasedMediaNavigator.Location,
4545
TextAwareMediaNavigator.Location
4646

4747
data class Playback(
@@ -52,17 +52,17 @@ class GuidedAudioNavigator<S : Configurable.Settings, P : Configurable.Preferenc
5252
override val buffered: Duration?,
5353
override val utterance: String,
5454
override val range: IntRange?,
55-
) : AudioNavigator.Playback, TextAwareMediaNavigator.Playback
55+
) : TimeBasedMediaNavigator.Playback, TextAwareMediaNavigator.Playback
5656

5757
data class ReadingOrder(
5858
override val duration: Duration?,
5959
override val items: List<Item>
60-
) : AudioNavigator.ReadingOrder, TextAwareMediaNavigator.ReadingOrder {
60+
) : TimeBasedMediaNavigator.ReadingOrder, TextAwareMediaNavigator.ReadingOrder {
6161

6262
data class Item(
6363
val href: Href,
6464
override val duration: Duration?
65-
) : AudioNavigator.ReadingOrder.Item, TextAwareMediaNavigator.ReadingOrder.Item
65+
) : TimeBasedMediaNavigator.ReadingOrder.Item, TextAwareMediaNavigator.ReadingOrder.Item
6666
}
6767

6868
override val publication: Publication =

readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/TtsNavigator.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class TtsNavigator<S : TtsEngine.Settings, P : TtsEngine.Preferences<P>,
4444
MediaNavigator<TtsNavigator.Location, TtsNavigator.Playback, TtsNavigator.ReadingOrder>,
4545
TextAwareMediaNavigator<TtsNavigator.Location, TtsNavigator.Playback, TtsNavigator.ReadingOrder>,
4646
Media3Adapter,
47-
Configurable<S, P> by player {
47+
Configurable<S, P> {
4848

4949
companion object {
5050

@@ -247,6 +247,14 @@ class TtsNavigator<S : TtsEngine.Settings, P : TtsEngine.Preferences<P>,
247247
return true
248248
}
249249

250+
override val settings: StateFlow<S> =
251+
player.settings
252+
253+
override fun submitPreferences(preferences: P) {
254+
player.submitPreferences(preferences)
255+
player.restartUtterance()
256+
}
257+
250258
private fun navigatorPlayback(playback: TtsPlayer.Playback, utterance: TtsPlayer.Utterance) =
251259
Playback(
252260
state = playback.state.toState(),

readium/navigator/src/main/java/org/readium/r2/navigator/media3/tts/android/AndroidTtsEngine.kt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -400,19 +400,23 @@ class AndroidTtsEngine private constructor(
400400
utteranceLanguage: Language?,
401401
voices: Set<Voice>
402402
): Boolean {
403-
var language = utteranceLanguage
403+
val language = utteranceLanguage
404404
.takeUnless { settings.overrideContentLanguage }
405+
// We take utterance language if data are missing but not if the language is not supported
406+
?.takeIf { isLanguageAvailable(it.locale) != LANG_NOT_SUPPORTED }
405407
?: settings.language
408+
.takeIf { isLanguageAvailable(it.locale) != LANG_NOT_SUPPORTED }
409+
?: defaultVoice?.locale?.let { Language(it) }
406410

407-
utteranceListener?.onError(id, Error.LanguageMissingData(language))
408-
return false
411+
if (language == null) {
412+
// We don't know what to do.
413+
utteranceListener?.onError(id, Error.Unknown)
414+
return false
415+
}
409416

410-
when (isLanguageAvailable(language.locale)) {
411-
LANG_MISSING_DATA -> {
412-
utteranceListener?.onError(id, Error.LanguageMissingData(language))
413-
return false
414-
}
415-
LANG_NOT_SUPPORTED -> language = Language(defaultVoice.locale)
417+
if (isLanguageAvailable(language.locale) < LANG_AVAILABLE) {
418+
utteranceListener?.onError(id, Error.LanguageMissingData(language))
419+
return false
416420
}
417421

418422
val preferredVoiceWithRegion =

test-app/src/main/java/org/readium/r2/testapp/reader/AudioReaderFragment.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import kotlin.time.DurationUnit
2323
import kotlinx.coroutines.flow.launchIn
2424
import kotlinx.coroutines.flow.onEach
2525
import kotlinx.coroutines.launch
26-
import org.readium.r2.navigator.media3.api.AudioNavigator
2726
import org.readium.r2.navigator.media3.api.MediaNavigator
27+
import org.readium.r2.navigator.media3.api.TimeBasedMediaNavigator
2828
import org.readium.r2.navigator.media3.exoplayer.ExoPlayerPreferences
2929
import org.readium.r2.navigator.media3.exoplayer.ExoPlayerSettings
3030
import org.readium.r2.navigator.preferences.Configurable
@@ -40,7 +40,7 @@ import timber.log.Timber
4040
@OptIn(ExperimentalReadiumApi::class)
4141
class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListener {
4242

43-
override lateinit var navigator: AudioNavigator<*, *, *>
43+
override lateinit var navigator: TimeBasedMediaNavigator<*, *, *>
4444

4545
private var binding: FragmentAudiobookBinding by viewLifecycle()
4646
private var seekingItem: Int? = null
@@ -88,7 +88,7 @@ class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListene
8888
.launchIn(viewLifecycleOwner.lifecycleScope)
8989
}
9090

91-
private fun onPlaybackChanged(playback: AudioNavigator.Playback) {
91+
private fun onPlaybackChanged(playback: TimeBasedMediaNavigator.Playback) {
9292
Timber.v("onPlaybackChanged $playback")
9393
if (playback.state is MediaNavigator.State.Error) {
9494
onPlayerError()
@@ -111,7 +111,7 @@ class AudioReaderFragment : BaseReaderFragment(), SeekBar.OnSeekBarChangeListene
111111
}
112112
}
113113

114-
private fun updateTimeline(playback: AudioNavigator.Playback) {
114+
private fun updateTimeline(playback: TimeBasedMediaNavigator.Playback) {
115115
val currentItem = navigator.readingOrder.items[playback.index]
116116
binding.timelineBar.max = currentItem.duration?.inWholeSeconds?.toInt() ?: 0
117117
binding.timelineDuration.text = currentItem.duration?.formatElapsedTime()

0 commit comments

Comments
 (0)