我正在使用 NAudio 库实时流式传输 mp3。我已经准备了一个代码来做到这一点,它通常运行良好,除非另一个媒体正在另一个进程中播放(例如 Youtube、本地 mp3 播放器..),. 那个时候,mp3是口吃的。我不知道为什么会这样。如何解决这个问题呢?
在控制台应用程序中流式传输的代码。复制粘贴,你可以试试。
static void Main(string[] args)
{
AcmMp3FrameDecompressor decompressor = null;
BufferedWaveProvider provider = null;
WaveFormat mp3format = null;
WaveOut waveOut = new WaveOut();
long size = 0;
byte[] decbuffer = new byte[50 * 1024];
//I am using mp3 links converted by listentoyoutube.com
//But links will be expired, so I didnt put any
string url = "";
string path = Path.Combine(Path.GetTempPath(), "test.mp3");
CheckUrlandCreateTools(url, ref decompressor, ref mp3format, ref size);
FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite);
HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
Stream remote = resp.GetResponseStream();
Mp3Frame frame = null;
MemoryStream ms = null;
byte[] buffer = new byte[1024];
int read = 0;
long offset = 0;
provider = new BufferedWaveProvider(decompressor.OutputFormat);
provider.BufferDuration = TimeSpan.FromSeconds(20);
waveOut.Init(provider);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
{
if((read = remote.Read(buffer, 0, buffer.Length)) > 0)
fs.Write(buffer, 0, read);
fs.Flush();
ms = new MemoryStream(ReadStreamPartially(fs, offset, 100 * 1024));
try
{
frame = Mp3Frame.LoadFromStream(ms);
if (frame == null)
continue;
}
catch
{
continue;
}
offset += ms.Position;
int decompressed = decompressor.DecompressFrame(frame, decbuffer, 0);
provider.AddSamples(decbuffer, 0, decompressed);
if (IsBufferNearlyFull(provider))
Thread.Sleep(500);
}
}
public static byte[] ReadStreamPartially(System.IO.FileStream stream,
long offset, long count)
{
long originalPosition = stream.Position;
stream.Position = offset;
byte[] readBuffer = new byte[4096];
byte[] total = new byte[count];
int totalBytesRead = 0;
int byteRead;
while ((byteRead = stream.ReadByte()) != -1)
{
Buffer.SetByte(total, totalBytesRead, (byte)byteRead);
totalBytesRead++;
if (totalBytesRead == count)
break;
}
if (totalBytesRead < count)
{
byte[] temp = new byte[totalBytesRead];
Buffer.BlockCopy(total, 0, temp, 0, totalBytesRead);
stream.Position = originalPosition;
return temp;
}
stream.Position = originalPosition;
return total;
}
public static bool IsBufferNearlyFull(BufferedWaveProvider bufferedWaveProvider)
{
return bufferedWaveProvider != null &&
bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes
< bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4;
}
public static void CheckUrlandCreateTools(string url, ref AcmMp3FrameDecompressor decompressor,
ref WaveFormat format, ref long size)
{
HttpWebRequest req = SendRequest(url, 0, 0);
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
size = resp.ContentLength;
Stream str = resp.GetResponseStream();
byte[] buffer = new byte[1024];
byte[] storer = new byte[1024 * 100];
int bytesRead = 0;
int total = 0;
while ((bytesRead = str.Read(buffer, 0, buffer.Length)) > 0)
{
Buffer.BlockCopy(buffer, 0, storer, total, bytesRead);
total += bytesRead;
Mp3Frame frame = Mp3Frame.LoadFromStream(new MemoryStream(storer));
if (frame == null) continue;
format = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2,
frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(format);
req.Abort();
resp.Close();
str.Close();
break;
}
}
public static HttpWebRequest SendRequest(string url, long from, long to)
{
HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
req.Credentials = CredentialCache.DefaultCredentials;
req.Accept = "*/*";
req.KeepAlive = false;
req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
req.AllowAutoRedirect = true;
if (to > 0)
req.AddRange(from, to);
return req;
}
}