Skip to main content

Add voice guidance

|

Voice guidance in the Maps SDK for Android allows you to enhance navigation experiences with spoken instructions. This guide covers how to enable built-in Text-to-Speech (TTS), manage voice settings, switch voices and languages, and integrate custom playback using the onNavigationSound callback for maximum flexibility.

The Maps SDK for Android provides two options for instruction playback:

  • Built-in solutions - playback using human voice recordings or computer-generated TTS.
  • External integration - manual handling of sound playback through the onNavigationSound callback.

The built-in solution also provides automatic audio session management, ducking other playbacks (such as music) while instructions are playing.

Quick start

Enable voice guidance using the built-in SoundPlayingService by implementing proper sound handling in your navigation listener:

import com.magiclane.sdk.core.SoundPlayingService
import com.magiclane.sdk.core.SoundPlayingListener
import com.magiclane.sdk.routesandnavigation.NavigationListener

// Create a sound listener for navigation sounds
val soundListener = object : SoundPlayingListener() {
override fun notifyStart(hasProgress: Boolean) {
// Navigation sound started
}

override fun notifyComplete(errorCode: Int, hint: String) {
// Navigation sound completed
}
}

// Add navigation listener with sound handling
val navigationListener = NavigationListener.create(
onNavigationSound = { sound ->
// Play the navigation sound using the service
val preferences = SoundPlayingService.getPlayingPreferences()
SoundPlayingService.play(sound, soundListener, preferences)
}
// Handle other navigation events...
)

// Start navigation with voice guidance
val navigationService = NavigationService()
navigationService.startNavigationWithRoute(
route = route,
navigationListener = navigationListener,
progressListener = ProgressListener.create()
)

For external TTS integration, override the default sound handling:

val navigationListener = NavigationListener.create(
onNavigationSound = { sound ->
// Custom TTS handling
val instructionText = sound.getAsString()
if (instructionText.isNotEmpty()) {
// Use your preferred TTS engine
customTtsEngine.speak(instructionText)
}
}
// Handle other events...
)

Note: The SDK does not provide automatic sound playback. You must implement sound handling in the onNavigationSound callback to hear voice instructions.

Basic Voice Guidance

To enable voice guidance, you need to handle navigation sounds in your NavigationListener and use the SoundPlayingService to play them:

import com.magiclane.sdk.core.SoundPlayingService
import com.magiclane.sdk.core.SoundPlayingListener
import com.magiclane.sdk.core.SoundPlayingPreferences

// Configure sound preferences
val preferences = SoundPlayingService.getPlayingPreferences()
preferences.volume = 8 // Set volume (0-10)

// Create navigation listener with sound handling
val navigationListener = NavigationListener.create(
onNavigationSound = { sound ->
val soundListener = object : SoundPlayingListener() {
override fun notifyComplete(errorCode: Int, hint: String) {
if (errorCode != 0) {
println("Sound playback failed: $errorCode")
}
}
}

// Play the navigation instruction sound
SoundPlayingService.play(sound, soundListener, preferences)
}
)
warning

Ensure that a valid TTS voice is configured and the voice volume is set to a positive value within the allowed range (0-10) to hear voice instructions.

tip

By default, the current voice is set to the best computer TTS voice matching the default SDK language.

The Sound Playing Service

The SoundPlayingService provides the following key methods for sound management:

MethodDescription
play(sound, listener, preferences)Plays an ISound object with monitoring and custom preferences
playText(text, listener, preferences)Plays TTS text using the current TTS voice
playFile(filePath, mimeType, listener, preferences)Plays an audio file with specified MIME type
getPlayingPreferences()Gets the current sound playing preferences (volume, etc.)
setTTSLanguage(languageCode)Sets the TTS language for computer voices
getTTSLanguages()Gets list of available TTS languages
cancel(listener)Cancels playback associated with a specific listener
playingSoundsCount()Returns the number of sounds currently playing

Voice

The Maps SDK for Android provides a list of voices for each supported language. These voices can be downloaded and activated to provide navigation prompts such as turn instructions, warnings, and announcements.

The SDK offers two types of voice guidance, defined by the EVoiceType enum:

  • EVoiceType.Human: Uses pre-recorded human voices to deliver instructions in a friendly and natural tone. These voices support only basic instruction types and do not include road or settlement names.
  • EVoiceType.Computer: Leverages the device's Text-to-Speech (TTS) engine to provide more detailed and flexible guidance. These voices fully support street and place names in the spoken instructions. The quality and availability is dependent on the device.

Voice Structure

The Voice class provides the following details:

