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

使用NAudio生成的WAV文件时长为0但文件大小增加的问题排查

问题:生成的WAV文件时长始终显示为0,文件大小正常变化

代码实现

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

    
    using (MemoryStream audioDataStream = new MemoryStream())
    {
        MixingSampleProvider mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(41100, 1));

        while (recQue.TryDequeue(out string first))
        {
            string firstDel = first.Substring(first.IndexOf('§'), 4);

            if (recQue.TryDequeue(out string second))
            {
                string secondDel = second.Substring(second.IndexOf('§'), 4);

                first = first.Replace(firstDel, string.Empty);
                second = second.Replace(secondDel, string.Empty);

                if (firstDel != secondDel)
                {
                    mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(41100, 1));

                    first = first.Replace(firstDel, string.Empty);
                    second = second.Replace(secondDel, string.Empty);

                    byte[] firstAudioData = Convert.FromBase64String(first);
                    byte[] secondAudioData = Convert.FromBase64String(second);

                    MemoryStream[] memoryStreams = { new MemoryStream(), new MemoryStream() };

                    await memoryStreams[0].WriteAsync(firstAudioData, 0, firstAudioData.Length);
                    await memoryStreams[1].WriteAsync(secondAudioData, 0, secondAudioData.Length);

                    foreach (var stream in memoryStreams)
                    {
                        await stream.FlushAsync();
                        var reader = new RawSourceWaveStream(stream, new WaveFormat(41100, 1));
                        var waveProvider = reader.ToSampleProvider();
                        mixer.AddMixerInput(waveProvider);
                        var tempBuffer = new float[mixer.WaveFormat.SampleRate * mixer.WaveFormat.Channels * 5]; // 5-second buffer
                        int samplesRead;

                        while ((samplesRead = mixer.Read(tempBuffer, 0, tempBuffer.Length)) > 0)
                        {
                            var byteBuffer = new byte[samplesRead * sizeof(float)];
                            Buffer.BlockCopy(tempBuffer, 0, byteBuffer, 0, byteBuffer.Length);
                            await audioDataStream.WriteAsync(byteBuffer, 0, byteBuffer.Length);
                        }
                    }
                }
                else
                {
                    first = first.Replace(firstDel, string.Empty);
                    second = second.Replace(secondDel, string.Empty);

                    byte[] firstAudioData = Convert.FromBase64String(first);
                    byte[] secondAudioData = Convert.FromBase64String(second);

                    await audioDataStream.WriteAsync(firstAudioData, 0, firstAudioData.Length);
                    await audioDataStream.WriteAsync(secondAudioData, 0, secondAudioData.Length);
                    await audioDataStream.FlushAsync();
                }
            }
            else
            {
                first = first.Replace(firstDel, string.Empty);
                byte[] firstAudioData = Convert.FromBase64String(first);
                await audioDataStream.WriteAsync(firstAudioData, 0, firstAudioData.Length);
                await audioDataStream.FlushAsync();
            }
        }
        WaveFileWriter writer = new WaveFileWriter(System.IO.Path.Combine(path, "Audio_recording_" + Directory.EnumerateFiles(path).Count().ToString() + ".wav"),mixer.WaveFormat);
        WriteWavHeader(writer, Convert.ToInt32(audioDataStream.Length));
        audioDataStream.Seek(0, SeekOrigin.Begin);
        await audioDataStream.CopyToAsync(writer);
        await writer.FlushAsync();
    }
    recQue = new ConcurrentQueue<string>();
    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)2); // 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
    }
}

问题描述

已确认WriteWavHeader方法可正常工作,但生成的WAV文件无论文件大小如何,时长始终显示为0。逻辑上,当firstDel与secondDel不匹配时混合两个原始音频流,否则将它们拼接至内存流,最终生成WAV文件。预期添加更多音频数据时文件时长会增加,但仅文件大小有所变化,请问该问题的可能原因是什么?

可能的原因分析

  • 音频格式与WAV头不匹配:
    混合音频时使用的是32位浮点格式(WaveFormat.CreateIeeeFloatWaveFormat(41100, 1)),但WriteWavHeader硬编码了16位PCM的参数(如BitsPerSample=16、BlockAlign=2),且覆盖了WaveFileWriter自动生成的对应格式头。播放器会根据WAV头的参数计算时长,实际数据格式与头信息不符时,会导致解析错误,显示时长为0。

  • 内存流位置未重置导致混合数据无效:
    写入音频数据到memoryStreams后,未将流的Position重置为0,导致后续RawSourceWaveStream读取不到任何音频数据,混合后的输出为空。即使文件大小因拼接部分的数据增加,混合部分的无效数据也会破坏整体文件的可解析性。

  • 音频数据格式混杂:
    拼接和单个音频处理时直接写入的是原始16位PCM数据,而混合部分写入的是32位浮点数据,两种格式混杂在同一个文件中,播放器无法识别统一的音频格式,进而无法正确计算时长。

  • WaveFileWriter的使用错误:
    代码中先通过WaveFileWriter初始化文件(使用混合器的浮点格式),随后调用WriteWavHeader覆盖了正确的头信息,导致文件头与实际数据格式完全不匹配,播放器无法解析出有效时长。

内容的提问来源于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 15:55:42