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

使用NAudio混合原始音频流生成的WAV文件损坏问题排查

问题分析:混合音频流生成损坏WAV文件的原因

代码片段

string path = string.Empty;
private void SaveAudioRecording()
{
    timer.Dispose();
    if (string.IsNullOrEmpty(path))
    {
        path = Directory.GetCurrentDirectory() + "\\AudioRecordings_"+clientSession.clientInfo[0];
        Directory.CreateDirectory(path);
    }

    WaveMixerStream32 mix= new WaveMixerStream32();
    foreach (var stream in new MemoryStream[] { audioOutputMemoryStream, audioInputMemoryStream })
    {
        stream.Position = 0;
        if (stream != null && stream.Length > 0 && stream.Position < stream.Length)
        {
            RawSourceWaveStream reader = new RawSourceWaveStream(stream,new WaveFormat(41100,1));
            WaveChannel32 chanel = new WaveChannel32(reader);
            mix.AddInputStream(chanel);
        }
    }


    using (FileStream stream = File.Create(System.IO.Path.Combine(path, "Audio_recording_" + Directory.EnumerateFiles(path).Count().ToString() + ".wav")))
    {
        byte[] buffer = new byte[mix.Length];
        mix.Read(buffer, 0, buffer.Length);
        stream.Write(buffer, 0, buffer.Length);
        WriteWavHeader(stream,Convert.ToInt32(stream.Length));
        stream.Flush();
    }

    recordButton.IsEnabled = true;
}

private void WriteWavHeader(Stream stream, int audioDataSize)
{
    using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
    {
        writer.Write(Encoding.ASCII.GetBytes("RIFF"));
        writer.Write(audioDataSize + 36); // Total file size - 8 bytes
        writer.Write(Encoding.ASCII.GetBytes("WAVE"));
        writer.Write(Encoding.ASCII.GetBytes("fmt "));
        writer.Write(16); // Length of format data
        writer.Write((ushort)1); // PCM format
        writer.Write((ushort)1); // Not Stereo
        writer.Write(41100); // Sample rate
        writer.Write(82200); // Byte rate (Sample rate * Channels * BitsPerSample / 8)
        writer.Write((ushort)4); // Block align (Channels * BitsPerSample / 8)
        writer.Write((ushort)16); // Bits per sample
        writer.Write(Encoding.ASCII.GetBytes("data"));
        writer.Write(audioDataSize); // Size of audio data
    }
}

问题描述

生成的文件已损坏,无法播放,但文件有一定大小,说明字节已写入。我尝试将两个原始音频流混合为完整的WAV文件,因此为其写入WAV头。此前单独测试WAV头功能正常,但修改代码后生成的文件出现损坏。可能的问题原因是什么?

可能的原因分析

  • WAV头写入顺序错误:标准WAV文件结构是先头后数据,你现在先写音频数据再写头,播放器读取时会先找开头的RIFF标识,头在文件末尾导致播放器无法识别,直接判定文件损坏。
  • 音频数据读取不完整:WaveMixerStream32的Length属性可能无法准确返回混合后音频的实际长度,一次性读取mix.Length字节可能导致数据读取不全,或者包含无效内容。建议用循环调用Read方法直到返回0,确保读取所有有效数据。
  • 原始流格式与指定格式不匹配:创建RawSourceWaveStream时指定了WaveFormat(41100,1),但如果audioOutputMemoryStream和audioInputMemoryStream实际不是41100采样率、单声道、16位PCM格式,混合后的音频数据会错乱,即使头正确也无法正常播放。
  • 音频数据大小计算错误:调用WriteWavHeader时传入的stream.Length是已写入的字节数,但如果mix.Read没读满buffer,这个值就不准确。正确的做法是用mix.Read的返回值作为实际音频数据大小,而不是stream.Length。
  • 流指针位置错误:写完音频数据后,文件流指针在末尾,此时写入头会把头放在数据后面。正确流程应该是先写头(或占位头),再写数据,最后回到开头更新头的正确数值;或者先准备好头,按头→数据的顺序写入。
  • 混合流格式与手动写头不匹配:WaveMixerStream32混合后的流格式可能和你手动写的头参数不一致,比如混合后变成了立体声或者采样率改变。可以检查mix.WaveFormat的参数,确保和写头时用的参数完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:35:35