NAudio:在WCF中将IEEE Float输入流转换为MP3输出流

时间:2017-03-27 15:40:56

标签: wcf audio mp3 naudio

我在IEEE浮点数16000Hz,32位,1通道格式的字节数组(来自数据库)中有WAV数据。我希望将其转换为mp3,并通过WCF服务的响应对象将其流出。

使用NAudio包,到目前为止我所使用的是使用MediaFoundationEncoder.EncodetoMp3()写入文件。但是,一旦该文件被写入响应,它就没用了。我想跳过文件写入步骤并输出到流或字节数组并将其写入响应对象。

有没有办法让MediaFoundationEncoder在某种内存对象(没有文件)中输出mp3?

或者,尝试使用LameMP3FileWriter,它写入流, 我可以直接将IEEE float wav输入发送到LameMP3FileWriter,但是无论我使用的输出格式如何(44100,16,1),(22050,16,1),(11025,16, 1),...

当我尝试将IEEE浮点源转换为PCM或使用WaveFormatConversion对其进行上采样时,它会出错

  

AcmNotPossible调用acmStreamOpen

如果我在IEEE浮动源上使用Wave32to16Stream,它不会出错但没有音频。这条链对我不起作用:

    byte[] bytes = (Byte[])dt.Rows[0]["AudioContent"];//this is the dataTable from the database query containing the WAV audio

    var ms = new MemoryStream(bytes);
    var OLDfmt = WaveFormat.CreateIeeeFloatWaveFormat(16000,1);
    var NEWfmt = new WaveFormat(16000, 16, 1);//tried many
    var readr = new RawSourceWaveStream(ms,OLDfmt);

    //the following line errors on 'AcmNotPossible calling acmStreamOpen' 
    //var wav16 = new WaveFormatConversionStream(NEWfmt, readr);

    //the following does not error but no mp3 streams out at the end
    var wav16 = new Wave32To16Stream(readr);

    var outptMP3 = new MemoryStream();
    var writr = new LameMP3FileWriter(outptMP3, NEWfmt, LAMEPreset.STANDARD);
    wav16.CopyTo(writr);
    HttpContext.Current.Response.BufferOutput = true;
    HttpContext.Current.Response.AddHeader("Content-Type", "audio/mpeg");
    HttpContext.Current.Response.BinaryWrite(outptMP3.ToArray());

如果我只使用ms MemoryStream的BinaryWrite,原始音频在Chrome中可以正常播放(作为WAV流),所以我认为IEEE浮动源数据是有效的。

如果错误,请纠正我,但该错误(AcmNotPossible)似乎意味着我的机器上没有用于IEEE浮动格式的ACM编解码器?我查询我的机器,似乎没有32位ACM编解码器,这就是我尝试Wave32To16Stream转换的原因。

Lame MP3管道的临时步骤是从IEEE float 32位转到mp3吗?

1 个答案:

答案 0 :(得分:1)

抱歉,关于将IEEE浮点32位波转码为mp3流的主要问题有很多子问题,但我至少可以告诉你如何使用ACM编解码器(我认为)我简单的WCF服务:

  1. 将服务上的返回类型更改为Stream
  2. 在返回
  3. 之前将MemoryStream位置设置为0

    否则上面的链实际上对我有效。为了完整起见,我将提供完整的代码以及所有无关的SQL内容,因为我在一个不相关的SO问题中找到了答案:

    public Stream playWAVEFileFromDB() {
            //if using the file output method, I change the return type to string and return text instead of streams
            try
            {
                SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["myconnectionstring"].ConnectionString);
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                cmd.CommandText = "SELECT theWAVEColumn FROM myTable WHERE allThoseAudiosAreStored";
                SqlDataAdapter sda = new SqlDataAdapter();
                DataTable dt = new DataTable();
    
                conn.Open();
                sda.SelectCommand = cmd;
                sda.Fill(dt);
    
                //read the raw audio from database into a byte array
                byte[] bytes = (Byte[])dt.Rows[0]["colName"];
                var ms = new MemoryStream(bytes);
                var NEWfmt = new WaveFormat(16000, 16, 1);
                var OLDfmt = WaveFormat.CreateIeeeFloatWaveFormat(16000,1);//how its stored
                var readr = new RawSourceWaveStream(ms,OLDfmt);
                var wav16 = new Wave32To16Stream(readr);
                var outptMP3 = new MemoryStream();    
                var writr = new LameMP3FileWriter(outptMP3, NEWfmt, LAMEPreset.STANDARD);
                wav16.CopyTo(writr);
                outptMP3.Position = 0;
    
                HttpContext.Current.Response.BufferOutput = true;
                HttpContext.Current.Response.AddHeader("Content-Type", "audio/mpeg");
    
                conn.Close();
                conn.Dispose();
                sda.Dispose();
    
                return outptMP3;
            }
                catch (Exception e)
            {
                //do the error logging stuff
                return Stream.Null;
            }
        }