mapbox / mapbox-navigation-ios

Turn-by-turn navigation logic and UI in Swift on iOS
https://docs.mapbox.com/ios/navigation/
Other
860 stars 310 forks source link

[Bug]: Nav will start talking even if mute is set on start #4670

Open JanTG1 opened 3 months ago

JanTG1 commented 3 months ago

Mapbox Navigation SDK version

3.1.1

Steps to reproduce

  1. Start an active guidance session
  2. Mute Navigation
  3. Close Navigation
  4. Re-start another navigation session
  5. The Navigator will start giving voice instructions, even if the button shows it is muted
  6. Un-mute and mute again to mute the voice

Expected behavior

The navigator should remember the last setting it had for voice instructions and never do something else than the button shows

Actual behavior

As stated above, the button shows that it is muted but the voice instructions will still be happening.

Is this a one-time issue or a repeatable issue?

repeatable

JanTG1 commented 2 months ago

Any updates on this issue?

JanTG1 commented 2 months ago

``In addition to the described issue, there are multiple more with the current speechSynthesizer, that can easily be found with minimal testing:

  1. Volume toggle goes crazy and pops up each time the speechSynthesizer ajusts the audio playback volume before trying to speak an instruction
  2. Manually toggeling voiceController.speechSynthesizer.muted = false does not work reliably, and does not update the mute icon state even if it did unmute

I am trying to make the voiceController speak an instruction, no matter the mute state. Since there is no function for that (there should be!), this is the work around, that does not work reliably:

await MainActor.run {
     self.unmuteAndSpeakInstruction(instruction: instruction)
}

    @MainActor
    func unmuteAndSpeakInstruction(instruction: SpokenInstruction) {
        guard let voiceController = self.navigationViewController.voiceController else { return }
        let wasMuted = voiceController.speechSynthesizer.muted

        if wasMuted {
            voiceController.speechSynthesizer.muted = false
        }

        voiceController.speechSynthesizer.speak(instruction, during: self.routeProgress.currentLegProgress, locale: .nationalizedCurrent)

        if wasMuted {
            voiceController.speechSynthesizer.muted = true
        }
    }
kried commented 1 month ago

Hi @JanTG1

Regarding the initial issue about unmuted voice instructions. Could you please try v3.2.0? There was a fix that should save the correct muted states across navigation sessions in UserDefaults.

I am trying to make the voiceController speak an instruction, no matter the mute state. Since there is no function for that (there should be!), this is the work around, that does not work reliably:

Could you please elaborate on the use case? Do you want to ignore the mute state and pronounce some voice instructions even if the state is muted? If so, the correct way to implement this will be to provide a custom speechSynthesizer that can override the muted property and the speak method to ignore the muted states in situations when you need it. Please take a look at this example for custom speechSynthesizer usage.


  1. Volume toggle goes crazy and pops up each time the speechSynthesizer ajusts the audio playback volume before trying to speak an instruction

We will investigate this issue. Could you please provide more details? Is this bug reproducible in the sample application? Is it reproducible on a specific iOS version?

JanTG1 commented 1 month ago

Hello @kried the first issue seems to have been fixed! However, there is still an issue when the instructions are muted. If there is audio playback in the background, the volume will still be lowered in order to prepare for the voice instruction, which will never run because of the muted state. After the voice instruction would have finished, the volume goes back up to normal.

Yes, you understood me correctly. I am trying to warn users or inform users about specific events. Since they are rare and since they is no third "Warnings only" mute state like many other navigation apps have, I wish to run these warning instructions in a way that would always be heard, no matter the current mute state. I will be trying your proposal, thanks for linking me an example!

As for the volume toggle bug: I am using iOS 17.5.1 on an iPhone 15 pro, running Mapbox Navigation 3.2.0. The bug is not really reproducible, it happens sometimes but I can't determine any pattern. If I do, I will be updating the thread. For the time being, experiment using audio playback and both muted and unmuted instructions and look for the "volume toggle" animation iOS sometimes shows from the side when pressing the volume buttons or changing the volume programmatically. Sometimes when the SpeechSynthesizer prepares for a voice instruction and adjusts the volume, the volume toggle will be visible. The same can happen after a voice instruction has been completed. This will result in the volume toiggle appearing, disappearing, and reappearing multiple times in a few seconds.

kried commented 1 month ago

Thank you for the detailed answer, we will investigate the above-mentioned issues.

JanTG1 commented 1 month ago

I was able to fix all the issues regarding voice instructions using a custom Voice Controller, which I also use to speak custom voice instructions that ignore the mute state. However, I still think that this functionality would be a good addition to the default functionality. The voiceController.speechSynthesizer.speak function would just need a bool whether to force that instruction or to match the mute state. That would avoid having to write a custom voice controller just for that simple feature.

I am happy to share if anyone wants to achieve that until then.