下面这个类是用Microsoft.DirectX和Microsoft.DirectSound来实现音频采集的,但采集出来之后的音频质量超烂,嚣叫声很厉害,总有翁翁声的,听得人都想发疯。有哪位前辈做过DirectX下的高质量音频采集,来指点小弟一下,谢谢!顶者有分!! public class clsDirectSound
{
#region //类成员变量定义 private MemoryStream memstream;//内存流
private SecondaryBuffer secBuffer;//辅助缓冲区
private int iNotifySize = 0;//通知大小
private int iBufferSize = 0;//捕捉缓冲区大小
private CaptureBuffer capturebuffer;//捕捉缓冲区对象
private AutoResetEvent notifyEvent;//通知事件
private Thread notifyThread;//通知线程
private int iNotifyNum = 0;//通知个数
private Notify myNotify;//通知对象
private Capture capture;//捕捉设备对象
private Device PlayDev;//播放设备对象
private BufferDescription buffDiscript;
private Socket Client;
private EndPoint epServer;
private int iBufferOffset = 0;//捕捉缓冲区位移
private IntPtr intptr;//窗口句柄
#endregion #region //类成员函数定义 #region //创建采集及播放设备
/// <summary>
/// 创建捕捉设备对象
/// </summary>
/// <returns>如果创建成功返回true</returns>
private bool CreateCaputerDevice()
{
//首先要玫举可用的捕捉设备
CaptureDevicesCollection capturedev = new CaptureDevicesCollection();
Guid devguid;
if (capturedev.Count > 0)
{
devguid = capturedev[1].DriverGuid;
}
else
{
System.Windows.Forms.MessageBox.Show("当前没有可用于音频捕捉的设备", "系统提示");
return false;
}
//利用设备GUID来建立一个捕捉设备对象
this.capture = new Capture(devguid);
return true;
} /// <summary>
/// 创建用于播放的音频设备对象
/// </summary>
/// <returns>创建成功返回true</returns>
private bool CreatePlayDevice()
{
DevicesCollection dc = new DevicesCollection();
Guid g;
if (dc.Count > 0)
{
g = dc[1].DriverGuid;
}
else
{ return false; } this.PlayDev = new Device(g); //播放设备
PlayDev.SetCooperativeLevel(intptr, CooperativeLevel.Normal);
return true;
}
#endregion #region//创建采集及播放缓冲区 /// <summary>
/// 创建捕捉缓冲
/// </summary>
private void CreateCaptureBuffer()
{
//想要创建一个捕捉缓冲区必须要两个参数:缓冲区信息(描述这个缓冲区中的格式等),缓冲设备。
WaveFormat mWavFormat = SetWaveFormat();
CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
bufferdescription.Format = mWavFormat;//设置缓冲区要捕捉的数据格式
iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//1秒的数据量/设置的通知数得到的每个通知大小小于0.2s的数据量,话音延迟小于200ms为优质话音
iBufferSize = iNotifyNum * iNotifySize;
bufferdescription.BufferBytes = iBufferSize;
bufferdescription.ControlEffects = true;
bufferdescription.WaveMapped = true; this.capturebuffer= new CaptureBuffer(bufferdescription, capture);//建立设备缓冲区对象 } /// <summary>
/// 创建播放缓冲
/// </summary>
private void CreateSecondaryBuffer()
{
buffDiscript = new BufferDescription();
WaveFormat mWavFormat = SetWaveFormat();
buffDiscript.Format = mWavFormat;
iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//设置通知大小
iBufferSize = iNotifyNum * iNotifySize;
buffDiscript.BufferBytes = iBufferSize;
buffDiscript.ControlPan = true;
buffDiscript.ControlFrequency = true;
buffDiscript.ControlVolume = true;
buffDiscript.GlobalFocus = true;
secBuffer = new SecondaryBuffer(buffDiscript, PlayDev);
byte[] bytMemory = new byte[100000];
this.memstream= new MemoryStream(bytMemory, 0, 100000, true, true);
//g729 = new G729();
//g729.InitalizeEncode();
//g729.InitalizeDecode();
} #endregion #region //设置通知对像
//设置通知
private void CreateNotification()
{
BufferPositionNotify[] bpn = new BufferPositionNotify[iNotifyNum];//设置缓冲区通知个数
//设置通知事件
notifyEvent = new AutoResetEvent(false);
notifyThread = new Thread(RecoData);//通知触发事件
notifyThread.IsBackground = true;
notifyThread.Start();
for (int i = 0; i < iNotifyNum; i++)
{
bpn[i].Offset = iNotifySize + i * iNotifySize - 1;//设置具体每个的位置
bpn[i].EventNotifyHandle = notifyEvent.Handle;
}
this.myNotify = new Notify(capturebuffer);
myNotify.SetNotificationPositions(bpn); }
//线程中的事件
private void RecoData()
{
while (true)
{
// 等待缓冲区的通知消息
notifyEvent.WaitOne(Timeout.Infinite, true);
// 录制数据
RecordCapturedData();
}
} //真正转移数据的事件,其实就是把数据传送到网络上去。
private void RecordCapturedData()
{
byte[] capturedata = null;
int readpos = 0, capturepos = 0, locksize = 0;
capturebuffer.GetCurrentPosition(out capturepos, out readpos);
locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小
if (locksize == 0)
{
return;
}
if (locksize < 0)
{//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处
locksize += iBufferSize;
}
capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.None, locksize);
try
{
if (this.audioCaptured != null) //调用事件订阅者处理程序
{
//事件订阅者主要是先对capturedata进行g729编码,
//再通过udp发到网络上去
this.audioCaptured(capturedata);
}
}
catch(Exception ex)
{
clsErrorLog.ErrorLog(Application.StartupPath, ex.ToString());
clsErrorLog.ErrorLog(Application.StartupPath, "调用上层程序处理采集到的音频数据失败");
}
iBufferOffset += capturedata.Length;
iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
} #endregion
/// <summary>
/// 启动采集
/// </summary>
public void StartVoiceCapture()
{
this.capturebuffer.Start(true);//true表示设置缓冲区为循环方式,开始捕捉
}
/// <summary>
/// 初始化相关操作
/// </summary>
public void InitVoice()
{//初始化声音相关设置:(1)捕捉缓冲区(2)播放缓冲区
if (!CreateCaputerDevice())
{
//clsErrorLog.ErrorLog(Application.StartupPath, "创建捕捉设备失败");
clsErrorLog.ErrorLog(Application.StartupPath, "创建捕捉设备失败");
throw new Exception();
}//建立设备对象
CreateCaptureBuffer();//创建捕捉缓冲 CreateNotification();//设置通知及事件
//======(2)==============
if (!CreatePlayDevice())
{
clsErrorLog.ErrorLog(Application.StartupPath, "创建播放设备失败");
throw new Exception();
}
CreateSecondaryBuffer(); //创建播放缓冲
}
#endregion }
}
{
#region //类成员变量定义 private MemoryStream memstream;//内存流
private SecondaryBuffer secBuffer;//辅助缓冲区
private int iNotifySize = 0;//通知大小
private int iBufferSize = 0;//捕捉缓冲区大小
private CaptureBuffer capturebuffer;//捕捉缓冲区对象
private AutoResetEvent notifyEvent;//通知事件
private Thread notifyThread;//通知线程
private int iNotifyNum = 0;//通知个数
private Notify myNotify;//通知对象
private Capture capture;//捕捉设备对象
private Device PlayDev;//播放设备对象
private BufferDescription buffDiscript;
private Socket Client;
private EndPoint epServer;
private int iBufferOffset = 0;//捕捉缓冲区位移
private IntPtr intptr;//窗口句柄
#endregion #region //类成员函数定义 #region //创建采集及播放设备
/// <summary>
/// 创建捕捉设备对象
/// </summary>
/// <returns>如果创建成功返回true</returns>
private bool CreateCaputerDevice()
{
//首先要玫举可用的捕捉设备
CaptureDevicesCollection capturedev = new CaptureDevicesCollection();
Guid devguid;
if (capturedev.Count > 0)
{
devguid = capturedev[1].DriverGuid;
}
else
{
System.Windows.Forms.MessageBox.Show("当前没有可用于音频捕捉的设备", "系统提示");
return false;
}
//利用设备GUID来建立一个捕捉设备对象
this.capture = new Capture(devguid);
return true;
} /// <summary>
/// 创建用于播放的音频设备对象
/// </summary>
/// <returns>创建成功返回true</returns>
private bool CreatePlayDevice()
{
DevicesCollection dc = new DevicesCollection();
Guid g;
if (dc.Count > 0)
{
g = dc[1].DriverGuid;
}
else
{ return false; } this.PlayDev = new Device(g); //播放设备
PlayDev.SetCooperativeLevel(intptr, CooperativeLevel.Normal);
return true;
}
#endregion #region//创建采集及播放缓冲区 /// <summary>
/// 创建捕捉缓冲
/// </summary>
private void CreateCaptureBuffer()
{
//想要创建一个捕捉缓冲区必须要两个参数:缓冲区信息(描述这个缓冲区中的格式等),缓冲设备。
WaveFormat mWavFormat = SetWaveFormat();
CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
bufferdescription.Format = mWavFormat;//设置缓冲区要捕捉的数据格式
iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//1秒的数据量/设置的通知数得到的每个通知大小小于0.2s的数据量,话音延迟小于200ms为优质话音
iBufferSize = iNotifyNum * iNotifySize;
bufferdescription.BufferBytes = iBufferSize;
bufferdescription.ControlEffects = true;
bufferdescription.WaveMapped = true; this.capturebuffer= new CaptureBuffer(bufferdescription, capture);//建立设备缓冲区对象 } /// <summary>
/// 创建播放缓冲
/// </summary>
private void CreateSecondaryBuffer()
{
buffDiscript = new BufferDescription();
WaveFormat mWavFormat = SetWaveFormat();
buffDiscript.Format = mWavFormat;
iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//设置通知大小
iBufferSize = iNotifyNum * iNotifySize;
buffDiscript.BufferBytes = iBufferSize;
buffDiscript.ControlPan = true;
buffDiscript.ControlFrequency = true;
buffDiscript.ControlVolume = true;
buffDiscript.GlobalFocus = true;
secBuffer = new SecondaryBuffer(buffDiscript, PlayDev);
byte[] bytMemory = new byte[100000];
this.memstream= new MemoryStream(bytMemory, 0, 100000, true, true);
//g729 = new G729();
//g729.InitalizeEncode();
//g729.InitalizeDecode();
} #endregion #region //设置通知对像
//设置通知
private void CreateNotification()
{
BufferPositionNotify[] bpn = new BufferPositionNotify[iNotifyNum];//设置缓冲区通知个数
//设置通知事件
notifyEvent = new AutoResetEvent(false);
notifyThread = new Thread(RecoData);//通知触发事件
notifyThread.IsBackground = true;
notifyThread.Start();
for (int i = 0; i < iNotifyNum; i++)
{
bpn[i].Offset = iNotifySize + i * iNotifySize - 1;//设置具体每个的位置
bpn[i].EventNotifyHandle = notifyEvent.Handle;
}
this.myNotify = new Notify(capturebuffer);
myNotify.SetNotificationPositions(bpn); }
//线程中的事件
private void RecoData()
{
while (true)
{
// 等待缓冲区的通知消息
notifyEvent.WaitOne(Timeout.Infinite, true);
// 录制数据
RecordCapturedData();
}
} //真正转移数据的事件,其实就是把数据传送到网络上去。
private void RecordCapturedData()
{
byte[] capturedata = null;
int readpos = 0, capturepos = 0, locksize = 0;
capturebuffer.GetCurrentPosition(out capturepos, out readpos);
locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小
if (locksize == 0)
{
return;
}
if (locksize < 0)
{//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处
locksize += iBufferSize;
}
capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.None, locksize);
try
{
if (this.audioCaptured != null) //调用事件订阅者处理程序
{
//事件订阅者主要是先对capturedata进行g729编码,
//再通过udp发到网络上去
this.audioCaptured(capturedata);
}
}
catch(Exception ex)
{
clsErrorLog.ErrorLog(Application.StartupPath, ex.ToString());
clsErrorLog.ErrorLog(Application.StartupPath, "调用上层程序处理采集到的音频数据失败");
}
iBufferOffset += capturedata.Length;
iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
} #endregion
/// <summary>
/// 启动采集
/// </summary>
public void StartVoiceCapture()
{
this.capturebuffer.Start(true);//true表示设置缓冲区为循环方式,开始捕捉
}
/// <summary>
/// 初始化相关操作
/// </summary>
public void InitVoice()
{//初始化声音相关设置:(1)捕捉缓冲区(2)播放缓冲区
if (!CreateCaputerDevice())
{
//clsErrorLog.ErrorLog(Application.StartupPath, "创建捕捉设备失败");
clsErrorLog.ErrorLog(Application.StartupPath, "创建捕捉设备失败");
throw new Exception();
}//建立设备对象
CreateCaptureBuffer();//创建捕捉缓冲 CreateNotification();//设置通知及事件
//======(2)==============
if (!CreatePlayDevice())
{
clsErrorLog.ErrorLog(Application.StartupPath, "创建播放设备失败");
throw new Exception();
}
CreateSecondaryBuffer(); //创建播放缓冲
}
#endregion }
}
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货