使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音
Posted
技术标签:
【中文标题】使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音【英文标题】:Playing sound parallelly with System.Media.SoundPlayer.PlaySync() and AxWindowsMediaPlayer 【发布时间】:2013-04-08 10:25:11 【问题描述】:我创建了一个 WinForm 应用程序,其中包含一个 AxWMPLib.AxMediaPlayer,我可以在其中播放一些视频。我还必须在不同的线程中播放一些其他自定义声音。为此,我使用了 System.Media.SoundPlayer.PlaySync()。该线程循环播放几个声音文件。问题是当我暂停/停止视频时,按钮事件的声音播放得很好。但是当视频运行时,有时会跳过一些声音文件。它是随机发生的。 任何人都可以对这个问题以及如何解决它给出一些解释。我的意思是我怎么能同时播放声音和视频。
视频在 UI 线程中播放,其他声音在不同线程中播放。请查看以下代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using ElectroQ;
using ElectroQServer1.Entities;
using WMPLib;
using System.Media;
using System.Windows.Media;
namespace ElectroQServer1
public partial class Form1 : Form
Thread dbListenerThread;
IWMPPlaylist playlist;
//string[] tokenNumber = "A001", "B002", "C003", "D004","E005", "F006", "G007","HAMB" ;
//string[] counterNumber = "01", "02", "03", "04", "05", "06", "07", "MB" ;
public Form1()
InitializeComponent();
//ResizeRedraw = true;
this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer, true);
this.WindowState = FormWindowState.Maximized;
//this.FormBorderStyle = FormBorderStyle.None;
//this.TopMost = true;
dbListenerThread = new Thread(RefreshQueueBoard);
dbListenerThread.Start();
/// <summary>
/// This method is used to prevent the flickering of the window.
/// </summary>
protected override CreateParams CreateParams
get
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
public void RefreshQueueBoard()
//Thread.Sleep(000);
while (true)
List<QueueData> lstQData = DA.GetAllQueueData(" where service_status_id = 2 ");
printToken(lstQData);
printCounter(lstQData);
playSound(lstQData);
Thread.Sleep(1000);
public void playSound(List<QueueData> lstQData)
foreach (QueueData qData in lstQData)
if (!qData.SoundPlayed)
string strSoundFile;
PlaySoundFIle(@"Sounds/TN.WAV");
foreach (char c in qData.ServiceQueueSerial)
strSoundFile = string.Format(@"Sounds/0.WAV", c);
PlaySoundFIle(strSoundFile);
PlaySoundFIle(@"Sounds/CN.WAV");
foreach (char c in qData.ServiceCounterID)
strSoundFile = string.Format(@"Sounds/0.WAV", c);
PlaySoundFIle(strSoundFile);
string strUpdateQuery = string.Format("UPDATE electro_queue SET sound_played = 1 WHERE service_queue_serial = '0'", qData.ServiceQueueSerial);
DA.UpdateQueueData(strUpdateQuery);
public void PlaySoundFIle(string strFile)
//string[] files = new string[4] @"Sounds/TN.WAV", @"Sounds/CN.WAV", @"Sounds/TN.WAV", @"Sounds/CN.WAV";
//WaveIO wa = new WaveIO();
//wa.Merge(files, @"tempfile.wav");
//MediaPlayer wowSound = new MediaPlayer(); //Initialize a new instance of MediaPlayer of name wowSound
//wowSound.Open(new Uri(@"tempfile.wav", UriKind.Relative)); //Open the file for a media playback
//wowSound.Play();
using (var soundPlayer = new SoundPlayer(strFile))
soundPlayer.PlaySync(); // can also use soundPlayer.Play() but it misses some sound file.
private void printToken(List<QueueData> lstQData)
if (InvokeRequired)
this.Invoke(new MethodInvoker(delegate
pnlQStat.Controls.Clear();
string dir;
//int xpos = 55;
//int ypos = 207;
int xpos = 10;
int ypos = 00;
//int k=0;
for (int i = 0; i < lstQData.Count; i++)
/* if (i == 4 || i == 8)
ypos = ypos - 360;
xpos = 675;
*/
foreach (char c in lstQData[i].ServiceQueueSerial)
if (i == 0)
dir = "Resources/_" + c + ".bmp";
else
dir = "Resources/" + c + ".bmp";
createPicBox(dir, "pBox" + i, xpos, ypos);
xpos = xpos + 43;
ypos = ypos + 50;
xpos = 10;
));
return;
private void printCounter(List<QueueData> lstQData)
if (InvokeRequired)
this.Invoke(new MethodInvoker(delegate
//int xpos = 415;
//int ypos = 207;
//int xpos = 292;
int xpos = 220;
int ypos = 00;
//int k=0;
for (int i = 0; i < lstQData.Count; i++)
/*if (i == 4 || i == 8)
ypos = ypos - 360;
xpos = 1035;
*/
foreach (char c in lstQData[i].ServiceCounterID)
string dir;
if (i == 0)
dir = "Resources/_" + c + ".bmp";
else
dir = "Resources/" + c + ".bmp";
//string dir = "Resources/" + c + ".bmp";
createPicBox(dir, "pBox" + i, xpos, ypos);
xpos = xpos + 63;
ypos = ypos + 50;
xpos = xpos - 63;
));
return;
private void createPicBox(string directory, string name, int xposition, int yposition)
PictureBox picBox = new System.Windows.Forms.PictureBox();
picBox.Name = name;
picBox.Location = new System.Drawing.Point(xposition, yposition);
picBox.Size = new System.Drawing.Size(40, 50);
picBox.BackgroundImage = Image.FromFile(directory);
picBox.BackgroundImageLayout = ImageLayout.Stretch;
pnlQStat.Controls.Add(picBox);
private void Form1_Load(object sender, EventArgs e)
createPlayList();
//dbListenerThread.Abort(); // this line of code should be placed in onClosing Event.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
dbListenerThread.Abort();
player.playlistCollection.remove(playlist);
private void createPlayList()
playlist = player.playlistCollection.newPlaylist("mpl");
playlist.appendItem(player.newMedia(@"E:\SONGS\teri-meri-promo-Muskurahat.Com.wmv"));
playlist.appendItem(player.newMedia(@"E:\MOVZZZ\English\The Kid\THE KID FILM_1_0001.avi"));
player.currentPlaylist = playlist;
private void btnPlay_Click(object sender, EventArgs e)
// player.URL = @"E:\MOVZZZ\English\The Kid\THE KID FILM_1_0001.avi";
player.Ctlcontrols.play();
private void btnStop_Click(object sender, EventArgs e)
player.Ctlcontrols.stop();
我的目标是顺序播放循环播放的声音文件,同时并行播放视频。
【问题讨论】:
您的 playSound() 方法可以正常工作的唯一方法是在单独的线程上运行。在这种情况下 btnPlay_Click 缺少代码,它不能确保该线程与视频同步。如果 playSound 实际上是在 UI 线程上运行,那么您会遇到各种麻烦,包括 UI 冻结和无响应,进而影响视频播放器。 SoundPlayer 过于原始,无法正确检测到声音是否播放完毕。周围的大量音频库可以做得更好。 @HansPassant 感谢线程的想法。我正在检查它.. 并让你知道它是否有效。你应该回答这个问题。 @HansPassant 您好,我将声音播放分开在不同的线程中。但这并不能解决问题。我仍然缺少声音。我编辑了问题并添加了新代码,请查看。 【参考方案1】:您不应为此使用SoundPlayer
; SoundPlayer
是一个轻量级、方便的类,用于在应用程序中播放偶尔的附带声音。如果音频子系统中发生其他事情(如视频播放),它偶尔会跳过声音。这里是a good sample that shows how to use the low-level waveOutOpen API for playing sounds。
【讨论】:
感谢您的回答。我正在检查它。如果它有效.. 我让你知道。 我已经从您提供的代码项目链接中下载了源代码。当我运行它并尝试播放 wav 文件时,程序崩溃了。 运行程序后,我单击打开按钮并选择一个 wav 文件。然后我按下播放按钮然后它崩溃了。它在函数 WaveOutPlayer 的第三行崩溃。错误是对象引用未设置为对象的实例。 第三行是什么?我现在在 macbook 上,所以我不能自己运行它。您选择的 WAV 文件可能有问题。 第三行是 WaveOutHelper.Try(WaveNative.waveOutOpen(out m_WaveOut, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));我尝试了几个 wav 文件,但它导致相同的错误以上是关于使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)