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

录制音频回放时ACMP4AACBaseDecoder解码失败问题求助

iOS音频录制回放二次录制后解码错误问题

我使用AVAudioRecorder实现音频录制,AVAudioPlayer实现回放功能。视图控制器加载时初始化一次AVAudioRecorder,每次录制覆盖同一文件,播放时使用录制器的URL。首次录制和回放正常,但再次录制并回放时出现以下错误日志:

2022-12-30 10:39:09.874066-0800 [40936:5138438]  Error deserializing gain control data
2022-12-30 10:39:09.874246-0800 [40936:5138438]  Error deserializing right channel stream
2022-12-30 10:39:09.874443-0800 [40936:5138438]  Error in deserializing element
2022-12-30 10:39:09.874545-0800 [40936:5138438]  Error deserializing packet
2022-12-30 10:39:09.874675-0800 [40936:5138438] [ac]   ACMP4AACBaseDecoder.cpp:1438  (0x127850040) Error decoding packet 1: err = -1, packet length: 198
2022-12-30 10:39:09.874781-0800 [40936:5138438] [ac]   ACMP4AACBaseDecoder.cpp:1447  '21 4E E5 44 87 E2 FC 62 0A 9B 64 42 80 D5 4E 01 17 D0 9D 47 CF FA E0 91 D2 5C FD 28 8B 3E 04 3A FD 71 F0 43 6D 20 48 52 EB 6C 73 7D 30 98 41 CC 12 F9 27 C3 10 60 4F 67 41 F6 4F 59 F1 A6 45 A4 B4 87 6A 4F 34 9C 26 CF 03 9A 9C 8D 20 14 6E 72 E6 C5 08 A6 BC D7 3B DE 3D 7F 61 1A 23 38 EC 95 1E 71 C8 1A D4 F1 B0 6E ED 9C 53 D3 FD 0E E1 5B AA CD 83 8F D3 0D 40 D7 D1 94 B4 F5 A8 1A 13 4D CE E2 37 69 14 FA E9 01 A2 50 2C AE 9C 75 49 04 06 8B 6F 01 23 20 0D 3E F1 5B 6F 47 D3 F3 F3 8A 06 E9 C5 AB 34 84 28 21 C7 4D DA 47 BE 9E 1A D5 6A B8 74 B2 EA 21 1D 51 0B 2D CE 1C 3F 01 F8 0F C0 7E 10 EB F5 C7'
2022-12-30 10:39:09.876272-0800 [40936:5138438]  Too few bits left in input buffer

以下是相关实现代码:

录制器初始化(视图控制器加载时仅执行一次)

func setupAudioRecorder() {
    // Set the audio file
    let audioFileURL = getFileUrl()
    
    // Setup audio session
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [])
    } catch _ {
    }
    
    // Define the recorder setting
    let recorderSetting = [AVFormatIDKey: NSNumber(value: kAudioFormatMPEG4AAC as UInt32),
                           AVSampleRateKey: 44100.0,
                           AVNumberOfChannelsKey: 2 ]
    
    audioRecorder = try? AVAudioRecorder(url: audioFileURL, settings: recorderSetting)
    audioRecorder?.delegate = self
    audioRecorder?.isMeteringEnabled = true
    audioRecorder?.prepareToRecord()
}

func getDocumentsDirectory() -> URL
{
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

func getFileUrl() -> URL
{
    let timeInterval = Int(NSDate().timeIntervalSince1970*1000)
    let audioFileName = "version_" + String(timeInterval) + ".m4a"
    let filePath = getDocumentsDirectory().appendingPathComponent(audioFileName)
    return filePath
}

开始录制

func startRecording() {
    if let recorder = audioRecorder {
        if !recorder.isRecording {
            let audioSession = AVAudioSession.sharedInstance()
            
            do {
                try audioSession.setActive(true)
            } catch _ {
            }
            
            // Start recording
            recorder.record()
            print("RECORD " + recorder.url.absoluteString)
        }
    }
}

播放器初始化(每次点击播放时调用)

func setUpPlayer() {
    guard let _ = self.audioPlayer  else {
        self.audioPlayer = try? AVAudioPlayer(contentsOf: self.audioRecorder!.url)
        self.audioPlayer?.delegate = self
        setAudioPlayerToUseSpeaker()
        return
    }
}

切换播放器状态

func toggleAudioPlayer() {
    if let audioPlayer = self.audioPlayer {
        if (audioPlayer.isPlaying) {
            audioPlayer.stop()
        } else {
            audioPlayer.play()
        }
    }
}

问题原因及解决方法

核心问题

  1. 音频文件未被彻底覆盖:AVAudioRecorder复用同一URL时,不会自动清空旧文件的全部内容,新录制的音频数据会和旧文件残留数据混合,破坏M4A文件的结构,导致解码失败。
  2. 播放器缓存未更新:二次录制后复用旧的AVAudioPlayer实例,它读取的是首次录制时的文件缓存,而非新录制的音频内容。

修复步骤

  1. 录制前重置音频文件与录制器
    修改getFileUrl返回固定文件名(确保每次录制覆盖同一文件):

    func getFileUrl() -> URL
    {
        let audioFileName = "recorded_audio.m4a"
        let filePath = getDocumentsDirectory().appendingPathComponent(audioFileName)
        return filePath
    }
    

    修改startRecording方法,每次录制前删除旧文件、重置录制器与播放器:

    func startRecording() {
        // 停止并清空播放器
        audioPlayer?.stop()
        audioPlayer = nil
        
        // 停止并清空录制器
        audioRecorder?.stop()
        audioRecorder = nil
        
        // 删除旧音频文件(如果存在)
        let targetURL = getFileUrl()
        if FileManager.default.fileExists(atPath: targetURL.path) {
            try? FileManager.default.removeItem(at: targetURL)
        }
        
        // 重新初始化录制器
        setupAudioRecorder()
        
        guard let recorder = audioRecorder else { return }
        
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(true)
        } catch {
            print("激活音频会话失败:\(error)")
        }
        
        recorder.record()
        print("RECORD " + recorder.url.absoluteString)
    }
    
  2. 播放前重新创建播放器
    修改setUpPlayer方法,每次播放都重新创建AVAudioPlayer,确保读取最新文件内容:

    func setUpPlayer() {
        // 销毁旧播放器
        audioPlayer?.stop()
        audioPlayer = nil
        
        // 重新创建播放器
        do {
            guard let recorderURL = audioRecorder?.url else { return }
            self.audioPlayer = try AVAudioPlayer(contentsOf: recorderURL)
            self.audioPlayer?.delegate = self
            setAudioPlayerToUseSpeaker()
        } catch {
            print("创建播放器失败:\(error)")
        }
    }
    
  3. 补充错误处理
    移除代码中的空catch块,添加错误打印,方便后续排查问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:00:55