Приложение IOS аварийно завершает работу с «необходимым условием является ложным: IsFormatSampleRateAndChannelCountValid(format)» при выборе микрофона

У меня происходит сбой приложения, когда я использую микрофон в моем случае Microsoft Teams в фоновом режиме и пытаюсь записать звук внутри своего приложения.

Завершение работы приложения из-за необработанного исключения "com.apple.coreaudio.avfaudio", причина: "необходимое условие ложно: IsFormatSampleRateAndChannelCountValid(format)"

Пожалуйста, обратитесь к коду ниже:

func startRecording() {
        
        // Clear all previous session data and cancel task
        if recognitionTask != nil {
            recognitionTask?.cancel()
            recognitionTask = nil
        }

        // Create instance of audio session to record voice
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(AVAudioSession.Category.record, mode: AVAudioSession.Mode.measurement, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
        } catch {
            print("audioSession properties weren't set because of an error.")
        }
    
        self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

        let inputNode = audioEngine.inputNode

        guard let recognitionRequest = recognitionRequest else {
            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
        }

        recognitionRequest.shouldReportPartialResults = true

        self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

            var isFinal = false

            if result != nil {

                self.textField.text = result?.bestTranscription.formattedString
                isFinal = (result?.isFinal)!
            }

            if error != nil || isFinal {

                self.audioEngine.stop()
                inputNode.removeTap(onBus: 0)

                self.recognitionRequest = nil
                self.recognitionTask = nil

                self.micButton.isEnabled = true
            }
        })
    
        let recordingFormat = inputNode.outputFormat(forBus: 0)

    
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
            self.recognitionRequest?.append(buffer)
        }

        self.audioEngine.prepare()

        do {
            try self.audioEngine.start()
        } catch {
            print("audioEngine couldn't start because of an error.")
        }

        self.textField.text = ""
    }

Я почти уверен, что проблема где-то здесь, но не уверен, как это исправить.

let recordingFormat = inputNode.outputFormat(forBus: 0)
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
            self.recognitionRequest?.append(buffer)
        }

Итак, мне удалось исправить сбой, изменив код здесь, пусть recordFormat = inputNode.outputFormat (forBus: 0), если recordFormat.sampleRate == 0.0 { return } inputNode.installTap (onBus: 0, bufferSize: 1024, формат: recordFormat) { (buffer, when) in self.recognitionRequest?.append(buffer) } Но я все еще не понимаю, как выдать ошибку в UIControl и возможно ли это вообще?

Nursultan Yelemessov 21.11.2022 12:37
[JS за 1 час] - 9. Асинхронный
[JS за 1 час] - 9. Асинхронный
JavaScript является однопоточным, то есть он может обрабатывать только одну задачу за раз. Для обработки длительных задач, таких как сетевые запросы,...
Топ-10 компаний-разработчиков PHP
Топ-10 компаний-разработчиков PHP
Если вы ищете надежных разработчиков PHP рядом с вами, вот список лучших компаний по разработке PHP.
Скраппинг поиска Apple App Store с помощью Python
Скраппинг поиска Apple App Store с помощью Python
📌Примечание: В этой статье я покажу вам, как скрапировать поиск Apple App Store и получить точно такой же результат, как на Apple iMac, потому что...
Редкие достижения на Github ✨
Редкие достижения на Github ✨
Редкая коллекция доступна в профиле на GitHub ✨
Подъем в javascript
Подъем в javascript
Hoisting - это поведение в JavaScript, при котором переменные и объявления функций автоматически "перемещаются" в верхнюю часть соответствующих...
Улучшение генерации файлов Angular
Улучшение генерации файлов Angular
Angular - это фреймворк. Вы можете создать практически любое приложение без использования сторонних библиотек.
2
1
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Итак, приложение вылетало, потому что я не применил правильный канал микрофона.

Шаг 1 Создайте протокол в верхней части вашего кода после импорта, чтобы представить ошибку в файле, где у вас есть: пусть audioEngine = AVAudioEngine()

protocol FeedbackViewDelegate : AnyObject {
    func showFeedbackError(title: String, message: String)
    func audioDidStart(forType type : FeedbackViewType)
}

