C#中是否有一种方法可以直接从System.IO.Stream播放音频(例如MP3),例如从WebRequest返回而不将数据暂时保存到磁盘?
在NAudio 1.3的帮助下,可以:
能够播放半载MP3文件本来不错,但由于NAudio库设计,这似乎是不可能的。
这是完成工作的功能:
public static void PlayMp3FromUrl(string url)
{
using (Stream ms = new MemoryStream())
{
using (Stream stream = WebRequest.Create(url)
.GetResponse().GetResponseStream())
{
byte[] buffer = new byte[32768];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
ms.Position = 0;
using (WaveStream blockAlignedStream =
new BlockAlignReductionStream(
WaveFormatConversionStream.CreatePcmStream(
new Mp3FileReader(ms))))
{
using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
waveOut.Init(blockAlignedStream);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing )
{
System.Threading.Thread.Sleep(100);
}
}
}
}
}
答案 0 :(得分:48)
编辑:答案已更新,以反映近期版本的NAudio
的变化可以使用我编写的NAudio开源.NET音频库。它会在您的PC上查找ACM编解码器以进行转换。 NAudio提供的Mp3FileReader目前希望能够在源流中重新定位(它预先构建MP3帧的索引),因此不适合通过网络进行流式传输。但是,您仍然可以使用NAudio中的MP3Frame
和AcmMp3FrameDecompressor
类来动态解压缩流式MP3。
我在我的博客上发布了一篇文章,解释how to play back an MP3 stream using NAudio。基本上你有一个线程下载MP3帧,解压缩并存储在BufferedWaveProvider
。然后另一个线程使用BufferedWaveProvider
作为输入进行回放。
答案 1 :(得分:8)
SoundPlayer类可以做到这一点。看起来你要做的就是将 Stream 属性设置为流,然后调用Play
。
修改
我不认为它可以播放MP3文件;它似乎仅限于.wav。我不确定框架中是否有任何东西可以直接播放MP3文件。我发现的所有内容都涉及使用WMP控件或与DirectX交互。
答案 2 :(得分:5)
Bass可以做到这一点。从内存中的Byte []或在您返回数据的直通文件代理中播放,这样您就可以在有足够数据开始播放时立即播放..
答案 3 :(得分:3)
我稍微修改了主题入门源,因此它现在可以播放未完全加载的文件。这是(注意,它只是一个示例,是一个从头开始的点;你需要在这里做一些异常和错误处理):
private Stream ms = new MemoryStream();
public void PlayMp3FromUrl(string url)
{
new Thread(delegate(object o)
{
var response = WebRequest.Create(url).GetResponse();
using (var stream = response.GetResponseStream())
{
byte[] buffer = new byte[65536]; // 64KB chunks
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var pos = ms.Position;
ms.Position = ms.Length;
ms.Write(buffer, 0, read);
ms.Position = pos;
}
}
}).Start();
// Pre-buffering some data to allow NAudio to start playing
while (ms.Length < 65536*10)
Thread.Sleep(1000);
ms.Position = 0;
using (WaveStream blockAlignedStream = new BlockAlignReductionStream(WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(ms))))
{
using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
waveOut.Init(blockAlignedStream);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
{
System.Threading.Thread.Sleep(100);
}
}
}
}
答案 4 :(得分:1)
NAudio包装了WaveOutXXXX API。我没有查看源代码,但是如果NAudio以不会在每次调用时自动停止播放的方式暴露waveOutWrite()函数,那么你应该能够做你真正想要的,即开始播放收到所有数据之前的音频流。
使用waveOutWrite()函数可以“预读”并将较小的音频块转储到输出队列中--Windows将自动无缝地播放块。您的代码必须采用压缩音频流并将其转换为小块WAV音频;这部分真的很难 - 我见过的所有库和组件都是MP3-to-WAV一次转换整个文件。可能你唯一现实的机会是用WMA而不是MP3来做这件事,因为你可以在多媒体SDK上编写简单的C#包装。
答案 5 :(得分:1)
我将MP3解码器库包装起来,并以.NET的形式提供给mpg123.net开发人员。
答案 6 :(得分:1)
我已经调整了问题中发布的来源,允许使用Google的TTS API来回答问题here:
bool waiting = false;
AutoResetEvent stop = new AutoResetEvent(false);
public void PlayMp3FromUrl(string url, int timeout)
{
using (Stream ms = new MemoryStream())
{
using (Stream stream = WebRequest.Create(url)
.GetResponse().GetResponseStream())
{
byte[] buffer = new byte[32768];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
ms.Position = 0;
using (WaveStream blockAlignedStream =
new BlockAlignReductionStream(
WaveFormatConversionStream.CreatePcmStream(
new Mp3FileReader(ms))))
{
using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
waveOut.Init(blockAlignedStream);
waveOut.PlaybackStopped += (sender, e) =>
{
waveOut.Stop();
};
waveOut.Play();
waiting = true;
stop.WaitOne(timeout);
waiting = false;
}
}
}
}
调用:
var playThread = new Thread(timeout => PlayMp3FromUrl("http://translate.google.com/translate_tts?q=" + HttpUtility.UrlEncode(relatedLabel.Text), (int)timeout));
playThread.IsBackground = true;
playThread.Start(10000);
终止于:
if (waiting)
stop.Set();
请注意,我在上面的代码中使用ParameterizedThreadDelegate
,并且线程以playThread.Start(10000);
启动。 10000表示最多播放10秒的音频,因此如果您的流需要比播放的时间更长,则需要调整它。这是必要的,因为当前版本的NAudio(v1.5.4.0)似乎在确定流何时完成播放时存在问题。它可以在以后的版本中修复,或者可能有一个我没有花时间查找的解决方法。
答案 7 :(得分:0)
我没有尝试过WebRequest,但Windows Media Player ActiveX和MediaElement(来自WPF)组件都能够播放和缓存MP3流。
我用它来播放来自SHOUTcast流的数据,效果很好。但是,我不确定它是否适用于您提出的方案。
答案 8 :(得分:0)
我一直把FMOD用于这样的事情,因为它可以免费用于非商业用途并且效果很好。
那就是说,我很乐意转向更小(FMOD约为300k)和开源的东西。超级奖励积分,如果它是完全管理,以便我可以编译/合并我的.exe而不必格外小心,以获得其他平台的可移植性......
(FMOD也具有可移植性,但你显然需要不同平台的不同二进制文件)