问题
I want to play MP3 file downloaded from the web using NET provided System.Media.SoundPlayer mechanism. As it works with WAV formats, it requires the support of e.g. NAudio library - I need to convert MP3 to WAV.
I want to do all operations in memory, as I need it to be so called fast, but I have problems. Below I've shown code which works as expected, but it cooperates with files. Instead I need to make it working using memory operations only.
(1) works, but involves disk operations:
public void Speak(Uri mp3FileUri)
{
using (var client = new WebClient())
{
using (var networkStream = client.OpenRead(mp3FileUri))
{
if (networkStream != null)
{
var temp = Path.GetTempPath();
var mp3File = Path.Combine(temp, "file.mp3");
var wavFile = Path.Combine(temp, "file.wav");
using (var fileStream = File.Create(mp3File))
{
networkStream.CopyTo(fileStream);
}
using (var reader = new Mp3FileReader(mp3File))
{
WaveFileWriter.CreateWaveFile(wavFile, reader);
}
using(var player = new SoundPlayer(wavFile))
{
player.Play();
}
}
}
}
}
(2) doesn't work - no exception is thrown, but nothing is played:
public void Speak(Uri mp3FileUri)
{
using (var client = new WebClient())
{
using (var networkStream = client.OpenRead(mp3FileUri))
{
if (networkStream != null)
{
var memStream = new MemoryStream();
networkStream.CopyTo(memStream);
memStream.Position = 0;
using (var reader = new Mp3FileReader(memStream))
{
var outStream = new MemoryStream();
using (var writer = new WaveFileWriter(outStream, reader.WaveFormat))
{
var num = 0L;
var buffer = new byte[reader.WaveFormat.AverageBytesPerSecond * 4];
while (true)
{
var count = reader.Read(buffer, 0, buffer.Length);
if (count != 0)
{
num += count;
if (num <= int.MaxValue)
writer.Write(buffer, 0, count);
else
throw new InvalidOperationException("Too large file or endless stream.");
}
else
break;
}
writer.Flush();
outStream.Position = 0;
using(var player = new SoundPlayer(outStream))
{
player.Play(); /* why silence ? */
}
}
}
}
}
}
}
How can it be done and what is wrong with the second code sample ?
回答1:
Why not skip using SoundPlayer and play the MP3 directly through NAudio? NAudio was designed to do this. Just download the MP3 into a temp file somewhere, and play it with NAudio, and delete the temp file once your finished with it. I don't think anything can be done to reduce a delay while downloading the file though.
http://naudio.codeplex.com/wikipage?title=MP3
回答2:
Based on Lee Harrison answer, I've created alternative code which is better.
(3) plays directly MP3 file from WEB without conversion to WAV and without usage of disk operations:
public void Speak(Uri mp3FileUri)
{
using (var client = new WebClient())
{
using (var networkStream = client.OpenRead(mp3FileUri))
{
if (networkStream != null)
{
using (var memStream = new MemoryStream())
{
networkStream.CopyTo(memStream);
memStream.Position = 0;
using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
var waveEvent = new ManualResetEvent(false);
waveOut.PlaybackStopped += (sender, e) => waveEvent.Set();
waveEvent.Reset();
using (var rdr = new Mp3FileReader(memStream))
using (var waveStream = WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new BlockAlignReductionStream(waveStream))
{
waveOut.Init(baStream);
waveOut.Play();
if (waveOut.PlaybackState != PlaybackState.Stopped)
{
waveEvent.WaitOne(); /* block thread for a while because I don't want async play back
(to be analogical as usage of SoundPlayer Play method) */
}
}
}
}
}
}
}
}
Nevertheless (despite this is quite good for me), I still don't know what's the problem with sample (2).
来源:https://stackoverflow.com/questions/14581349/play-mp3-using-soundplayer-after-conversion-to-wav-using-naudio