PropertyTypeDescription
idLongUnique identifier for the voice.
nameStringDisplay name of the voice.
filenameStringFile name which can be used to load the voice (available for EVoiceType.Human).
languageLanguageAssociated language object.
typeEVoiceTypeEnum: Human or Computer.
danger

Do not confuse the Voice and Language concepts.

The Language defines what is said - it determines the words, phrasing, and localization. The Voice defines how it is said - it controls attributes like accent, tone, and gender. Always ensure that the selected Voice is compatible with the chosen Language, as mismatched combinations may result in unnatural or incorrect pronunciation.

Relevance

  • Language is relevant for both the built-in TTS system and custom solutions using the onNavigationSound callback. See the internationalization guide for more info about the Language class.
  • Voice is relevant only for the built-in voice-guidance (using human and computer voices) playback.
danger

The SDK distinguishes between two language settings:

  • SDK language (SdkSettings.language) : Defines the language used for all on-screen text and UI intended strings.
  • Voice language (Voice.language) : Defines the language used for spoken output, whether through the built-in engine (computer/human voices) or via the onNavigationSound callback.

Both settings use the same Language class. The synchronization between the SDK language and the voice language should be made by the user, depending on the use case.

Get the Current Voice

Use the voice property provided by the SdkSettings class:

val currentVoice = SdkSettings.voice

Get the List of Available Human Voices

The available human voices list is provided by the getLocalContentList method provided by the ContentStore class.

val contentStore = ContentStore()
val items = contentStore.getLocalContentList(EContentType.HumanVoice)

items?.forEach { contentStoreItem ->
// The voice name (ex: Ella)
val name = contentStoreItem.name

// The absolute path to the voice file. Used for applying the voice.
val filePath = contentStoreItem.filename

// Unique identifier for the voice
val id = contentStoreItem.id

// Voice language information
val language = contentStoreItem.language

// Voice type (Human or Computer)
val type = contentStoreItem.type

// Country codes associated with this voice
val countryCodes = contentStoreItem.countryCodes
}
tip

Check the Manage Content Guide for information about managing voices and performing operations such as downloading, deleting, and more and details about the ContentStore and ContentStoreItem classes.

Apply a Voice by path

A human voice can be applied by providing the absolute path (obtained from the ContentStoreItem.filename getter) to the setVoiceByPath method provided by the SdkSettings class:

val filePath = contentStoreItem.filename
SdkSettings.setVoiceByPath(filePath)
Tip

The SdkSettings.setVoiceByPath method can also be used to set computer voices, provided the computer voice path is known.

For setting TTS computer voices, it's recommended to use SoundPlayingService.setTTSLanguage with the appropriate language code instead.

Apply a Voice by language

Computer voices can be applied using the setTTSLanguage method provided by the SoundPlayingService class. The method requires a language code string:

// Get available TTS languages
val ttsLanguages = SoundPlayingService.getTTSLanguages()

// Set TTS language by language code
if (ttsLanguages.isNotEmpty()) {
SoundPlayingService.setTTSLanguage(ttsLanguages[0].code)
}

// Or set directly with a known language code
SoundPlayingService.setTTSLanguage("en-US")

The computer voice is implemented using the device included TTS capabilities.

danger

Selecting a computer voice in an unsupported language may cause a mismatch between the spoken voice and the instruction content. The exact behavior depends on the device and its available text-to-speech capabilities.

Get the TTS Instruction Strings

The TTS instructions can be provided by the NavigationService as strings in order to be further processed and played with external tools. For example, Android's built-in TTS engine or third-party TTS libraries can be used for playing sound based on the TTS text instructions provided by the SDK. The voice instructions strings will come on the onNavigationSound callback set during navigation or simulation.

Add Android's built-in TTS or a third-party TTS library to your project. For Android's built-in TTS, ensure you have the necessary permissions in your AndroidManifest.xml.

We can use the onNavigationSound callback of the navigation listener in the following way:

import android.speech.tts.TextToSpeech
import com.magiclane.sdk.core.ISound
import com.magiclane.sdk.routesandnavigation.NavigationInstruction
import com.magiclane.sdk.routesandnavigation.NavigationListener

// instantiate Android TTS
val tts = TextToSpeech(context) { status ->
if (status == TextToSpeech.SUCCESS) {
// TTS engine initialized successfully
}
}

fun simulationInstructionUpdated(instruction: NavigationInstruction) {
// handle instruction
}

fun handleNavigationSound(sound: ISound) {
val instructionText = sound.getAsString()
if (!instructionText.isNullOrEmpty()) {
tts.speak(instructionText, TextToSpeech.QUEUE_FLUSH, null, "NavigationTTS")
}
}

