Post

Replies

Boosts

Views

Activity

Reply to Speech Recognition Problem in iOS 18.0
I'm experiencing the same issue on iOS 18, although it works fine on older versions. The problem is that I'm receiving partial results, but the text disappears and returns as empty later in the repeated callbacks. Adding the screenshot and code for reference here. import UIKit import Speech public protocol SpeechRecognizerWrapperDelegate: AnyObject { func speechRecognitionFinished(transcription: String) func speechRecognitionPartialResult(transcription: String) func speechRecognitionRecordingNotAuthorized(statusMessage: String) func speechRecognitionTimedOut() } public class SpeechRecognizerWrapper: NSObject, SFSpeechRecognizerDelegate { public weak var delegate: SpeechRecognizerWrapperDelegate? private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: (LocalData.sharedInstance.UPAppLanguage == LanguageCode.Hindi.rawValue) ? "hi-IN" : "en-IN"))! private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? private var recognitionTask: SFSpeechRecognitionTask? private let audioEngine = AVAudioEngine() var notAuthorise = true var noAuthStatus = "" var allPermissionGranted:(()->())? public override init() { super.init() setupSpeechRecognition() } private func setupSpeechRecognition() { speechRecognizer.delegate = self } func requestAuthorization() { if SFSpeechRecognizer.authorizationStatus() == .authorized && AVAudioSession.sharedInstance().recordPermission == .granted { self.notAuthorise = false return } self.notAuthorise = true SFSpeechRecognizer.requestAuthorization { [weak self] authStatus in guard let self = self else { return } /* The callback may not be called on the main thread. Add an operation to the main queue to update the record button's state. */ OperationQueue.main.addOperation { if authStatus != .authorized { self.notAuthorise = true self.noAuthStatus = "" if authStatus == .denied { self.noAuthStatus = "User denied access to speech recognition" } else if authStatus == .restricted { self.noAuthStatus = "Speech recognition restricted on this device" } } else { self.checkTheRecord() self.notAuthorise = false } } } } func checkTheRecord() { switch AVAudioSession.sharedInstance().recordPermission { case AVAudioSession.RecordPermission.granted: // self.allPermissionGranted?() break case AVAudioSession.RecordPermission.denied: break case AVAudioSession.RecordPermission.undetermined: AVAudioSession.sharedInstance().requestRecordPermission({ [weak self] (granted) in if granted { // self?.allPermissionGranted?() } else { self?.notAuthorise = true } }) default: break } } private var speechRecognitionTimeout: Timer? public var speechTimeoutInterval: TimeInterval = 2 { didSet { restartSpeechTimeout() } } private func restartSpeechTimeout() { speechRecognitionTimeout?.invalidate() speechRecognitionTimeout = Timer.scheduledTimer(timeInterval: speechTimeoutInterval, target: self, selector: #selector(timedOut), userInfo: nil, repeats: false) } public func startRecording() throws { if let recognitionTask = recognitionTask { recognitionTask.cancel() self.audioEngine.stop() self.audioEngine.inputNode.removeTap(onBus: 0) self.recognitionTask = nil self.recognitionRequest = nil self.recognitionTask = nil } let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) recognitionRequest = SFSpeechAudioBufferRecognitionRequest() let inputNode = audioEngine.inputNode let mixerNode = AVAudioMixerNode() audioEngine.attach(mixerNode) audioEngine.connect(inputNode, to: mixerNode, format: nil) guard let recognitionRequest = recognitionRequest else { return } // Configure request so that results are returned before audio recording is finished recognitionRequest.shouldReportPartialResults = true // A recognition task represents a speech recognition session. // We keep a reference to the task so that it can be cancelled. recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { [weak self] result, error in guard let self = self else { return } var isFinal = false if let result = result { print("formattedString: \(result.bestTranscription.formattedString)") isFinal = result.isFinal self.delegate?.speechRecognitionPartialResult(transcription: result.bestTranscription.formattedString) } if error != nil || isFinal { self.audioEngine.stop() inputNode.removeTap(onBus: 0) self.recognitionRequest = nil self.recognitionTask = nil } if isFinal { self.delegate?.speechRecognitionFinished(transcription: result!.bestTranscription.formattedString) self.stopRecording() } else { if error == nil { self.restartSpeechTimeout() } else { // cancel voice recognition } } } let recordingFormat = inputNode.outputFormat(forBus: 0) inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] (buffer: AVAudioPCMBuffer, when: AVAudioTime) in guard let self = self else { return } self.recognitionRequest?.append(buffer) } audioEngine.prepare() try audioEngine.start() } @objc private func timedOut() { stopRecording() self.delegate?.speechRecognitionTimedOut() } public func stopRecording() { audioEngine.stop() audioEngine.inputNode.removeTap(onBus: 0) // Remove tap on bus when stopping recording. recognitionRequest?.endAudio() speechRecognitionTimeout?.invalidate() speechRecognitionTimeout = nil } }
Oct ’24
Reply to Xcode tests stuck in testing state
Hey, I encountered the same issue with Xcode 15.3 as well. I tried fixing it, but unfortunately, it didn't work for me either. Here is the sample code: import XCTest @testable import Dummy final class CryptoDataAPIResorucesUnitTests: XCTestCase { func test_CoinAPIResources() { let resources = CoinAPIResources(httpUtility: HttpUtility()) let expectation = self.expectation(description: "CoinAPIResources") resources.getCoinList { coinData, errorMessage in XCTAssertNotNil(coinData) XCTAssertNil(errorMessage) expectation.fulfill() } waitForExpectations(timeout: 5) } }
1w