Шаг 2 В начале добавьте в свою функцию возврат логического значения.

 func startRecording() -> Bool {
}

Шаг 3 Добавьте эту строку кода в часть SharedInstance Catch (это предотвратит сбой)

 let audioSession = AVAudioSession.sharedInstance()
            do {
                try audioSession.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.measurement, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
                try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
            } catch {
                print("audioSession properties weren't set because of an error.")
                delegate?.showFeedbackError(title: "Sorry", message: "Mic is busy")
                return false
            }

Возврат выше предотвратит выполнение кода...

Шаг 4 Создайте расширение в контроллере представления

extension codeFileName : name of the protocol in my case its a FeedbackViewDelegate {
        func showFeedbackError(title: String, message: String) {
         
        }

Введите код здесь (в сети есть миллионы примеров) внутри функции вы можете создать предупреждение, а в части "внутри" использовать self

Можете ли вы поделиться своим кодом? Я столкнулся с той же проблемой и не смог решить ее с помощью вашего решения.

tamaramaria 23.11.2022 18:05

Попробуйте пройти код, который я только что опубликовал, и если у вас возникнет такая же проблема, вернитесь ко мне здесь. @тамарамария

Nursultan Yelemessov 23.11.2022 18:22

Я все еще получаю то же сообщение об ошибке required condition is false: IsFormatSampleRateAndChannelCountValid(format)

tamaramaria 24.11.2022 09:56

Попробуйте применить это, если recordFormat.sampleRate == 0.0 {return}. Между этим пусть recordFormat = inputNode.outputFormat(forBus: 0) inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordFormat) { (буфер, когда) в self.recognitionRequest?.append(buffer) } @tamaramaria

Nursultan Yelemessov 24.11.2022 10:27

Теперь я не получаю сообщение об ошибке, что прекрасно, но также не записывает мой голос.

tamaramaria 24.11.2022 11:10

Да, у меня нет решения о том, как заставить аудиозапись, когда микрофон занят, но приведенное выше решение выдаст ошибку и покажет вам, как отобразить сообщение об ошибке во внешнем интерфейсе, чтобы оно, по крайней мере, информировало пользователя. @тамарамария

Nursultan Yelemessov 24.11.2022 12:54

Спасибо тебе за помощь! Также опубликую, надеюсь, мое решение здесь

tamaramaria 24.11.2022 15:36
fileprivate let NibName = "FeedbackView"
protocol FeedbackViewDelegate : AnyObject {
    func showFeedbackError(title: String, message: String)
    func audioDidStart(forType type : FeedbackViewType)
}

enum FeedbackViewType {
    
    case feedbackView, rootcauseView, suggestionView, actionView
    
}

class FeedbackView: UIControl, ViewLoadable, SFSpeechRecognizerDelegate {
    
    @IBOutlet weak var textField: UITextField!
    
    static var nibName: String = NibName
    
    var feedbackViewType : FeedbackViewType = .feedbackView
    
    @IBOutlet var contentView: UIView!
    
    @IBOutlet weak var micButton: UIButton!
    
    @IBOutlet weak var micView: DefaultCardView!
    
    @IBOutlet weak var micImageView: UIImageView!
    
    weak var delegate : FeedbackViewDelegate?
    var allowTextEntry = true
    
