Voice instructions

VERSION 2.2.0

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 file before you can use it.

implementation("com.tomtom.sdk:tts:2.2.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 acts as a facade for performing operations on the TextToSpeechEngine. It handles queuing messages based on priority.

You can create a TextToSpeech instance in two ways:

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

OnEngineReadyListener

You can listen for when the TextToSpeechEngine is ready to use. To do this, set the OnEngineReadyListener on either the TextToSpeech or the TextToSpeechEngine directly. If a listener has already been added, a IllegalArgumentException is thrown. OnEngineReadyListener.onReady() is called when the engine is ready. OnEngineReadyListener.onError(TextToSpeechEngineError) is triggered if the 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 is 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 a 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 shown in the example. The second parameter is a PhoneticTranscription. To create a PhoneticTranscription, provide the following:

  • A list of phonetic transcriptions for the phrases tagged in the message.
  • A list of language codes in IETF format, sorted in the same order as the transcriptions.
  • A tag surrounding the phrase in the message.
  • The phonetic alphabet used for 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 using a Locale object. It can be done via the TextToSpeech constructor or by calling the TextToSpeech.changeLanguage(Locale) method. By default, the language is set to American English.

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 is removed. If the process has already started, it is stopped, and the MessagePlaybackListener.onStop() method is 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 by disposing of the underlying engine using the TextToSpeech.close() method.

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

tts.close()

Errors

The Maps and Navigation SDK provides the TextToSpeechEngineError class and its subclasses to report errors that occur in the AndroidTextToSpeechEngine.

Next steps

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