菜鸟教程小白 发表于 2022-12-11 18:53:06

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


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

<hr/>

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

<pre><code>&lt;key&gt;NSMicrophoneUsageDescription&lt;/key&gt;
&lt;string&gt;Some description to explain why access is required&lt;/string&gt;
</code></pre>

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

<p><em>ViewController.swift</em></p>

<pre><code>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: &#34;test.caf&#34;) 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(&#34;Error: \(error)&#34;)
      }

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

      do {
            try engine.start()
      } catch {
            print(&#34;Error: \(error)&#34;)
      }
    }

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

    @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)
    }

    func urlFor(filename: String) -&gt; 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
    }

}
</code></pre>

<hr/>

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

<pre><code>2017-02-08 17:09:14.330151 AudioEngineSimpleApp Audio files cannot be non-interleaved. Ignoring setting AVLinearPCMIsNonInterleaved YES.
2017-02-08 17:09:14.333715 AudioEngineSimpleApp 54:   ERROR:    &gt;avae&gt; AVAudioFile.mm:160: AVAudioFileImpl: error -54
2017-02-08 17:09:14.333796 AudioEngineSimpleApp 54:   ERROR:    &gt;avae&gt; AVAudioFile.mm:122: ReadMagicCookie: error -50
2017-02-08 17:09:14.334369 AudioEngineSimpleApp *** Terminating app due to uncaught exception &#39;com.apple.coreaudio.avfaudio&#39;, reason: &#39;error -50&#39;
</code></pre>

<p>这个问题似乎与 Stack Overflow 线程 <a href="https://stackoverflow.com/questions/35457524/avaudioplayer-working-on-simulator-but-not-on-real-device" rel="noreferrer noopener nofollow">AVAudioPlayer working on Simulator but not on Real Device</a> 有关但我不知道如何将其响应实现到我自己的代码中以解决我的问题。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>我已经重构了我的代码,并用以下 <code>url</code> 属性替换了旧的 <code>urlFor(filename: String) -> URL?</code> 方法:</p>

<pre><code>let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(&#34;test.caf&#34;)
</code></pre>

<hr/>

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

<pre><code>import UIKit
import AVFoundation

class ViewController: UIViewController {

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

    override func viewDidLoad() {
      super.viewDidLoad()

      recordButton.setTitle(&#34;Record&#34;, for: .normal)

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

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

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

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

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

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

      // Toggle button title
      recordButton.setTitle(&#34;Record&#34;, for: .normal)

      print(url)
    }

}
</code></pre></p>
                                   
                                                <p style="font-size: 20px;">关于ios - AVAudioFile init 在模拟器上工作,但在设备上崩溃,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/42118181/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/42118181/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - AVAudioFile init 在模拟器上工作,但在设备上崩溃