如何使用AVFAudio的SDK录制、播放和保存音频
How to use AVFAudio's SDK to Record, Play and save audio
我一直在尝试实现 AVFoundation 的框架 AVFAudio,以便根据用户选择的预设来录制音频、播放音频以及更改音频数据。我也一直在尝试找出如何将文件本地保存到用户设备,但是,在阅读苹果关于 AVFAudio 的文档后,我几乎无法理解在创建这些文件时要采取哪些步骤。我一直在关注 https://www.raywenderlich.com/21868250-audio-with-avfoundation/lessons/1 并设法在这里设置了一些功能。
这里我设置了保存音频,但是如您所见,这只会将音频保存到一个临时目录中。我想知道如何将音频文件本地保存到用户的设备。
// MARK: Saving audio
var urlForVocals: URL {
let fileManger = FileManager.default
let tempDirectory = fileManger.temporaryDirectory
let filePath = "TempVocalRecording.caf"
return tempDirectory.appendingPathComponent(filePath)
}
我在使用 AVFAudio 时通常对 AVFoundation 的框架感到困惑,并且文档 https://developer.apple.com/documentation/avfaudio 没有详细说明如何实现每个方法。例如;文档指出,对于创建音频播放器:我们需要初始化(contentsOf:url),但没有深入探讨 url 是什么以及我们为什么要使用它?任何人都可以帮助我了解进一步采取哪些步骤,我觉得我 运行 在试图理解这个框架和苹果文档的圈子里。
这是一个相对简单的版本。请参阅内联评论以了解正在发生的事情。
cclass AudioManager : ObservableObject {
@Published var canRecord = false
@Published var isRecording = false
@Published var audioFileURL : URL?
private var audioPlayer : AVAudioPlayer?
private var audioRecorder : AVAudioRecorder?
init() {
//ask for record permission. IMPORTANT: Make sure you've set `NSMicrophoneUsageDescription` in your Info.plist
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.canRecord = true
} else {
self.canRecord = false
}
}
}
}
//the URL where the recording file will be stored
private var recordingURL : URL {
getDocumentsDirectory().appendingPathComponent("recording.caf")
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func recordFile() {
do {
//set the audio session so we can record
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
self.canRecord = false
fatalError()
}
//this describes the format the that the file will be recorded in
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
//create the recorder, pointing towards the URL from above
audioRecorder = try AVAudioRecorder(url: recordingURL,
settings: settings)
audioRecorder?.record() //start the recording
isRecording = true
} catch {
print(error)
isRecording = false
}
}
func stopRecording() {
audioRecorder?.stop()
isRecording = false
audioFileURL = recordingURL
}
func playRecordedFile() {
guard let audioFileURL = audioFileURL else {
return
}
do {
//create a player, again pointing towards the same URL
self.audioPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
self.audioPlayer?.play()
} catch {
print(error)
}
}
}
struct ContentView: View {
@StateObject private var audioManager = AudioManager()
var body: some View
{
VStack {
if !audioManager.isRecording && audioManager.canRecord {
Button("Record") {
audioManager.recordFile()
}
} else {
Button("Stop") {
audioManager.stopRecording()
}
}
if audioManager.audioFileURL != nil && !audioManager.isRecording {
Button("Play") {
audioManager.playRecordedFile()
}
}
}
}
}
我一直在尝试实现 AVFoundation 的框架 AVFAudio,以便根据用户选择的预设来录制音频、播放音频以及更改音频数据。我也一直在尝试找出如何将文件本地保存到用户设备,但是,在阅读苹果关于 AVFAudio 的文档后,我几乎无法理解在创建这些文件时要采取哪些步骤。我一直在关注 https://www.raywenderlich.com/21868250-audio-with-avfoundation/lessons/1 并设法在这里设置了一些功能。
这里我设置了保存音频,但是如您所见,这只会将音频保存到一个临时目录中。我想知道如何将音频文件本地保存到用户的设备。
// MARK: Saving audio
var urlForVocals: URL {
let fileManger = FileManager.default
let tempDirectory = fileManger.temporaryDirectory
let filePath = "TempVocalRecording.caf"
return tempDirectory.appendingPathComponent(filePath)
}
我在使用 AVFAudio 时通常对 AVFoundation 的框架感到困惑,并且文档 https://developer.apple.com/documentation/avfaudio 没有详细说明如何实现每个方法。例如;文档指出,对于创建音频播放器:我们需要初始化(contentsOf:url),但没有深入探讨 url 是什么以及我们为什么要使用它?任何人都可以帮助我了解进一步采取哪些步骤,我觉得我 运行 在试图理解这个框架和苹果文档的圈子里。
这是一个相对简单的版本。请参阅内联评论以了解正在发生的事情。
cclass AudioManager : ObservableObject {
@Published var canRecord = false
@Published var isRecording = false
@Published var audioFileURL : URL?
private var audioPlayer : AVAudioPlayer?
private var audioRecorder : AVAudioRecorder?
init() {
//ask for record permission. IMPORTANT: Make sure you've set `NSMicrophoneUsageDescription` in your Info.plist
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.canRecord = true
} else {
self.canRecord = false
}
}
}
}
//the URL where the recording file will be stored
private var recordingURL : URL {
getDocumentsDirectory().appendingPathComponent("recording.caf")
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func recordFile() {
do {
//set the audio session so we can record
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
self.canRecord = false
fatalError()
}
//this describes the format the that the file will be recorded in
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
//create the recorder, pointing towards the URL from above
audioRecorder = try AVAudioRecorder(url: recordingURL,
settings: settings)
audioRecorder?.record() //start the recording
isRecording = true
} catch {
print(error)
isRecording = false
}
}
func stopRecording() {
audioRecorder?.stop()
isRecording = false
audioFileURL = recordingURL
}
func playRecordedFile() {
guard let audioFileURL = audioFileURL else {
return
}
do {
//create a player, again pointing towards the same URL
self.audioPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
self.audioPlayer?.play()
} catch {
print(error)
}
}
}
struct ContentView: View {
@StateObject private var audioManager = AudioManager()
var body: some View
{
VStack {
if !audioManager.isRecording && audioManager.canRecord {
Button("Record") {
audioManager.recordFile()
}
} else {
Button("Stop") {
audioManager.stopRecording()
}
}
if audioManager.audioFileURL != nil && !audioManager.isRecording {
Button("Play") {
audioManager.playRecordedFile()
}
}
}
}
}