Voice instructions

VERSION 1.19.0
PUBLIC PREVIEW

Navigation SDK for Android is only available upon request. Contact us to get started.

The Navigation module includes Text To Speech (TTS) functionality for generating voice instructions. TTS is deployed as a separate module. This means that you have to add the following dependency to your module’s build.gradle.kts before you can use it.

implementation("com.tomtom.sdk:tts:1.19.0")

TTS engine

The TTS engine is responsible for providing voice synthesis for messages. The Navigation module provides a default AndroidTextToSpeechEngine based on Android’s TextToSpeech. However, you can also define a custom engine for text to speech conversion. Any custom engine must conform to the TextToSpeechEngine interface.

The TextToSpeech class is a facade for performing operations on TextToSpeechEngine. It takes care of queuing messages based on priority.

You can create TextToSpeech in two different ways.

  • A TextToSpeech that uses the default AndroidTextToSpeechEngine engine underneath:
    val androidTtsEngine = AndroidTextToSpeechEngine(applicationContext)
    val tts = TextToSpeech(androidTtsEngine)
  • A TextToSpeech with a custom TextToSpeechEngine for voice synthesis:
    val customTts = TextToSpeech(customTtsEngine)

OnEngineReadyListener

You can listen for whether the TextToSpeechEngine is ready to be used. To do so, set OnEngineReadyListener to TextToSpeech or to TextToSpeechEngine itself. If the listener has already been added, IllegalArgumentException is thrown. OnEngineReadyListener.onReady() is called when the engine is ready. OnEngineReadyListener.onError(TextToSpeechEngineError) is triggered if engine initialization ends with an error. TextToSpeechEngineError provides the reason for the failure.

1val onEngineReadyListener =
2 object : OnEngineReadyListener {
3 override fun onReady() {
4 // YOUR CODE GOES HERE
5 }
6
7 override fun onError(error: TextToSpeechEngineError) {
8 // YOUR CODE GOES HERE
9 }
10 }
11tts.addOnEngineReadyListener(onEngineReadyListener)

If the listener is no longer needed you can remove it. OnEngineReadyListener will be automatically removed when the TextToSpeech.close() method is called.

tts.removeOnEngineReadyListener(onEngineReadyListener)

Playing messages

The TextToSpeech.playAudioMessage(AudioMessage, MessageConfig, MessagePlaybackListener) and the TextToSpeech.playTaggedMessage(TaggedMessage, MessageConfig, MessagePlaybackListener) methods synthesize the provided message using the underlying TextToSpeechEngine. The MessageConfig parameter is used to configure the priority and time limit of the message. Message queuing depends on this priority. If the message that is currently being synthesized has an equal or higher priority to the new message, the new message will be added to the queue (taking the priorities of queued messages into account). If the message that is currently being synthesized has a lower priority than the new one, it will be interrupted and the new message will be processed right away.

val messageConfig = MessageConfig(priority = 10, timeout = TIMEOUT)

You must also provide a MessagePlaybackListener listener. It is used to provide the playback state. It consists of 4 methods that are triggered in different states.

1val messagePlaybackListener =
2 object : MessagePlaybackListener {
3 override fun onStart() {
4 // YOUR CODE GOES HERE
5 }
6
7 override fun onDone() {
8 // YOUR CODE GOES HERE
9 }
10
11 override fun onError(error: TextToSpeechEngineError) {
12 // YOUR CODE GOES HERE
13 }
14
15 override fun onStop() {
16 // YOUR CODE GOES HERE
17 }
18 }

Playing an audio message

To play an audio message, use the TextToSpeech.playAudioMessage(AudioMessage, MessageConfig, MessagePlaybackListener) method.

1val audioMessage =
2 AudioMessage(
3 message = "In 300 meters turn left",
4 messageType = MessageType.Plain,
5 )
6tts.playAudioMessage(
7 audioMessage = audioMessage,
8 config = messageConfig,
9 playbackListener = messagePlaybackListener,
10)

The AudioMessage can also be provided in Speech Synthesis Markup Language (SSML) format.

1val ssmlMessage =
2 AudioMessage(
3 "<speak>Turn left onto <phoneme alphabet='ipa' ph='e¬¬.¬f¬¬¬'>A4</phoneme> towards " +
4 "<phoneme alphabet='ipa' ph=''sxep.fart.my.'2ze.^m'>Scheepvaartmuseum</phoneme></speak>",
5 MessageType.Ssml,
6 )

Playing a tagged message

