我想这样做:
Sistema.Util.MP3Player(@"sound1.mp3");
Sistema.Util.MP3Player(@"sound2.mp3");
namespace Sistema.Util.TextToSpeech
{
public class Player
{
static System.Windows.Media.MediaPlayer mp = new System.Windows.Media.MediaPlayer();
public static void MP3Player(string FileName, bool Async = false)
{
if (Async)
{
//mp.MediaOpened += new EventHandler(mp_MediaOpened);
//mp.MediaEnded += new EventHandler(mp_MediaEnded);
mp.Open(FileName.ToUri());
//mp.SpeedRatio = .2;
mp.Play();
}
else
{
// 03-06-2011
//using (var ms = System.IO.File.OpenRead(FileName)) // "test.mp3"
using (var rdr = new Mp3FileReader(FileName))
using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new BlockAlignReductionStream(wavStream))
using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
//GC.KeepAlive(waveOut);
waveOut.Init(baStream);
waveOut.Play();
//waveOut.PlaybackStopped += new EventHandler(waveOut_PlaybackStopped);
while (waveOut.PlaybackState == PlaybackState.Playing)
{
System.Threading.Thread.Sleep(100);
}
}
}
}
}
}
问题是我有时会尝试,它会抛出一个错误:
检测到CallbackOnCollectedDelegate 消息:在“NAudio!NAudio.Wave.WaveInterop + WaveCallback :: Invoke”类型的垃圾收集委托上进行了回调。这可能会导致应用程序崩溃,损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须将它们保持活动状态,直到确保它们永远不会被调用为止。
更新:我试过这个,但错误仍然发生在3次。你可以尝试阅读这段代码:
void play(string FileName)
{
var mre = new System.Threading.ManualResetEvent(false); // created unsignaled
var callbackInfo = WaveCallbackInfo.FunctionCallback(); //lifetime outside using
using (var rdr = new Mp3FileReader(FileName))
using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new BlockAlignReductionStream(wavStream))
using (var waveOut = new WaveOut(callbackInfo))
{
waveOut.Init(baStream);
waveOut.Play();
waveOut.PlaybackStopped += (sender, e) => { mre.Set(); };
mre.WaitOne();
}
}
play(@"C:\Users\Tony\AppData\Local\Temp\Sistema\Boa_Tarde(exclamacao).mp3");
play(@"C:\Users\Tony\AppData\Local\Temp\Sistema\Bem_vindo(exclamacao).mp3");
play(@"C:\Users\Tony\AppData\Local\Temp\Sistema\Boa_Tarde(exclamacao).mp3");
play(@"C:\Users\Tony\AppData\Local\Temp\Sistema\Bem_vindo(exclamacao).mp3");
答案 0 :(得分:1)
“{1}}委托”拥有“WaveOut
对象,在WaveCallbackInfo.FunctionCallback()
- 块结束时被处理掉并收集垃圾。事实上你的using
循环似乎没有提供对代理使用的保护(听起来像本机代码最终调用它,奇怪的架构)。
您可以使用ManualResetEvent来实现等待:
while
然后在你的方法中
// lifetime as long as your application
static WaveCallbackInfo callbackInfo = WaveCallbackInfo.FunctionCallback();
编辑:本机代码需要某种句柄才能运行。这有效意味着当本机代码仍在运行时句柄永远不会消失。
此代码的当前问题是很难判断何时(如果有的话)您需要创建一个新的回调信息对象。您也可以尝试:
var mre = new ManualResetEvent(false); // created unsignaled
using (var rdr = new Mp3FileReader(FileName))
using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new BlockAlignReductionStream(wavStream))
using (var waveOut = new WaveOut(callbackInfo))
{
waveOut.Init(baStream);
waveOut.Play();
waveOut.PlaybackStopped += (sender,e) => { mre.Set(); };
mre.WaitOne();
}
然后在你的方法中(假设waveOut可以多次初始化):
static WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback());
static ManualResetEvent waveEvent = new ManualResetEvent(false);
static Player()
{
waveOut.PlaybackStopped += (sender, e) => { waveEvent.Set(); };
}
答案 1 :(得分:1)
您看起来像是在使用旧版本的NAudio。从1.4开始,Mp3FileReader从Read方法返回PCM格式的音频,不再需要WaveFormatConversionStream和BlockAlignReductionStream。我建议你升级。
此外,我倾向于建议不要使用函数回调,如果你可以避免它们(即WinForms和WPF),因为我发现不同的音频卡驱动程序在不同的和意外的时间调用它们。如果不向非托管代码提供指向托管函数的函数指针,则生活会轻松许多。使用默认的WaveOut构造函数,让它使用Windowed回调。这是一种更可靠的工作方式。有关详情,请参阅NAudio output devices上的博文。
答案 2 :(得分:0)
目前我正在使用此解决方案:WPF MediaPlayer: How to play in sequence, sync?
答案 3 :(得分:0)
我遇到过这个话题,我实际上也在使用NAudio播放TTS mp3。所以我希望它们同步。经过多次尝试,这是我的解决方案。
var rdr = new Mp3FileReader(sFilePath);
var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr);
var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback());
waveOut.Init(wavStream);
waveOut.Play();
while (wavStream.Position != wavStream.Length)
Thread.Sleep(100);
希望它有所帮助,检查waveOut.PlaybackState == PlaybackState.Playing似乎不起作用,因为它一直保持在播放状态。检查波浪流可以解决这个问题但是如果你在播放完音频之前停止它,那么代码将会永远睡眠,请确保你在那里进行检查。