2014-06-13 7 views
4

배경 : audio/wav의 MIME 유형으로 데이터를 반환하는 서비스를 사용하고 있습니다. 이 오디오 (현재 MVC 응용 프로그램으로 빌드 됨)에 대한 재생 메커니즘을 제공해야합니다. 예를 들어, 종단점은 다음과 같습니다. https://audio.fooservice.com/GetAudio?audioId=123wav를 HTTP를 통해 mp3로 실시간으로 변환합니다.

오디오는 8kHz, 1 채널 u-law입니다.

HTML5 <audio> 태그를 사용할 때 다양한 형식의 브라우저가 지원되므로 Internet Explorer에서 재생하지 않기 때문에 원래의 u-law wav를 사용할 수 없습니다.

내 제안 된 솔루션은 소스 형식을 mp3로 실시간 변환하는 것입니다.

나는 여기에 여러 다른 질문에서와 NAudio 포럼에서 부분적으로 작업 솔루션을 함께 자갈길했지만, 아래의 코멘트에 언급 한 바와 같이이 예외가 발생합니다 : 내가 파고 봤는데

private void NAudioTest(string url) 
{ 
    Stream outStream = new MemoryStream(); 
    var format = WaveFormat.CreateMuLawFormat(8000, 1); 

    using (Stream ms = new MemoryStream()) 
    { 
     var request = (HttpWebRequest)WebRequest.Create(url); 
     request.KeepAlive = false; 
     request.ProtocolVersion = HttpVersion.Version10; 

     using (Stream stream = request.GetResponse().GetResponseStream()) 
     { 
      using (var reader = new RawSourceWaveStream(stream, format)) 
      { 
       // reader is not seekable; we need to convert to a byte array to seek 
       var bytes = reader.ToByteArray(); 

       // create a new stream from the byte aray 
       var seekableStream = new MemoryStream(bytes); 

       // instantiating a WaveFileReader as follows will throw an exception: 
       // "System.FormatException: Not a WAVE file - no RIFF header" 
       using (var waveReader = new WaveFileReader(seekableStream)) 
       { 
        using (var pcmStream = WaveFormatConversionStream.CreatePcmStream(waveReader)) 
        { 
         var pcmBytes = pcmStream.ToByteArray(); 
         var mp3 = pcmBytes.ToMp3(); 
        } 
       } 
      } 
     } 
    } 
} 

public static class StreamExtensions 
{ 
    public static byte[] ToByteArray(this Stream stream) 
    { 
     var ms = new MemoryStream(); 
     var buffer = new byte[1024]; 
     int bytes = 0; 

     while ((bytes = stream.Read(buffer, 0, buffer.Length)) > 0) 
      ms.Write(buffer, 0, bytes); 

     return ms.ToArray(); 
    } 
} 

public static class ByteExtensions 
{ 
    public static byte[] ToMp3(this byte[] bytes) 
    { 
     using (var outStream = new MemoryStream()) 
     { 
      using (var ms = new MemoryStream(bytes)) 
      { 
       using (var reader = new WaveFileReader(ms)) 
       { 
        using (var writer = new LameMP3FileWriter(outStream, reader.WaveFormat, 64)) 
        { 
         reader.CopyTo(writer); 
         return outStream.ToArray(); 
        } 
       } 
      } 
     } 
    } 
} 

대부분의 하루 동안이 주변에서 나는 무언가에 불필요한 복잡성을 도입하는 것처럼 느낍니다. 은 매우 간단해야합니다.처럼 보입니다.

도움을 주시면 감사하겠습니다.

참고 : 소스 형식을 변경할 수 없으며 지원 IE가 필요합니다.

EDIT : RIFF 예외를 해결하고 MP3 스트림을 생성 할 수 있지만 화이트 노이즈 일뿐입니다. 잘하면 나는 그것을 해결할 수 있습니다. 새로운 코드는 다음과 같습니다.

[HttpGet] 
public ActionResult GetMp3(string url) 
{ 
    if (String.IsNullOrWhiteSpace(url)) 
     return null; 

    var muLawFormat = WaveFormat.CreateMuLawFormat(8000, 1); 
    var compressedStream = new MemoryStream(); 

    using (var ms = new MemoryStream()) 
    { 
     var request = (HttpWebRequest)WebRequest.Create(url); 
     request.KeepAlive = false; 
     request.ProtocolVersion = HttpVersion.Version10; 

     using (Stream webStream = request.GetResponse().GetResponseStream()) 
     { 
      var buffer = new byte[4096]; 
      int read; 
      while (webStream != null && (read = webStream.Read(buffer, 0, buffer.Length)) > 0) 
       ms.Write(buffer, 0, read); 
     } 

     ms.Position = 0; 

     using (WaveStream wav = WaveFormatConversionStream.CreatePcmStream(new RawSourceWaveStream(ms, muLawFormat))) 
     using (var mp3 = new LameMP3FileWriter(compressedStream, new WaveFormat(), LAMEPreset.MEDIUM_FAST)) 
      wav.CopyTo(mp3); 
    } 

    compressedStream.Seek(0, 0); 
    return new FileStreamResult(compressedStream, "audio/mpeg"); 
} 
+1

소스의 실제 웨이브 형식을'LameMP3FileWriter' 생성자에 제공해야합니다. 'new WaveFormat() 대신'wav.WaveFormat'을 사용하십시오. 그렇지 않으면 잘못된 데이터를 읽게됩니다. – Corey

+0

Corey에게 감사드립니다. 'CreatePcmStream' 메쏘드가 기본'WaveFormat' 생성자와 같은 형식으로 스트림을 리턴 할 것이라고 잘못 가정했습니다. 필자의 소스 스트림에 대한 문서 (및 MIME 형식)가 올바르지 않으며, 일주일 동안 아무 것도하지 않고 보냈다. – LiquidPony

답변

0

이 코드는 저에게 효과적입니다. 원하는 작업을 정확하게 수행해야했습니다. 희망이 다른 사람뿐만 아니라 도움이됩니다. NAAME과 LAME을 사용했습니다.

libmp3lamexx.dll 파일을 웹 서버의 BIN 위치 또는 % PATH % 변수의 일부 폴더로 복사해야합니다. 그렇지 않으면 작동하지 않습니다.

 string sq = /* URL of WAV file (http://foo.com/blah.wav) */ 

     Response.ContentType = "audio/mpeg"; 

     using (WebClient wc = new WebClient()) 
     { 
      if (!sq.ToLower().EndsWith(".wav")) 
      { 
       byte[] rawFile = wc.DownloadData(sq.Trim()); 
       Response.OutputStream.Write(rawFile, 0, rawFile.Length); 
      } 
      else 
      { 
       using (var wavReader = new WaveFileReader(new MemoryStream(wc.DownloadData(sq.Trim())))) 
       { 
        try 
        { 
         using (var wavWriter = new LameMP3FileWriter(Response.OutputStream, wavReader.WaveFormat, LAMEPreset.ABR_128)) 
         { 
          wavReader.CopyTo(wavWriter); 
         } 
        } 
        catch (ArgumentException) 
        { 
         var newFormat = new WaveFormat(wavReader.WaveFormat.SampleRate, 16, 2); 

         using (var pcmStream = new WaveFormatConversionStream(newFormat, wavReader)) 
         { 
          using (var wavWriter = new LameMP3FileWriter(Response.OutputStream, pcmStream.WaveFormat, LAMEPreset.ABR_128)) 
          { 
           pcmStream.CopyTo(wavWriter); 
          } 
         } 
        } 
       } 
      } 

      Response.Flush(); 
      Response.End(); 
     }