You can also pass the TaggedMessage with phonetics to be substituted using the TextToSpeech.playTaggedMessage(TaggedMessage, MessageConfig, MessagePlaybackListener) method. To create a TaggedMessage, provide the message along with the tags to be synthesized as in the example. The second parameter is PhoneticTranscription. To create a PhoneticTranscription, provide:

  • List of phonetic transcriptions of phrases that are tagged in the message.
  • List of language codes in IETF format, sorted in the same order as the transcriptions.
  • Tag surrounding the phrase within the message.
  • Phonetic alphabet of the transcriptions (e.g. "ipa", "lhp").
1val roadNumberPhonetics =
2 PhoneticTranscription(
3 transcriptions = listOf("e¬¬.¬f¬¬¬"),
4 locales = listOf(Locale("nl", "NL")),
5 tag = "roadNumber",
6 alphabet = "ipa",
7 )
8val signpostPhonetics =
9 PhoneticTranscription(
10 transcriptions = listOf("'sxep.fart.my.'2ze.^m"),
11 locales = listOf(Locale("nl", "NL")),
12 tag = "signpostText",
13 alphabet = "ipa",
14 )
1val taggedMessage =
2 TaggedMessage(
3 message =
4 "Turn left onto <roadNumber>A4</roadNumber> " +
5 "towards<signpostText>Scheepvaartmuseum</signpostText>",
6 phonetics = listOf(roadNumberPhonetics, signpostPhonetics),
7 language = Locale.US,
8 )
9
10tts.playTaggedMessage(
11 taggedMessage = taggedMessage,
12 config = messageConfig,
13 playbackListener = messagePlaybackListener,
14)

Language

The language of the underlying engine can be changed. Provide the new language in the form of the Locale. It can be done via the TextToSpeech constructor or with the TextToSpeech.changeLanguage(Locale) method. The language is set to American English by default.

tts.changeLanguage(Locale.forLanguageTag("pl-PL"))

Voice

The voice of the AndroidTextToSpeechEngine can be changed. The configuration of a new Voice is possible using the AndroidTextToSpeechEngine.setVoice(Voice) method. Available voices can be retrieved with the AndroidTextToSpeechEngine.getVoices() method.

After the language of the AndroidTextToSpeechEngine is changed, the voice of the AndroidTextToSpeechEngine is set to the default for that language.

1val currentLanguage = Locale.forLanguageTag("pl-PL")
2val voicesResult = androidTtsEngine.getVoices()
3if (voicesResult.isSuccess()) {
4 val availableVoices = voicesResult.value()
5 val voicesInCurrentLanguage = availableVoices.filter {
6 // filter voices by current language
7 it.locale.language == currentLanguage.language
8 }
9 // select preferred voice
10 val preferredVoice = voicesInCurrentLanguage.first()
11 val setVoiceResult = androidTtsEngine.setVoice(preferredVoice)
12 if (setVoiceResult.isFailure()) {
13 // YOUR CODE GOES HERE
14 val error = setVoiceResult.failure()
15 }
16} else {
17 // YOUR CODE GOES HERE
18 val error = voicesResult.failure()
19}

Message cancellation

Both the TextToSpeech.playAudioMessage(AudioMessage, MessageConfig, MessagePlaybackListener) and TextToSpeech.playTaggedMessage(TaggedMessage, MessageConfig, MessagePlaybackListener) methods return a Cancellable object. It can be used to cancel the message.

If the message is in the queue it will be removed. If the process has already started, it will be stopped and the MessagePlaybackListener.onStop() will be called.

1val cancellable =
2 tts.playAudioMessage(
3 audioMessage = audioMessage,
4 config = messageConfig,
5 playbackListener = messagePlaybackListener,
6 )
7cancellable.cancel()

You can also remove all messages from the queue using the TextToSpeech.clearQueue(Boolean) method. The provided parameter specifies whether the message currently being played should be stopped as well.

tts.clearQueue(stopCurrent = true)

Disposal

If the TextToSpeechEngine is no longer needed it should be disposed. You can do this either by calling TextToSpeechEngine.close() directly on the engine, or dispose the underlying engine with the TextToSpeech.close() method.

After the engine is disposed, audio messages cannot be synthesized. An EngineNotReadyError will be raised in that case.

tts.close()

Errors

The Navigation SDK provides the TextToSpeechEngineError error and its subclasses to report on errors that occurred in the AndroidTextToSpeechEngine.

Next steps

Since you have learned how to work with voice instructions, here are recommendations for the next steps: