Custom voice controller
You can provide a custom text-to-speech implementation for the Navigation SDK to use.
To provide a custom text-to-speech implementation:
- Implement a type that conforms to the
SpeechSynthesizing
protocol. Checkout theCustomVoiceController
implementation in the example below. - Customize and present
NavigationViewController
. Learn how in theCustomVoiceControllerUI.presentNavigationWithCustomVoiceController(_:_:)
method below.
/*This code example is part of the Mapbox Navigation SDK for iOS demo app,which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examplesTo learn more about each example in this app, including descriptions and linksto documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/custom-voice-controller/*/ import Foundationimport UIKitimport MapboxCoreNavigationimport MapboxNavigationimport MapboxDirectionsimport MapboxSpeechimport AVFoundation class CustomVoiceControllerUI: UIViewController { override func viewDidLoad() {super.viewDidLoad() let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648)let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268)let routeOptions = NavigationRouteOptions(coordinates: [origin, destination]) Directions.shared.calculate(routeOptions) { [weak self] (_, result) inswitch result {case .failure(let error):print(error.localizedDescription)case .success(let response):self?.presentNavigationWithCustomVoiceController(response: response)}}} func presentNavigationWithCustomVoiceController(response: RouteResponse) {// For demonstration purposes, simulate locations if the Simulate Navigation option is on.let indexedRouteResponse = IndexedRouteResponse(routeResponse: response, routeIndex: 0)let navigationService = MapboxNavigationService(indexedRouteResponse: indexedRouteResponse,customRoutingProvider: NavigationSettings.shared.directions,credentials: NavigationSettings.shared.directions.credentials,simulating: simulationIsEnabled ? .always : .onPoorGPS) // `MultiplexedSpeechSynthesizer` will provide "a backup" functionality to cover cases, which// our custom implementation cannot handle.let speechSynthesizer = MultiplexedSpeechSynthesizer([CustomVoiceController(), SystemSpeechSynthesizer()]) // Create a `RouteVoiceController` type with a customized `SpeechSynthesizing` instance.// A route voice controller monitors turn-by-turn navigation events and triggers playing spoken instructions// as audio using the custom `speechSynthesizer` we created above.let routeVoiceController = RouteVoiceController(navigationService: navigationService,speechSynthesizer: speechSynthesizer)// Remember to pass our RouteVoiceController` to `Navigation Options`!let navigationOptions = NavigationOptions(navigationService: navigationService,voiceController: routeVoiceController) // Create `NavigationViewController` with the custom `NavigationOptions`.let navigationViewController = NavigationViewController(for: indexedRouteResponse,navigationOptions: navigationOptions)navigationViewController.modalPresentationStyle = .fullScreen present(navigationViewController, animated: true, completion: nil)}} class CustomVoiceController: MapboxSpeechSynthesizer { // You will need audio files for as many or few cases as you'd like to handle// This example just covers left and right. All other cases will fail the Custom Voice Controller and// force a backup System Speech to kick inlet turnLeft = NSDataAsset(name: "turnleft")!.datalet turnRight = NSDataAsset(name: "turnright")!.data override func speak(_ instruction: SpokenInstruction, during legProgress: RouteLegProgress, locale: Locale? = nil) { guard let soundForInstruction = audio(for: legProgress.currentStep) else {// When `MultiplexedSpeechSynthesizer` receives an error from one of it's Speech Synthesizers,// it requests the next on the listdelegate?.speechSynthesizer(self,didSpeak: instruction,with: SpeechError.noData(instruction: instruction,options: SpeechOptions(text: instruction.text)))return}speak(instruction, data: soundForInstruction)} func audio(for step: RouteStep) -> Data? {switch step.maneuverDirection {case .left:return turnLeftcase .right:return turnRightdefault:return nil // this will force report that Custom View Controller is unable to handle this case}}}
Was this example helpful?