    let speechRecognizer        = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))

       var recognitionRequest      : SFSpeechAudioBufferRecognitionRequest?
       var recognitionTask         : SFSpeechRecognitionTask?
       let audioEngine             = AVAudioEngine()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    init() {
        super.init(frame: CGRect.zero)
        commonInit()
    }
    
    private func commonInit() {
        Bundle(for: type(of: self)).loadNibNamed(NibName, owner: self, options: nil)
        backgroundColor = .clear
        addSubview(contentView)
        contentView.frame = self.bounds
        contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
      
    }
    
    func configure(text: String, placeholder:String, contentType: UITextContentType,keyboardType:UIKeyboardType) {
        
        print("Did configure keyboard")
        self.textField.textContentType = contentType
        self.textField.isSecureTextEntry = (contentType == .password)
        self.textField.keyboardType = keyboardType
        self.textField.delegate = self
        self.textField.placeholder = placeholder
        if (!text.isEmpty) {
            self.textField.text = text
        }
    }
    
    
    @IBAction func btnStartSpeechToText(_ sender: UIButton) {
//        allowTextEntry = false
        if audioEngine.isRunning {
            let audioText = textField.text
                  self.audioEngine.stop()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                self.textField.text = audioText
//                self.allowTextEntry = true
            }
            textField.text = audioText
                  self.micButton.isEnabled = true
                  self.micImageView.image = UIImage(named: "mic")
              } else {
                  print("Audio did start")
                  self.delegate?.audioDidStart(forType: self.feedbackViewType)
                  self.setupSpeech()
                  if self.startRecording() {
                      self.micImageView.image = UIImage(named: "micRed")

                  }
              }
    }
    
    func stopRecording() {
//        allowTextEntry = false
        let audioText = textField.text
        self.audioEngine.stop()
        self.recognitionRequest?.endAudio()
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
            self.textField.text = audioText
//            self.allowTextEntry = true
        }
        self.micButton.isEnabled = true
        self.micImageView.image = UIImage(named: "mic")
    }
    
    func setupSpeech() {
        
//           self.micButton.isEnabled = false
           self.speechRecognizer?.delegate = self

           SFSpeechRecognizer.requestAuthorization { (authStatus) in

               var isButtonEnabled = false

               switch authStatus {
               case .authorized:
                   isButtonEnabled = true

               case .denied:
                   isButtonEnabled = false
                   print("User denied access to speech recognition")

               case .restricted:
                   isButtonEnabled = false
                   print("Speech recognition restricted on this device")

               case .notDetermined:
                   isButtonEnabled = false
                   print("Speech recognition not yet authorized")
               }

               OperationQueue.main.addOperation() {
//                   self.micButton.isEnabled = isButtonEnabled
               }
           }
       }
    
//    func audioInputIsBusy(recordingFormat: AVAudioFormat) -> Bool {
//        guard recordingFormat.sampleRate == 0 || recordingFormat.channelCount == 0 else {
//            return false
//        }
//        return true
//    }
    
    func startRecording() -> Bool {
            
            // Clear all previous session data and cancel task
            if recognitionTask != nil {
                recognitionTask?.cancel()
                recognitionTask = nil
            }

            // Create instance of audio session to record voice
            let audioSession = AVAudioSession.sharedInstance()
            do {
                try audioSession.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.measurement, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
                try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
            } catch {
                print("audioSession properties weren't set because of an error.")
                delegate?.showFeedbackError(title: "Sorry", message: "Mic is busy")
                return false
            }
        
            self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

            let inputNode = audioEngine.inputNode

            guard let recognitionRequest = recognitionRequest else {
                fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
            }

            recognitionRequest.shouldReportPartialResults = true

            self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

                var isFinal = false

                if result != nil {

                    self.textField.text = result?.bestTranscription.formattedString
                    isFinal = (result?.isFinal)!
                }

                if error != nil || isFinal {

                    self.audioEngine.stop()
                    inputNode.removeTap(onBus: 0)
                    self.recognitionRequest = nil
                    self.recognitionTask = nil
                    self.micButton.isEnabled = true
                }
            })
        
            let recordingFormat = inputNode.outputFormat(forBus: 0)
            inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
                self.recognitionRequest?.append(buffer)
            }

            self.audioEngine.prepare()

            do {
                try self.audioEngine.start()
            } catch {
                print("audioEngine couldn't start because of an error.")
                delegate?.showFeedbackError(title: "Sorry", message: "Your microphone is used somewhere else")
                return false
            }

            self.textField.text = ""
        return true
        }
    
    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
        if available {
            self.micButton.isEnabled = true
        } else {
            self.micButton.isEnabled = false
        }
    }
    

}

extension FeedbackView: UITextFieldDelegate {
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        self.endEditing(true)
        return false
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return allowTextEntry
    }
}

Другие вопросы по теме