RePlay 後 回圈內的第二次Play()
waveOut.Init(reader); 這行中斷點 執行後會跳出程式不執行
然後 程式還在運行沒有跳任何錯誤 但是後續的NAudio功能會停住
public void RePlay(int times)
{
Play();
int i = 1;
while (true)
{
if (i >= times) break;
if (waveOut.PlaybackState == PlaybackState.Stopped)
{
//這邊Play() 中斷點設 waveOut.Init(reader); 會錯誤
//Play();
i++;
}
Thread.Sleep(100);
}
}
public void Play()
{
DirectoryInfo directory = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media"));
if (!File.Exists($"{directory}\\{Mp3Name}"))
{
MessageBox.Show("查無檔案,重新擷取媒體庫");
infos = directory.GetFiles("*.mp3");
infoIndex = 0;
dataHolder.Mp3FileName = infos[infoIndex].Name;
return;
}
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
waveOut.Pause();
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
waveOut.Play();
}
else if (waveOut.PlaybackState == PlaybackState.Stopped)
{
waveOut = new WaveOut();
reader = new Mp3FileReader($"{directory}\\{Mp3Name}");
waveOut.Init(reader);
waveOut.Play();
waveOut.PlaybackStopped += WaveOut_PlaybackStopped;
}
Task.Run(() =>
{
while (waveOut.PlaybackState == PlaybackState.Playing)
{
TimeSpan currentTime = reader.CurrentTime;
TimeSpan totalTime = reader.TotalTime;
double progress = (double)currentTime.Ticks / totalTime.Ticks;
int progressBarValue = (int)(progress * 100);
Mp3Progress = progressBarValue;
NotifyOfPropertyChange(() => Mp3Progress);
Thread.Sleep(500);
}
});
}
}
private void WaveOut_PlaybackStopped(object? sender, StoppedEventArgs e)
{
Mp3Progress = 0;
NotifyOfPropertyChange(() => Mp3Progress);
reader.Dispose();
waveOut.Dispose();
}
第二次調用 RePlay() 方法時,waveOut.PlaybackState 的值為 Stopped,因此程式將嘗試執行 waveOut.Init(reader); 這一行,但由於 reader 已在 WaveOut_PlaybackStopped() 方法中被釋放,所以會引發異常。
要解決此問題,每次調用 Play() 方法時創建一個新的 Mp3FileReader 物件。確保在 waveOut 物件上調用 Stop() 時,reader 物件不會被釋放。
public void Play()
{
DirectoryInfo directory = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media"));
if (!File.Exists($"{directory}\\{Mp3Name}"))
{
MessageBox.Show("查無檔案,重新擷取媒體庫");
infos = directory.GetFiles("*.mp3");
infoIndex = 0;
dataHolder.Mp3FileName = infos[infoIndex].Name;
return;
}
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
waveOut.Pause();
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
waveOut.Play();
}
else if (waveOut.PlaybackState == PlaybackState.Stopped)
{
waveOut = new WaveOut();
reader = new Mp3FileReader($"{directory}\\{Mp3Name}");
waveOut.Init(reader);
waveOut.Play();
waveOut.PlaybackStopped += WaveOut_PlaybackStopped;
}
Task.Run(() =>
{
while (waveOut.PlaybackState == PlaybackState.Playing)
{
TimeSpan currentTime = reader.CurrentTime;
TimeSpan totalTime = reader.TotalTime;
double progress = (double)currentTime.Ticks / totalTime.Ticks;
int progressBarValue = (int)(progress * 100);
Mp3Progress = progressBarValue;
NotifyOfPropertyChange(() => Mp3Progress);
Thread.Sleep(500);
}
});
reader.Dispose(); // 釋放上一個 Mp3FileReader 物件的資源
}
}
這個測試後 不行
因為我是用排程去call replay 我在想是不是 執行緒的問題
Quartz.cs
public async Task Execute(IJobExecutionContext context)
{
var dataMap = context.JobDetail.JobDataMap;
string musicName = dataMap.GetString("Music") ?? "";
string LoopTimes = dataMap.GetString("LoopTimes") ?? "0";
await Task.Run(() =>
{
if (!NPDay())
{
_mainVM.Mp3Name = musicName;
_mainVM.Replay(int.Parse(LoopTimes));
}
});
}
改成這種方式用按鈕是可以正常replay 但排程一樣播完第一次就卡死了
public async Task Replay(int times)
{
for (int i = 0; i < times; i++)
{
await Play();
}
}
public async Task Play()
{
.....
await Task.Run(() =>
{
.....
}
}
這樣是同步跟非同步混用 講起來有點複雜 等其他大大回答吧
可能是因為在第二次執行時,已經有一個 waveOut 實例正在運行,但是在初始化 reader 時出現了錯誤。因此,可以嘗試在第二次執行之前關閉 waveOut 和 reader,並重新初始化。修改後的程式碼如下:
public void RePlay(int times)
{
Play();
int i = 1;
while (true)
{
if (i >= times) break;
if (waveOut.PlaybackState == PlaybackState.Stopped)
{
waveOut.Stop(); // 停止播放
reader.Dispose(); // 關閉 reader
waveOut.Dispose(); // 關閉 waveOut
waveOut = new WaveOut(); // 重新初始化 waveOut
reader = new Mp3FileReader(Path.Combine(Media, Mp3Name)); // 重新初始化 reader
waveOut.Init(reader);
waveOut.Play();
waveOut.PlaybackStopped += WaveOut_PlaybackStopped;
i++;
}
Thread.Sleep(100);
}
}
注意在重新初始化 reader 時,應該使用 Path.Combine(Media, Mp3Name) 來取代 ${directory}\{Mp3Name},因為 Mp3Name 已經是相對於 Media 的路徑了。