在播放时从不同的线程停止 SoundPlayer
Posted
技术标签:
【中文标题】在播放时从不同的线程停止 SoundPlayer【英文标题】:Stopping SoundPlayer from a different thread while it's playing 【发布时间】:2019-10-22 08:25:48 【问题描述】:为了制作(随机播放的)播放列表,我制作了一个单独的线程,在其中加载和播放播放列表中的每首歌曲。背景内容(wav 文件、文件路径、播放列表和随机播放)都可以顺利运行。
问题是我有 2 个窗口,每个窗口都可以关闭和打开另一个。每个窗口都有不同的播放列表,当我切换到另一个窗口时,我希望我的静态 SoundPlayer 停止播放,然后开始播放新的播放列表。
这目前不起作用:目前,应用程序会等到当前曲目播放完毕,然后再显示下一个窗口并启动另一个播放列表。是的,整个应用程序都在等待这个。
我是线程编码的新手,所以我不确定该怎么做。到目前为止,我尝试过的两种停止方法是 SoundPlayer.Stop() 和 Thread.Abort()。两者都没有改变现状。
在每个窗口中:
Thread playlistThread;
public Window()
InitializeComponent();
MusicPlayer.music.Stop();
playlistThread = new Thread(() => MusicPlayer.PlayPlaylist(MusicPlayer.ShufflePlaylist(MusicPlayer.PlaylistFromType("[insert track type]"), random)));
playlistThread.Start();
接下来我将展示的 PlayPlaylist 需要一个字符串列表,所以不要担心 Thread 行,它只是将几个部分合二为一。之后的属性只是生成该列表,并且再次,一切正常,但如果有人认为有必要,我可以展示它。这是 PlayPlaylist 方法:
public static void PlayPlaylist(List<string> tracks)
for (int i = 0; i < tracks.Count; i++)
music.SoundLocation = tracks[i];
music.PlaySync();
【问题讨论】:
仅供参考,这不适用于许多 Windows 10 计算机,因为声音播放器需要安装媒体播放器。 我很确定它没有 - MediaPlayer 是另一个使用 WMP 的类,但我认为 SoundPlayer 没有 我很确定它确实如此,因为我安装了 Windows 10 R 并且我无法使用该类。我什至不能使用它的 Mono 版本。 如果您使用的是旧版本的 VS,您可能需要手动添加 dll:它显然来自 PresentationCore.dll,但没有任何迹象表明它仅存在于某些 Windows 机器上。所有 Windows PC 都使用 .Net,所以这应该不是问题。 我用的是2017企业版和2019社区版。是的,所有电脑都使用网络,但有些系统在出售时根本没有内置媒体功能。在没有安装媒体扩展包的情况下,我什至有所谓的第 3 方媒体播放器无法运行,我可以向您保证,该库是媒体播放器 dll 的包装器。我不得不重写一些我自己的软件才能不使用它。我的观点是:由于欧盟的裁决,您不能再依赖内置的媒体功能在系统上。 support.microsoft.com/en-us/help/4475817/… 【参考方案1】:这是我得出的答案:
public static void PlayTrack(List<string> tracks, int i)
while (true)
if (i == tracks.Count)
tracks = MusicPlayer.ShufflePlaylist(tracks, MusicPlayer.random);
i = 0;
music.SoundLocation = tracks[i];
int l = SoundInfo.GetSoundLength(tracks[i]);
music.Play();
while (l > 0)
Thread.Sleep(1000);
l -= 1000;
i++;
我找到了带有 GetSoundLength 方法的 SoundInfo 类here。 此方法有效而其他方法无效的原因是 Play() 和 PlaySync() 的工作方式。 PlaySync() 在当前线程中播放整个 .wav 文件,在完成之前不运行任何其他文件。因此,即使 SoundPlayer.Stop() 和 Thread.Abort() 也不起作用,因为它们会在当前行之后插入新行。
通过在新线程中运行此方法,您可以避免 PlaySync() 给您带来该问题。但是,使用 PlaySync() 提前停止轨道仍然是不可能的。这就是你使用 Play() 的原因。
然而,其中存在第二个问题:Play() 在自己的线程中播放曲目,这意味着其余代码将继续。如果您只想在当前曲目结束后做任何事情,这是一个很大的风险。
答案是计算您要播放的曲目的长度。然后简单地创建一个 while 循环,一直运行直到 l(由 GetSoundLength() 给出)达到 0。在每次通过循环时,线程(与窗口的主线程分开)休眠 1 秒。这在 CPU 上很好,意味着每隔一秒就有额外的代码,例如 SoundPlayer.Stop(),可以注入到线程中。
【讨论】:
以上是关于在播放时从不同的线程停止 SoundPlayer的主要内容,如果未能解决你的问题,请参考以下文章
C# Windows 窗体中的 WMP 在显示 GIF 后停止播放声音
SoundPlayer 不播放任何捆绑的 Windows 声音 PCM wav 文件
使用 System.Media.SoundPlayer 播放 Windows 系统声音
使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音