【问题标题】:How to use AVFAudio's SDK to Record, Play and save audio如何使用 AVFAudio 的 SDK 录制、播放和保存音频
【发布时间】:2021-12-28 21:01:56
【问题描述】:

我一直在尝试实现 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 没有详细说明如何实现每种方法。例如;该文档指出,对于创建音频播放器:我们需要 init(contentsOf:url),但没有说明 url 是什么以及我们为什么使用它?任何人都可以帮助我了解进一步采取哪些步骤,我觉得我在绕圈子试图理解这个框架和苹果文档。

【问题讨论】:

  • "我们需要 init(contentsOf:url),但不涉及 url 是什么以及我们使用它的原因" -- URL 是您要播放的文件。否则,播放器不知道您从哪里播放音频数据。
  • @jnpdx 我不明白,如何播放尚未录制的文件?我们是在创建该文件本身吗?你能再深入一点吗?
  • 我特别指的是您问题的第二部分,您询问有关创建播放器的问题。在录制文件之前,您不会这样做。如果以后有时间我可以写一个答案,包括录音部分。
  • @jnpdx 是的,我很感激,因为过去两周我花了很多时间试图理解苹果文档以及如何使用这个 SDK。 SDK的流程我懂,但是不懂怎么用

标签: swift avfoundation avaudiorecorder avaudioengine avaudiofile


【解决方案1】:

这是一个相对简单的版本。查看内联 cmets 了解正在发生的事情。

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

【讨论】:

  • 感谢您分享这个,我看到的很多在线示例都是使用 swift UI,我想知道这是否有原因?我创建的项目在 UIKit 中,但我想知道在这个特定项目中使用 swift UI 是否更好,为什么?
  • UIKit vs SwiftUI 对于所有与录制和播放音频相关的代码都是无关紧要的——它只与 UI 呈现有关。我在这里选择使用 SwiftUI,因为我可以用更少的 UI 代码行创建一个最小的示例。如果这回答了您的问题,请使用绿色复选标记将其标记为已接受。
  • 谢谢,关于将文件本地保存到设备的问题,我仍然迷茫,如果你看看我的原始代码,它说文件路径是临时目录。我不相信临时目录会允许用户将文件保存到他们的设备上?文件路径还注明格式为 caf,我想将文件保存为 MP3 格式。我该怎么做?
  • “本地保存到设备”是什么意思?我正在使用文档目录—— is 在设备上。将文件转换为 mp3 应该是一个新问题(此外,您可能不会在没有很多麻烦的情况下使用 mp3,但 mp4 is trivial)——关于 SO 的问题应该处理 one 问题一次。
  • 如果您遇到这种情况,请参阅此内容以使您的文档目录在“文件”应用中可见:nemecek.be/blog/57/…
猜你喜欢
  • 1970-01-01
  • 2013-06-24
  • 2014-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
相关资源
最近更新 更多