Voice instructions
The Navigation SDK for iOS is only available upon request. Contact us to get started.
Project setup
The Navigation module uses Text To Speech (TTS) functionality for generating voice instructions. TTS is provided as separate modules.
Configure the project according to the project setup guide and import the necessary frameworks using the following instructions, based on your preferred package manager:
Swift Package Manager
- Open your App’s target and navigate to General > Frameworks, Libraries, and Embedded Content.
- Add the following TomTomSDK libraries from the provided code snippet. Once the project is set up, import the mentioned frameworks into your code.
1import TomTomSDKRoute2import TomTomSDKRoutePlanner3import TomTomSDKTextToSpeech4import TomTomSDKTextToSpeechEngine
CocoaPods
- Add the
TomTomSDKTextToSpeech
andTomTomSDKDefaultTextToSpeech
modules to your project’sPodfile
:1TOMTOM_SDK_VERSION = '0.63.0'23target 'YourAppTarget' do4 use_frameworks!5 pod 'TomTomSDKTextToSpeech', TOMTOM_SDK_VERSION6 pod 'TomTomSDKDefaultTextToSpeech', TOMTOM_SDK_VERSION7end - Install the dependencies by executing the following commands in the project directory:
pod repo-art update tomtom-sdk-cocoapodspod install --repo-update
- Once the modules are added to your target, import the following frameworks:
1import TomTomSDKRoute2import TomTomSDKRoutePlanner3import TomTomSDKTextToSpeech4import TomTomSDKTextToSpeechEngine
TTS engine
The TTS engine is responsible for providing voice synthesis for messages. The Navigation module can use TomTomSDKDefaultTextToSpeech
based on the AVFoundation framework. Alternatively, you can also define a custom engine for text to speech conversion. Any custom engine must conform to the TextToSpeechEngineDelegate
interface.
The TextToSpeech
class is a facade for performing operations on TextToSpeechEngineDelegate
. It takes care of queuing messages based on priority.
You can create TextToSpeech
in two different ways.
- A
TextToSpeech
that uses the defaultSystemTextToSpeechEngine
engine underneath:1let locale = Locale(identifier: "en-Gb")2let tts = try! SystemTextToSpeechEngine(language: locale)3self.tts = makeTextToSpeech(ttsEngine: tts) - A
TextToSpeech
with a customTextToSpeechEngineDelegate
for voice synthesis:tts = makeTextToSpeech(ttsEngine: customEngine)
TextToSpeechEngineDelegate
You can listen for whether the TextToSpeechEngineDelegate
is ready to be used. A readiness notification is sent via TextToSpeechEngineDelegate.onReady()
.
1func onReady() {2 /* YOUR CODE GOES HERE */3}
Playing messages
The TextToSpeech.play(message:priority:)
method synthesizes the provided message using the underlying TextToSpeechEngineDelegate
. The TTSMessage
parameter is an enum with two cases: * TTSMessage.audio(message:type:)
- message with handling options, where MessageType
can be plain or SSML. * tagged(message: String, phonetics: [PhoneticTranscription])
- message with phonetic transcriptions that should be parsed for correct playback. Message queuing depends on 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. Messages remain in the queue for the time defined as the priority timeout. There are default timeouts defined for each priority level, but custom timeouts can also be provided:
let priority = TTSMessagePriority(timeout: 120)
Playing an audio message
To play an audio message, use the TextToSpeech.play(message:priority:)
method.
1let message = "In 300 meters turn left"2let audioMessage = TTSMessage.audio(message: message, type: .plain)3let priority = TTSMessagePriority(timeout: 10)4tts.play(message: audioMessage, priority: priority)
The audio message can also be provided in Speech Synthesis Markup Language (SSML) format.
1let ssmlMessage =2 "<speak>Turn left onto <phoneme alphabet='ipa' ph='e¬¬.¬f¬¬¬'>A4</phoneme> " +3 "towards <phoneme alphabet='ipa'ph=''sxep.fart.my.'2ze.^m'>Scheepvaartmuseum</phoneme></speak>"4let audioMessage = TTSMessage.audio(message: ssmlMessage, type: .ssml)5let priority = TTSMessagePriority(timeout: 10)6tts.play(message: audioMessage, priority: priority)
Playing a tagged message
You can also pass the tagged message with phonetics to be substituted using the same TextToSpeech.play(message:priority:)
method. To create a tagged message, provide the message along with the tags to be synthesized as in the example. The second parameter for tagged message generation 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 - "ipa" in our case.
1let roadNumbersPhonetics = TomTomSDKTextToSpeechEngine.PhoneticTranscription(2 transcriptions: ["e¬¬.¬f¬¬¬"],3 languages: [Locale(identifier: "nl-NL")],4 tag: "roadNumber",5 alphabet: "ipa"6)78let signpostPhonetics = TomTomSDKTextToSpeechEngine.PhoneticTranscription(9 transcriptions: ["'sxep.fart.my.'2ze.^m"],10 languages: [Locale(identifier: "nl-NL")],11 tag: "signpostText",12 alphabet: "ipa"13)1415let phonetics = [roadNumbersPhonetics, signpostPhonetics]16let message = "Turn left onto <roadNumber>A4</roadNumber> towards<signpostText>Scheepvaartmuseum</signpostText>"17let taggedMessage = TTSMessage.tagged(message: message, phonetics: phonetics)1819let priority = TTSMessagePriority(timeout: 10)20tts.play(message: taggedMessage, priority: priority)
Tracking voice synthesis status
To track the status of message synthesis, use the TextToSpeechEngineDelegate
set on the implementation of the TextToSpeechEngineDelegate
. All the methods provided by the delegate are optional. The following methods are available:
TextToSpeechEngineDelegate.didStart(message:)
- message playback has been started.TextToSpeechEngineDelegate.didStop(message:)
- message playback has been stopped.TextToSpeechEngineDelegate.didPause(message:)
- message playback has been paused.TextToSpeechEngineDelegate.didContinue(message:)
- message playback has been resumed.TextToSpeechEngineDelegate.didFinish(message:)
- message playback has been finished.TextToSpeechEngineDelegate.didFinish(message:withError:)
- an error has occurred.
1func didStart(message: TTSMessage) {2 /* YOUR CODE GOES HERE */3}45func didStop(message: TTSMessage) {6 /* YOUR CODE GOES HERE */7}89func didPause(message: TTSMessage) {10 /* YOUR CODE GOES HERE */11}1213func didContinue(message: TTSMessage) {14 /* YOUR CODE GOES HERE */15}1617func didFinish(message: TTSMessage, withError: Error) {18 /* YOUR CODE GOES HERE */19}
Language
The language of the underlying engine can be changed. This can be done via the TextToSpeech
constructor or with the TextToSpeech.changeLanguage(locale:)
method.
try! tts.changeLanguage(locale: Locale(identifier: "en-US"))
Adjusting volume
The volume of the underlying engine can be changed using the TextToSpeech.setVolume(_:)
method. SpeechVolume
is an enum with 3 states: low, medium, high. The volume is set to medium level by default.
tts.setVolume(.high)
Stop voice synthesis
The voice synthesis can be stopped with the TextToSpeech.stop()
method.
tts.stop()
TTS integration
While navigating, TomTomNavigation
generates a guidance update after each location change. Generated guidance contains an announcement if the distance is in a suitable range. GuidanceUpdateObserver.didGenerateAnnouncement(announcement:shouldPlay:)
is triggered when an announcement is generated. GuidanceAnnouncement
info can be used for voice instructions.
You can find more details in the turn-by-turn navigation guide.
1func didGenerateAnnouncement(announcement: GuidanceAnnouncement, shouldPlay: Bool) {2 guard shouldPlay else { return }3 guard !announcement.ssmlMessage.isEmpty else { return }4 let message: TTSMessage = .tagged(message: announcement.ssmlMessage, phonetics: [])5 let priority = TTSMessagePriority(timeout: 120)6 try! tts.changeLanguage(locale: announcement.language)7 tts.play(message: message, priority: priority)8}
Next steps
Since you have learned how to work with voice instructions, here are recommendations for the next steps: