David Hopkins
David Hopkins

Reputation: 1

Recognize speech from microphone while audio plays in the background

I want my app to recognize speech from the microphone and allow audio in the background to keep playing.

My app recognizes speech coming in through the microphone and converts it to text. When my app launches it shuts down any audio playing in the background.

Is it possible to let the background audio continue to play while my app listens for speech using the microphone?

Stripped down code:

import UIKit
import Speech
class ViewController: UIViewController {
    public private(set) var isRecording = false
    private var audioEngine: AVAudioEngine!
    private var inputNode: AVAudioInputNode!
    private var audioSession: AVAudioSession!
    private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override public func viewDidAppear(_ animated: Bool) {
        checkPermissions()
        startRecording()
        isRecording.toggle()
    }
    
    private func startRecording() {

        guard let recognizer = SFSpeechRecognizer(), recognizer.isAvailable else {
            handleError(withMessage: "Speech recognizer not available.")
            return
        }
        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
        recognitionRequest!.shouldReportPartialResults = true
        recognizer.recognitionTask(with: recognitionRequest!) { (result, error) in
            guard error == nil else { self.handleError(withMessage: error!.localizedDescription); return }
            guard let result = result else { return }
            print(result.bestTranscription.segments)
        }
        audioEngine = AVAudioEngine()
        inputNode = audioEngine.inputNode
        let recordingFormat = inputNode.outputFormat(forBus: 0)
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, _) in
            self.recognitionRequest?.append(buffer)
        }
        audioEngine.prepare()

        do {
            audioSession = AVAudioSession.sharedInstance()
            try audioSession.setCategory(.record, mode: .spokenAudio, options: .duckOthers)
            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
            try audioEngine.start()
        } catch {
            handleError(withMessage: error.localizedDescription)
        }
    }
    private func checkPermissions() {
        SFSpeechRecognizer.requestAuthorization { authStatus in
            DispatchQueue.main.async {
                switch authStatus {
                case .authorized: break
                default: self.handlePermissionFailed()
                }
            }
        }
    }

    private func handlePermissionFailed() {
        // Present an alert asking the user to change their settings.
        let ac = UIAlertController(title: "This app must have access to speech recognition to work.",
                                   message: "Please consider updating your settings.",
                                   preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "Open settings", style: .default) { _ in
            let url = URL(string: UIApplication.openSettingsURLString)!
            UIApplication.shared.open(url)
        })
        ac.addAction(UIAlertAction(title: "Close", style: .cancel))
        present(ac, animated: true)
    }
    private func handleError(withMessage message: String) {
        // Present an alert.
        let ac = UIAlertController(title: "An error occured", message: message, preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default))
        present(ac, animated: true)
    }
}

When I run my app and there is audio running in the background my app pauses the audio. I tried exiting my app and restarting the audio but when I return to my app it once again pauses the background audio. I would like the audio to keep playing while my app is using the microphone to listen.

I tried removing "options: .duckOthers" but it made no difference.

I believe what I want to do is possible. Shazam, for instance, can play a song on the speaker and simultaneously use the microphone to listen to it and identify it.

Upvotes: 0

Views: 687

Answers (1)

odlh
odlh

Reputation: 469

Try .playAndRecord instead of .record .

Upvotes: 0

Related Questions