Voice instructions
The Mapbox Navigation SDK allows you to provide prompt and detailed voice instructions to users of your application. You can use a voice instruction to notify the user of an upcoming turn or announce that a faster route has been detected.
The Navigation SDK uses the Mapbox Java SDK's VoiceInstructions
class to hold information that should be announced out loud by the device (for example, the street that the user should stay on for a certain distance).
Use default voice instructions
There are two steps to play voice instructions in your application: generate an announcement and then play an announcement.
Create an instance of the speech API
Before you can generate an announcement, you need to instantiate the speech API in your Activity
or Fragment
:
MapboxSpeechApi speechApi = new MapboxSpeechApi(this, Locale.US.toLanguageTag());
val speechApi = MapboxSpeechApi(this, Locale.US.toLanguageTag())
Create an instance of the voice instructions player
And before you can play an announcement, you need to instantiate the text-to-speech engine in onCreate
of your Activity
or onActivityCreated
of your Fragment
.
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 voiceInstructionsPlayer;
@Override
public void onCreate() {
// do your initialization here
voiceInstructionsPlayer = new MapboxVoiceInstructionsPlayer(
this,
Locale.US.toLanguageTag()
);
}
lateinit var voiceInstructionsPlayer: MapboxVoiceInstructionsPlayer
override fun onCreate() {
// do your initialization here
voiceInstructionsPlayer = MapboxVoiceInstructionsPlayer(
this,
Locale.US.toLanguageTag()
)
}
Generate and play an announcement
Start by generating the content of the announcement using MapboxSpeechApi
. MapboxSpeechApi
accepts a VoiceInstructions
object and returns a state object that includes the content of the announcement when it is ready or an error and a fallback with the raw announcement.
Then, pass the content of the announcement to MapboxVoiceInstructionsPlayer
, which will play the announcement aloud. If you provide a synthesized speech MP3 which was successfully generated with the MapboxSpeechApi
, a media player will be used to play the instruction. If not, an onboard speech-to-text engine, obtained using built-in Android APIs, will be used to synthesize the raw announcement's text.
The result of invoking MapboxSpeechApi#generate
is returned as a callback containing either a success in the form of SpeechValue
or failure in the form of SpeechError
.
MapboxNavigationConsumer<Expected<SpeechValue, SpeechError>> speechCallback = new MapboxNavigationConsumer<Expected<SpeechValue, SpeechError>>() {
@Override
public void accept(Expected<SpeechValue, SpeechError> value) {
if (value instanceof Expected.Success) {
// The announcement data obtained (synthesized speech mp3 file from Mapbox's API Voice) is played
// using MapboxVoiceInstructionsPlayer
voiceInstructionsPlayer.play(
((SpeechValue) ((Expected.Success) value).getValue()).getAnnouncement(),
voiceInstructionsPlayerCallback
);
} else {
// In case of error, a fallback announcement is returned that can be played
// using MapboxVoiceInstructionsPlayer
voiceInstructionsPlayer.play(
((SpeechError) ((Expected.Failure) value).getError()).getFallback(),
voiceInstructionsPlayerCallback
);
}
}
};
VoiceInstructionsObserver voiceInstructionsObserver = voiceInstructions -> {
// The data obtained must be used to generate the speech announcement
speechApi.generate(
voiceInstructions,
speechCallback
);
};
val speechCallback =
MapboxNavigationConsumer<Expected<SpeechError, SpeechValue>> { expected ->
expected.fold(
{ error ->
// In case of error, a fallback announcement is returned that can be played
// using [MapboxVoiceInstructionsPlayer]
voiceInstructionsPlayer.play(
error.fallback,
voiceInstructionsPlayerCallback
)
},
{ value ->
// The announcement data obtained (synthesized speech mp3 file from Mapbox's API Voice) is played
// using [MapboxVoiceInstructionsPlayer]
voiceInstructionsPlayer.play(
value.announcement,
voiceInstructionsPlayerCallback
)
}
)
}
val voiceInstructionsObserver =
VoiceInstructionsObserver { voiceInstructions ->
// The data obtained must be used to generate the speech announcement
speechAPI.generate(
voiceInstructions,
speechCallback
)
}
The result of invoking MapboxVoiceInstructionsPlayer#play
is returned as a callback containing SpeechAnnouncement
. This can be used to cleanup any associated files generated before:
MapboxNavigationConsumer<SpeechAnnouncement> voiceInstructionsPlayerCallback = new MapboxNavigationConsumer<SpeechAnnouncement>() {
@Override
public void accept(SpeechAnnouncement value) {
speechApi.clean(value);
}
};
val voiceInstructionsPlayerCallback =
MapboxNavigationConsumer<SpeechAnnouncement> { value ->
// Remove already consumed file to free-up space
speechAPI.clean(value)
}
MapboxVoiceInstructionsPlayer
with manually created SpeechAnnouncement
s with only announcement
text value which will rely only on the usage of the onboard TTS engine.Start and stop receiving voice events
Register a VoiceInstructionsObserver
with MapboxNavigation
:
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver);
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
Don't forget to unregister the observer, cancel any potential in-flight MapboxSpeechApi
requests and shutdown MapboxVoiceInstructionsPlayer
in onStop
or onDestroy
:
@Override
protected void onDestroy() {
super.onDestroy();
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver);
speechApi.cancel();
voiceInstructionsPlayer.shutdown();
}
override fun onDestroy() {
super.onDestroy()
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
speechApi.cancel()
voiceInstructionsPlayer.shutdown()
}
Also, every time a new route is obtained make sure to cancel any potential in-flight MapboxSpeechApi
requests and clear the MapboxVoiceInstructionsPlayer
queue:
RoutesObserver routesObserver = result -> {
speechApi.cancel();
voiceInstructionsPlayer.clear();
};
val routesObserver =
RoutesObserver { result ->
// Every time a new route is obtained make sure to cancel the [MapboxSpeechApi] and
// clear the [MapboxVoiceInstructionsPlayer]
speechApi.cancel()
voiceInstructionsPlayer.clear()
}
Adjust voice instructions volume
To set the volume level of MapboxVoiceInstructionsPlayer
you need to provide a value between 0.0
(mute) and 1.0
(max) through SpeechVolume
:
// This is used to set the speech volume to mute
voiceInstructionsPlayer.volume(new SpeechVolume(0.0f));
// This is used to set the speech volume to mute
voiceInstructionsPlayer.volume(SpeechVolume(0.0f))