val navigationListener = NavigationListener.create(
onNavigationInstructionUpdated = { instruction ->
simulationInstructionUpdated(instruction)
},
onNavigationSound = { sound ->
handleNavigationSound(sound)
}
)

val navigationService = NavigationService()
navigationService.startSimulationWithRoute(
route = route,
navigationListener = navigationListener,
progressListener = ProgressListener.create(),
speedMultiplier = 2.0f
)

For navigation we can set the onNavigationSound callback in a similar way with startNavigation.

See the Android documentation for TextToSpeech for information on how to set the TTS voice, language and other options such as pitch, volume, speech rate, etc.

Tip

To change the language of the instructions provided through the onNavigationSound callback, you can:

  • Use SoundPlayingService.setTTSLanguage and specify the preferred language code.
  • Or use SdkSettings.setVoiceByPath with a voice path corresponding to the desired language.

To disable the internal playback engine, simply don't call SoundPlayingService.play() in your onNavigationSound callback. The instruction will still be delivered via the callback, but no audio will be played.

Monitor Sound Playback Events

The Maps SDK provides sound playback monitoring through the SoundPlayingListener interface. This listener receives callbacks during sound operations and allows you to track playback progress.

Here's how to create a custom sound playing listener:

import com.magiclane.sdk.core.SoundPlayingListener
import com.magiclane.sdk.core.SoundPlayingService
import com.magiclane.sdk.core.SoundPlayingPreferences

class CustomSoundPlayingListener : SoundPlayingListener() {
override fun notifyStart(hasProgress: Boolean) {
// Sound playback started
println("Sound playback started. Has progress: $hasProgress")
}

override fun notifyProgress(progress: Int) {
// Progress update (0-100)
println("Playback progress: $progress%")
}

override fun notifyComplete(errorCode: Int, hint: String) {
// Sound playback completed
if (errorCode == 0) {
println("Sound playback completed successfully")
} else {
println("Sound playback failed with error: $errorCode")
}
}

override fun onVolumeChangedByKeys(newVolume: Int) {
// Volume changed via hardware keys
println("Volume changed to: $newVolume")
}
}

// Use the listener when playing sounds
val listener = CustomSoundPlayingListener()
val preferences = SoundPlayingPreferences()

// Play text with monitoring
SoundPlayingService.playText(
text = "Turn left in 100 meters",
listener = listener,
preferences = preferences
)

Monitoring Navigation Sounds

To monitor navigation sounds specifically, you can create a listener and use it with the sound received from onNavigationSound:

val soundListener = object : SoundPlayingListener() {
override fun notifyStart(hasProgress: Boolean) {
// Navigation sound started playing
}

override fun notifyComplete(errorCode: Int, hint: String) {
// Navigation sound finished
}
}

val navigationListener = NavigationListener.create(
onNavigationSound = { sound ->
// Play the navigation sound with monitoring
val preferences = SoundPlayingService.getPlayingPreferences()
SoundPlayingService.play(sound, soundListener, preferences)
}
)

Getting Playback Information

You can check the current playback status using these methods:

// Check how many sounds are currently playing
val playingCount = SoundPlayingService.playingSoundsCount()

// Get current playing preferences
val preferences = SoundPlayingService.getPlayingPreferences()
val currentVolume = preferences.volume // Volume level (0-10)
val maxPlayingTime = preferences.maxPlayingTime // Max duration in seconds

// Cancel a specific playback
SoundPlayingService.cancel(listener)
info

The SoundPlayingListener is used for all sound operations in the SDK, including TTS, file playback, and navigation sounds. Only one sound can be played at a time through the service.

Play custom instructions

Sometimes you may need to play custom instructions, such as road information warnings or social reports.

To do this, use the playText method of the SoundPlayingService to play back a custom string. This uses the currently selected TTS voice and requires a listener and preferences.

import com.magiclane.sdk.core.SoundPlayingService
import com.magiclane.sdk.core.SoundPlayingListener
import com.magiclane.sdk.core.SoundPlayingPreferences

// Create a listener for the custom instruction
val customInstructionListener = object : SoundPlayingListener() {
override fun notifyStart(hasProgress: Boolean) {
println("Custom instruction started")
}

override fun notifyComplete(errorCode: Int, hint: String) {
if (errorCode == 0) {
println("Custom instruction completed")
} else {
println("Custom instruction failed: $errorCode")
}
}
}

// Get default preferences or create custom ones
val preferences = SoundPlayingService.getPlayingPreferences()

// Play a custom instruction
SoundPlayingService.playText(
text = "Speed camera ahead",
listener = customInstructionListener,
preferences = preferences
)
tip

Check the speed warnings and landmark & overlay alarms docs to learn how to get notified about speed warnings and reports.