feat!: Application outline
This commit is contained in:
parent
80dfa6ab4e
commit
01fbf32042
9 changed files with 1440 additions and 190 deletions
111
app/src/main/java/eu/ztsh/garmin/mapbox/VoiceControl.kt
Normal file
111
app/src/main/java/eu/ztsh/garmin/mapbox/VoiceControl.kt
Normal file
|
@ -0,0 +1,111 @@
|
|||
package eu.ztsh.garmin.mapbox
|
||||
|
||||
import android.content.Context
|
||||
import com.mapbox.bindgen.Expected
|
||||
import com.mapbox.navigation.core.trip.session.VoiceInstructionsObserver
|
||||
import com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer
|
||||
import com.mapbox.navigation.voice.api.MapboxSpeechApi
|
||||
import com.mapbox.navigation.voice.api.MapboxVoiceInstructionsPlayer
|
||||
import com.mapbox.navigation.voice.model.SpeechAnnouncement
|
||||
import com.mapbox.navigation.voice.model.SpeechError
|
||||
import com.mapbox.navigation.voice.model.SpeechValue
|
||||
import com.mapbox.navigation.voice.model.SpeechVolume
|
||||
import eu.ztsh.garmin.UI
|
||||
import java.util.*
|
||||
|
||||
class VoiceControl(private val ui: UI, context: Context) {
|
||||
|
||||
/**
|
||||
* Extracts message that should be communicated to the driver about the upcoming maneuver.
|
||||
* When possible, downloads a synthesized audio file that can be played back to the driver.
|
||||
*/
|
||||
private lateinit var speechApi: MapboxSpeechApi
|
||||
|
||||
/**
|
||||
* Plays the synthesized audio files with upcoming maneuver instructions
|
||||
* or uses an on-device Text-To-Speech engine to communicate the message to the driver.
|
||||
* NOTE: do not use lazy initialization for this class since it takes some time to initialize
|
||||
* the system services required for on-device speech synthesis. With lazy initialization
|
||||
* there is a high risk that said services will not be available when the first instruction
|
||||
* has to be played. [MapboxVoiceInstructionsPlayer] should be instantiated in
|
||||
* `Activity#onCreate`.
|
||||
*/
|
||||
private lateinit var voiceInstructionsPlayer: MapboxVoiceInstructionsPlayer
|
||||
|
||||
init {
|
||||
speechApi = MapboxSpeechApi(
|
||||
context,
|
||||
Locale("pl").language
|
||||
)
|
||||
voiceInstructionsPlayer = MapboxVoiceInstructionsPlayer(
|
||||
context,
|
||||
Locale("pl").language
|
||||
)
|
||||
ui.soundButton.setOnClickListener {
|
||||
// mute/unmute voice instructions
|
||||
isVoiceInstructionsMuted = !isVoiceInstructionsMuted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores and updates the state of whether the voice instructions should be played as they come or muted.
|
||||
*/
|
||||
private var isVoiceInstructionsMuted = false
|
||||
set(value) {
|
||||
field = value
|
||||
if (value) {
|
||||
ui.soundButton.muteAndExtend(UI.BUTTON_ANIMATION_DURATION)
|
||||
voiceInstructionsPlayer.volume(SpeechVolume(0f))
|
||||
} else {
|
||||
ui.soundButton.unmuteAndExtend(UI.BUTTON_ANIMATION_DURATION)
|
||||
voiceInstructionsPlayer.volume(SpeechVolume(1f))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes when a new voice instruction should be played.
|
||||
*/
|
||||
val voiceInstructionsObserver = VoiceInstructionsObserver { voiceInstructions ->
|
||||
speechApi.generate(voiceInstructions, speechCallback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on whether the synthesized audio file is available, the callback plays the file
|
||||
* or uses the fall back which is played back using the on-device Text-To-Speech engine.
|
||||
*/
|
||||
private val speechCallback =
|
||||
MapboxNavigationConsumer<Expected<SpeechError, SpeechValue>> { expected ->
|
||||
expected.fold(
|
||||
{ error ->
|
||||
// play the instruction via fallback text-to-speech engine
|
||||
voiceInstructionsPlayer.play(
|
||||
error.fallback,
|
||||
voiceInstructionsPlayerCallback
|
||||
)
|
||||
},
|
||||
{ value ->
|
||||
// play the sound file from the external generator
|
||||
voiceInstructionsPlayer.play(
|
||||
value.announcement,
|
||||
voiceInstructionsPlayerCallback
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* When a synthesized audio file was downloaded, this callback cleans up the disk after it was played.
|
||||
*/
|
||||
private val voiceInstructionsPlayerCallback =
|
||||
MapboxNavigationConsumer<SpeechAnnouncement> { value ->
|
||||
// remove already consumed file to free-up space
|
||||
speechApi.clean(value)
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
speechApi.cancel()
|
||||
voiceInstructionsPlayer.shutdown()
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue