You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AVAudioRecorder录制无声音问题排查求助

iOS音频录制后文件为空且播放无声音问题

我正在尝试用Swift实现iOS平台的简单音频录制功能,使用AVAudioRecorder编写了如下AudioRecorder类:

import Foundation
import AVFoundation

class AudioRecorder: NSObject, AVAudioRecorderDelegate {
    var audioRecorder: AVAudioRecorder?
    var file: URL? = nil
    
    func setupAudioSession() {
        let session = AVAudioSession.sharedInstance()
        
        do {
            try session.setCategory(.playAndRecord, mode: .default)
            try session.setActive(true)
            try session.overrideOutputAudioPort(.speaker)
            debugPrint("Listo todo")
        } catch {
            print("Error setting up audio session: \(error.localizedDescription)")
        }
    }
    
    func startRecording() {
        file = getDocumentsDirectory().appendingPathComponent("recording.wav")
        
        let settings: [String: Any] = [
            AVFormatIDKey: kAudioFormatLinearPCM,
            AVSampleRateKey: 44100.0,
            AVNumberOfChannelsKey: 2,
            AVLinearPCMBitDepthKey: 16,
            AVLinearPCMIsFloatKey: false,
            AVLinearPCMIsBigEndianKey: false
        ]
        
        do {
            audioRecorder = try AVAudioRecorder(url: file!, settings: settings)
            audioRecorder?.delegate = self
            audioRecorder?.prepareToRecord()
            audioRecorder?.record()
        } catch {
            print("Error starting recording: \(error.localizedDescription)")
        }
    }
    
    func stopRecording() {
        audioRecorder?.stop()
    }
    
    private func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
    
    // MARK: AVAudioRecorderDelegate
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        if flag {
            print("Recording was successful.")
        } else {
            print("Recording failed.")
        }
    }
}

视图中会调用setupAudioSession方法,点击按钮时调用startRecording(调用前已通过AVAudioSession.sharedInstance().requestRecordPermission获取麦克风权限)。

点击停止录制后,audioRecorderDidFinishRecording回调返回"Recording was successful."日志。使用AVAudioPlayer播放文件时,能正确读取文件属性:

"Playing ... Optional("file:///var/mobile/Containers/Data/Application/0760DB3E-440E-4898-83A6-0888EC2EA399/Documents/recording.wav")"
"Duration: 4.180997732426304"
"Format: <AVAudioFormat 0x281ce80f0:  2 ch,  44100 Hz, Int16, interleaved>"
"Current Time: 0.0"
"Volume: 1.0"

但播放时完全没有声音,且我已在Info.plist中配置了NSMicrophoneUsageDescription。我在模拟器和真机上都做了测试,均无声音,将WAV文件下载到音频编辑器中查看发现文件为空。这是一个很基础的示例,搜索到的案例也都类似,请问我哪里遗漏了?


问题排查与解决方法

1. 修复AVAudioRecorder的强引用问题

你的audioRecorder是类的可选属性,如果AudioRecorder实例在录制过程中被提前释放,AVAudioRecorder也会被销毁,导致录制中断、文件无法写入。确保AudioRecorder实例在录制全程被强引用持有,比如在视图控制器中声明为var audioRecorder: AudioRecorder!,直到录制完成再释放。

2. 补充WAV格式的关键配置

使用kAudioFormatLinearPCM格式时,需要明确指定文件类型标识,否则可能导致文件写入不完整。在录制设置中添加AVAudioFileTypeKey:

let settings: [String: Any] = [
    AVFormatIDKey: kAudioFormatLinearPCM,
    AVSampleRateKey: 44100.0,
    AVNumberOfChannelsKey: 2,
    AVLinearPCMBitDepthKey: 16,
    AVLinearPCMIsFloatKey: false,
    AVLinearPCMIsBigEndianKey: false,
    AVAudioFileTypeKey: AVFileType.wav.rawValue // 新增该行
]

3. 确保文件写入完成

调用stopRecording后,AVAudioRecorder需要时间完成文件写入,建议在audioRecorderDidFinishRecording回调中再执行文件操作或播放。也可以在停止录制时显式触发写入:

func stopRecording() {
    audioRecorder?.stop()
    audioRecorder?.finishRecording() // 确保文件写入完成
}

4. 处理旧文件覆盖问题

每次调用startRecording都会生成相同路径的文件,若旧文件未被正确覆盖可能导致异常。录制前可删除旧文件:

func startRecording() {
    file = getDocumentsDirectory().appendingPathComponent("recording.wav")
    // 删除已存在的旧文件
    if FileManager.default.fileExists(atPath: file!.path) {
        try? FileManager.default.removeItem(at: file!)
    }
    // 后续录制逻辑...
}

5. 优化音频会话配置

将overrideOutputAudioPort替换为会话配置的options参数,更符合官方推荐的用法:

do {
    try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
    try session.setActive(true)
} catch {
    print("Audio session setup failed: \(error)")
}

6. 确认麦克风权限状态

即使请求了权限,也建议在回调中确认权限是否真正被授予:

AVAudioSession.sharedInstance().requestRecordPermission { granted in
    DispatchQueue.main.async {
        if granted {
            // 执行录制操作
        } else {
            print("麦克风权限未授权")
        }
    }
}

内容的提问来源于stack exchange,提问作者Ricardo Markiewicz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:37:17