AVAudioEngine 在扬声器中录制和播放声音

发布于 2025-01-11 02:39:26 字数 3240 浏览 0 评论 0原文

我想用 AVAudioEngine 创建一个 iOS 应用程序,主要功能是从麦克风录制声音并在扬声器上播放声音。我想在扬声器(底部扬声器)和接收器(顶部扬声器)之间切换。我的代码如下,这在接收器上工作正常。我的问题是扬声器无法播放声音。请帮助我,非常感谢!

import  AVFoundation
import UIKit

class XViewController: UIViewController {
    let audioSession = AVAudioSession.sharedInstance()
    var player: AVAudioPlayerNode!
    var engine: AVAudioEngine!

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        setupAudioSession()
        setupNotifications()
        initRecorder()
    }

    func setupAudioSession() {
        do{
            try audioSession.setPreferredSampleRate(16000)
            try self.audioSession.setPreferredOutputNumberOfChannels(1)
            try audioSession.setCategory(.playAndRecord, options: [])
            try audioSession.overrideOutputAudioPort(.none)
            try audioSession.setMode(.voiceChat)
            try audioSession.setActive(true)
        } catch{
            print(error.localizedDescription)
        }
    }

    func initRecorder() {
        player = AVAudioPlayerNode()
        engine = AVAudioEngine()
        let input = engine.inputNode
        engine.attach(player)
        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)
        engine.connect(player, to: engine.outputNode, format: inputFormat)
        let mixerNode = AVAudioMixerNode()
        engine.attach(mixerNode)
        engine.connect(input, to: mixerNode, format: nil)
        input.installTap(onBus: bus, bufferSize: 2048, format: inputFormat) { (buffer, time) -> Void in
            self.player.scheduleBuffer(buffer)
            print(buffer)
        }
    }

    func start() {
        engine.prepare()
        try! engine.start()
        player.play()
    }

    func playToLoudSpeaker() {
        do{
            try self.audioSession.overrideOutputAudioPort(.speaker)
        } catch{
            print(error.localizedDescription)
        }
    }

    func setupNotifications() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(handleRouteChange),
                                               name: AVAudioSession.routeChangeNotification,
                                               object: nil)
    }

    @objc func handleRouteChange(notification: Notification) {
        guard let userInfo = notification.userInfo,
              let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
              let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
            return
        }
        // Switch over the route change reason.
        switch reason {
        case .override :
            resume()
        default: break
        }
    }

    func resume() {
        self.engine.stop()
        self.player.stop()
        self.engine.detach(player)

        self.initRecorder()

        engine.prepare()
        try? self.engine.start()
        player.play()
    }

    @IBAction private func startRecorderAndPlay(_ sender: UIButton) {
        start()
    }

    @IBAction private func switchToLoudSpeaker(_ sender: UIButton) {
        playToLoudSpeaker()
    }
}

I want to create a iOS app with AVAudioEngine, main function is record sound from mic and play sound on speaker. I want to switch between loud speaker(bottom speaker) and receiver(top speaker). My code is below, this work fine on receiver. My problem is sound can not play in loud speaker. Please help me, many thanks!

import  AVFoundation
import UIKit

class XViewController: UIViewController {
    let audioSession = AVAudioSession.sharedInstance()
    var player: AVAudioPlayerNode!
    var engine: AVAudioEngine!

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        setupAudioSession()
        setupNotifications()
        initRecorder()
    }

    func setupAudioSession() {
        do{
            try audioSession.setPreferredSampleRate(16000)
            try self.audioSession.setPreferredOutputNumberOfChannels(1)
            try audioSession.setCategory(.playAndRecord, options: [])
            try audioSession.overrideOutputAudioPort(.none)
            try audioSession.setMode(.voiceChat)
            try audioSession.setActive(true)
        } catch{
            print(error.localizedDescription)
        }
    }

    func initRecorder() {
        player = AVAudioPlayerNode()
        engine = AVAudioEngine()
        let input = engine.inputNode
        engine.attach(player)
        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)
        engine.connect(player, to: engine.outputNode, format: inputFormat)
        let mixerNode = AVAudioMixerNode()
        engine.attach(mixerNode)
        engine.connect(input, to: mixerNode, format: nil)
        input.installTap(onBus: bus, bufferSize: 2048, format: inputFormat) { (buffer, time) -> Void in
            self.player.scheduleBuffer(buffer)
            print(buffer)
        }
    }

    func start() {
        engine.prepare()
        try! engine.start()
        player.play()
    }

    func playToLoudSpeaker() {
        do{
            try self.audioSession.overrideOutputAudioPort(.speaker)
        } catch{
            print(error.localizedDescription)
        }
    }

    func setupNotifications() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(handleRouteChange),
                                               name: AVAudioSession.routeChangeNotification,
                                               object: nil)
    }

    @objc func handleRouteChange(notification: Notification) {
        guard let userInfo = notification.userInfo,
              let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
              let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
            return
        }
        // Switch over the route change reason.
        switch reason {
        case .override :
            resume()
        default: break
        }
    }

    func resume() {
        self.engine.stop()
        self.player.stop()
        self.engine.detach(player)

        self.initRecorder()

        engine.prepare()
        try? self.engine.start()
        player.play()
    }

    @IBAction private func startRecorderAndPlay(_ sender: UIButton) {
        start()
    }

    @IBAction private func switchToLoudSpeaker(_ sender: UIButton) {
        playToLoudSpeaker()
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文