• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

ios - AVAudioFile init 在模拟器上工作,但在设备上崩溃

[复制链接]
菜鸟教程小白 发表于 2022-12-11 18:53:06 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我想构建一个 iOS 应用程序(使用 Swift 3 和 Xcode 8.2.1),从 iPhone 的麦克风记录并将记录保存到 .caf 文件。


首先,我在我的项目的 Info.plist 文件中添加了以下几行:

<key>NSMicrophoneUsageDescription</key>
<string>Some description to explain why access is required</string>

然后,我创建了一个简单的 UIViewController 来设置 AVAudioEngine 并在点击 Record停止按钮。

ViewController.swift

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var engine = AVAudioEngine()
    var file: AVAudioFile?
    var player = AVAudioPlayerNode()

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let url = urlFor(filename: "test.caf") else { return }
        do {
            file = try AVAudioFile(forWriting: url, settings: engine.inputNode!.inputFormat(forBus: 0).settings, commonFormat: engine.inputNode!.inputFormat(forBus: 0).commonFormat, interleaved: false)
        } catch {
            print("Error: \(error)")
        }

        engine.attach(player)
        engine.connect(player, to: engine.mainMixerNode, format: engine.mainMixerNode.outputFormat(forBus: 0))

        do {
            try engine.start()
        } catch {
            print("Error: \(error)")
        }
    }

    @IBAction func record(sender: AnyObject) {
        engine.inputNode?.installTap(onBus: 0, bufferSize: 1024, format: engine.mainMixerNode.outputFormat(forBus: 0)) { (buffer, time) -> Void in
            do {
                try self.file?.write(from: buffer)
            } catch {
                print("Error: \(error)")
            }
        }
    }

    @IBAction func stop(sender: AnyObject) {
        engine.inputNode?.removeTap(onBus: 0)
        // Print the url of the saved file
        let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
        print(urls[urls.endIndex - 1])
    }

    func urlFor(filename: String) -> URL? {
        // Get url of saved file
        if let dir = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true).first {
            let path = dir.appending(filename)
            return URL(fileURLWithPath: path)
        }
        return nil
    }

}

该应用程序在模拟器上运行良好:我可以录制我的声音,获取录制文件的 url 并测试我的声音是否已正确录制。但是,该应用程序在我在设备上启动后立即崩溃(在 iOS 10.2.1 上使用 iPhone 6s 进行了测试)。控制台给了我以下日志:

2017-02-08 17:09:14.330151 AudioEngineSimpleApp[7100:2659416] Audio files cannot be non-interleaved. Ignoring setting AVLinearPCMIsNonInterleaved YES.
2017-02-08 17:09:14.333715 AudioEngineSimpleApp[7100:2659416] [central] 54:   ERROR:    [0x1b7440c40] >avae> AVAudioFile.mm:160: AVAudioFileImpl: error -54
2017-02-08 17:09:14.333796 AudioEngineSimpleApp[7100:2659416] [central] 54:   ERROR:    [0x1b7440c40] >avae> AVAudioFile.mm:122: ReadMagicCookie: error -50
2017-02-08 17:09:14.334369 AudioEngineSimpleApp[7100:2659416] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -50'

这个问题似乎与 Stack Overflow 线程 AVAudioPlayer working on Simulator but not on Real Device 有关但我不知道如何将其响应实现到我自己的代码中以解决我的问题。



Best Answer-推荐答案


我已经重构了我的代码,并用以下 url 属性替换了旧的 urlFor(filename: String) -> URL? 方法:

let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("test.caf")

因此,以下代码在设备上正常工作:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var recordButton: UIButton!
    let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("test.caf")
    //let url = URL(fileURLWithPath: NSTemporaryDirectory().appending("test.caf")) also works
    var engine = AVAudioEngine()

    override func viewDidLoad() {
        super.viewDidLoad()

        recordButton.setTitle("Record", for: .normal)

        let file: AVAudioFile
        do {
            file = try AVAudioFile(forWriting: url, settings: engine.inputNode!.outputFormat(forBus: 0).settings)
        } catch {
            print("Error: \(error)")
            return
        }

        engine.inputNode?.installTap(onBus: 0, bufferSize: 1024, format: engine.inputNode!.outputFormat(forBus: 0)) { (buffer, time) -> Void in
            do {
                try file.write(from: buffer)
            } catch {
                print("Error: \(error)")
            }
        }
    }

    @IBAction func toggleAction(_ sender: AnyObject) {
        engine.isRunning ? stopRecording() : startRecording()
    }

    func startRecording() {
        do {
            // Start engine
            try engine.start()

            // Toggle button title
            recordButton.setTitle("Stop", for: .normal)
        } catch {
            print("Error: \(error)")
        }
    }

    func stopRecording() {
        // Stop engine
        engine.stop()

        // Toggle button title
        recordButton.setTitle("Record", for: .normal)

        print(url)
    }

}

关于ios - AVAudioFile init 在模拟器上工作,但在设备上崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42118181/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap