2023年7月29日发(作者:)
语音采集
由于所实现的方法与录音方法一致,因此不会着墨过多,如果你不能很好的理解,请先参考:C# 中利用 DirectSound 录音
与录音不同的是,录音我们需要建立一个WAVE文件来存储这些采集到的数据,而在语音聊天中,则不需要存储,当采集到一些数据后,就立刻发送出去,因此也不需要开辟很大的空间来存放PCM数据。
我们先来回顾下采集的基本步骤:
1. 设置PCM格式,设置相关的参数,如:采样频率、量化位数等。
2. 建立采集用的设备对象,建立采集用的缓冲区对象。
3. 设置缓冲区通知,设置通知被触发后的事件。通知是用于当缓冲区的读指针达到某预设位置时触发通知事件,提醒我们可以对某部分的数据进行传送了。
4. 开始采集声音。
5. 当通知被触发后,建立一个新的线程来处理数据传送的事件。(建立一个新的线程,就是为了防止采集过程被中断)。
///
/// 设置音频格式,如采样率等
///
///
private WaveFormat SetWaveFormat()
{
WaveFormat format = new WaveFormat();
Tag = ;//设置音频类型
sPerSecond = 11025;//采样率(单位:赫兹)典型值:11025、22050、44100Hz
rSample = 16;//采样位数
ls = 1;//声道
lign = (short)(ls * (rSample / 8));//单位采样点的字节数
eBytesPerSecond = lign * sPerSecond;
return format;
//按照以上采样规格,可知采样1秒钟的字节数为22050*2=44100B 约为 43K
}
///
/// 创建捕捉设备对象
///
///
private bool CreateCaputerDevice()
{ //首先要玫举可用的捕捉设备
CaptureDevicesCollection capturedev = new CaptureDevicesCollection();
Guid devguid;
if ( > 0)
{
devguid = capturedev[0].DriverGuid;
}
else
{
("当前没有可用于音频捕捉的设备", "系统提示");
return false;
}
//利用设备GUID来建立一个捕捉设备对象
capture = new Capture(devguid);
return true;
}
///
/// 创建捕捉缓冲区对象
///
private void CreateCaptureBuffer()
{
//想要创建一个捕捉缓冲区必须要两个参数:缓冲区信息(描述这个缓冲区中的格式等),缓冲设备。
WaveFormat mWavFormat = SetWaveFormat();
CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
= mWavFormat;//设置缓冲区要捕捉的数据格式
iNotifySize = eBytesPerSecond / iNotifyNum;//1秒的数据量/设置的通知数得到的每个通知大小小于0.2s的数据量,话音延迟小于200ms为优质话音
iBufferSize = iNotifyNum * iNotifySize;
Bytes = iBufferSize;
lEffects = true;
pped = true;
capturebuffer = new CaptureBuffer(bufferdescription, capture);//建立设备缓冲区对象
}
//设置通知
private void CreateNotification()
{ BufferPositionNotify[] bpn = new BufferPositionNotify[iNotifyNum];//设置缓冲区通知个数
//设置通知事件
notifyEvent = new AutoResetEvent(false);
notifyThread = new Thread(RecoData);//通知触发事件
ground = true;
();
for (int i = 0; i < iNotifyNum; i++)
{
bpn[i].Offset = iNotifySize + i * iNotifySize - 1;//设置具体每个的位置
bpn[i].EventNotifyHandle = ;
}
myNotify = new Notify(capturebuffer);
ificationPositions(bpn);
}
//线程中的事件
private void RecoData()
{
while (true)
{
// 等待缓冲区的通知消息
e(te, true);
// 录制数据
RecordCapturedData(Client,epServer);
}
}
//真正转移数据的事件,其实就是把数据传送到网络上去。
private void RecordCapturedData(Socket Client,EndPoint epServer )
{
byte[] capturedata = null;
int readpos = 0, capturepos = 0, locksize = 0;
rentPosition(out capturepos, out readpos);
locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小
if (locksize == 0)
{
return;
}
if (locksize < 0)
{//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处
locksize += iBufferSize;
}
capturedata = (byte[])(iBufferOffset, typeof(byte), iteCursor, locksize);
//capturedata = (capturedata);//语音编码
try
{
(capturedata, epServer);//传送语音
}
catch
{
throw new Exception();
}
iBufferOffset += ;
iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
}
上述代码可以很好的采集到声音数据,几乎与原始声音一致。如果你已经可以实现录音,那么以上对你来说应该并不陌生。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1690643542a384537.html
评论列表(0条)