Ich möchte eine iOS-App (mit Swift 3 und Xcode 8.2.1) erstellen, die vom Mikrofon eines iPhone aufzeichnet und speichert den Datensatz in eine .caf
Datei.AVAudioFile Init funktioniert auf Simulator aber stürzt auf Gerät
Zuerst habe ich die folgenden Zeilen in die Info.plist Datei von meinem Projekt hinzugefügt:
<key>NSMicrophoneUsageDescription</key>
<string>Some description to explain why access is required</string>
Dann habe ich ein einfaches UIViewController
erstellt, die eine AVAudioEngine
setzt und installieren/Entfernen Sie einen Audio-Tipp, wenn Sie auf die Schaltflächen Record
und Stop
tippen.
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
}
}
Die App funktioniert auf dem Simulator in Ordnung: Ich habe meine Stimme aufnehmen kann, die URL der aufgenommenen Datei und Test greifen, dass meine Stimme korrekt aufgezeichnet worden. Allerdings stürzt die App ab, sobald ich sie auf einem Gerät starte (getestet mit einem iPhone 6s auf iOS 10.2.1). Die Konsole gibt mir die folgenden Protokolle:
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'
Dieses Problem scheint AVAudioPlayer working on Simulator but not on Real Device auf den Stack-Überlauf-Thread verwandt zu sein, aber ich kann nicht verstehen, wie seine Antwort in meinen eigenen Code zu implementieren, um mein Problem zu lösen.