AVSpeechSynthesizer works wrong with Russian language

Here is a simple app to demonstrate problem:

import SwiftUI
import AVFoundation

struct ContentView: View {
    var synthVM = SpeakerViewModel()

    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            HStack {
              Button("Speak") {
                  if self.synthVM.speaker.isPaused {
                      self.synthVM.speaker.continueSpeaking()
                } else {
                    self.synthVM.speak(text: "Привет на корабле! Кто это пришел к нам, чтобы посмотреть на это произведение?")
                }
              }
              Button("Pause") {
                  if self.synthVM.speaker.isSpeaking {
                      self.synthVM.speaker.pauseSpeaking(at: .word)
                }
              }
              Button("Stop") {
                  self.synthVM.speaker.stopSpeaking(at: .word)
              }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class SpeakerViewModel: NSObject {
    var speaker = AVSpeechSynthesizer()
  
  override init() {
    super.init()
    self.speaker.delegate = self
  }
  
  func speak(text: String) {
    let utterance = AVSpeechUtterance(string: text)
      utterance.voice = AVSpeechSynthesisVoice(language: "ru")
    speaker.speak(utterance)
  }
}

extension SpeakerViewModel: AVSpeechSynthesizerDelegate {
  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
    print("started")
  }

  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
    print("paused")
  }

  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {}
  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {}
  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
      guard let rangeInString = Range(characterRange, in: utterance.speechString) else { return }
      print("Will speak: \(utterance.speechString[rangeInString])")
  }
  func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
    print("finished")
  }
}

On simulator all works fine, but on real device there are many strange words appears in synthesis speak.

And willSpeakRangeOfSpeechString output is different on simulator and real device

Simulator:

started
Will speak: Привет
Will speak: на
Will speak: корабле!
Will speak: Кто
Will speak: это
Will speak: пришел
Will speak: к
Will speak: нам,
Will speak: чтобы
Will speak: посмотреть
Will speak: на
Will speak: это
Will speak: произведение?
finished

iPhone output have errors:

2021-10-12 17:09:32.613273+0300 VoiceTest[9027:203522] [AXTTSCommon] Broken user rule: \b([234567890]+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0]) > Error Domain=NSCocoaErrorDomain Code=2048 "The value “\b([234567890]+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])” is invalid." UserInfo={NSInvalidValue=\b([234567890]+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])}

2021-10-12 17:09:32.613548+0300 VoiceTest[9027:203522] [AXTTSCommon] Broken user rule: \b(1\d+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0]) > Error Domain=NSCocoaErrorDomain Code=2048 "The value “\b(1\d+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])” is invalid." UserInfo={NSInvalidValue=\b(1\d+)2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])}

2021-10-12 17:09:32.613725+0300 VoiceTest[9027:203522] [AXTTSCommon] Broken user rule: \b2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0]) > Error Domain=NSCocoaErrorDomain Code=2048 "The value “\b2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])” is invalid." UserInfo={NSInvalidValue=\b2 (мили|кварты|чашки|{столовых }ложки)(?=$|\s|[[:punct:]»\xa0])}

started

Will speak: Привет

Will speak: на 

Will speak: ивет на корабле!

Will speak: Кто

Will speak: это 

Will speak: Кто это пришел

Will speak: к

Will speak: нам,

Will speak: чтобы

Will speak: посмотреть

Will speak: на 

Will speak: реть на это

Will speak:  на это произведение?

finished

Error appears on iOS / iPadOS 15.0, 15.0.1, 15.0.2, 14.7 But all works fine on 14.8

Looks like engine error. How to fix that issue?

Replies

Please file a feedback post the number here. Thanks!

  • FB9699842

  • thank you!

Add a Comment

Any news regarding this issue?

Getting the same incorrect behaviour in an app that used to be working fine compiled a year and more ago.

Some sentences begin playing as intended then suddenly a part of a sentence (sometimes even starting in the middle of a word) begins playing in between the words, interrupting some further words from being read.

The audible result is... Well, at first I even thought it was reading some hidden characters first. But no, it is a problem of the ranges being read in a shuffled and intersecting ways..

The output of the willSpeakRangeOfSpeechString looks exactly like the one that Sanctor had provided.

Seems like something is broken in the latest iOS's AVSpeechSynthesizer. Hope there is to be a fix in iOS 16.

Seems to be fixed in iOS 16 Beta. Will test it more thoroughly, but some of the known places that produced wrong synth reading on iOS 15 are fine now.

  • Nice. Thanks for checking.

Add a Comment