using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace MatureVoice
{
public partial class Voice : DevComponents.DotNetBar.Office2007Form
{
public Voice()
{
InitializeComponent();
}
private Point posMouse;
private NetChat netchat1;
private void Voice_Load(object sender, EventArgs e)
{
netchat1 = new NetChat(8000);
this.Text = "本机:" + netchat1.BindSelf(netchat1.LocalIPEnd);
// this.comboIP.Text = Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
// MessageBox.Show(Dns.GetHostAddresses(Dns.GetHostName())[0].ToString());
}
private void Voice_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
posMouse.X = e.X;
posMouse.Y = e.Y;
}
}
private void Voice_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Voice.ActiveForm.Top = Control.MousePosition.Y - posMouse.Y - SystemInformation.FrameBorderSize.Height - SystemInformation.CaptionHeight;
Voice.ActiveForm.Left = Control.MousePosition.X - posMouse.X - SystemInformation.FrameBorderSize.Width;
}
}
private void btnSelect_Click(object sender, EventArgs e)
{
}
//建立一个委托
private delegate void FormHandel(string strArgu);
private void FormWrite(string strText)
{
if (InvokeRequired)
{
FormHandel handel1 = new FormHandel(FormWrite);
this.Invoke(handel1, new object[] { strText });
}
else
{
lblStatus.Text = strText;
}
}
private void Voice_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void lblStatus_TextChanged(object sender, EventArgs e)
{
timer1.Start();
}
private int intTickedTimes = 0;
private void timer1_Tick(object sender, EventArgs e)
{
intTickedTimes++;
if (intTickedTimes > 6)
{
timer1.Stop();
intTickedTimes = 0;
}
else
{
lblStatus.ForeColor = intTickedTimes % 2 == 0 ? Color.MidnightBlue : Color.Red;
}
}
string ip = "";
private void btnSubmit_Click(object sender, EventArgs e)
{
}
private void btnChat_Click(object sender, EventArgs e)
{//先初始化语音模块,启动监听方法,再启动语音采集方法
progressBar1.Maximum = 60;
try
{
netchat1.SetRemoteIPEnd(ip, 8000);
FormWrite("已经接通……!");
}
catch
{
FormWrite("非法的IP地址");
btnChat.Enabled = false;
}
if (btnChat.Text == "接听")
{
btnChat.Text = "持断";
i = 0;
timer2.Enabled = true;
try
{
netchat1.Intptr = this.Handle;
netchat1.InitVoice();
}
catch
{
FormWrite("声音模块初始化失败");
}
try
{
netchat1.Listen();
}
catch
{
FormWrite("监听模块异常");
}
try
{
netchat1.StartSendVoice();
}
catch
{
if (MessageBox.Show("应用程序出现问题,需要重新启动应该程序嘛?", "系统提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes)
{
Application.Exit();//先关闭应用程序
System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location);
}
}
}
else
{
netchat1.Stop();
btnChat.Text = "接听";
timer1.Enabled = false;
timer2.Enabled = false;
}
}
int i = 0;
private void timer2_Tick(object sender, EventArgs e)
{
i++;
lblStatus.Text = i.ToString();
progressBar1.Value = i;
if (i==60)
{
i = 0;
}
}
private void button2_Click(object sender, EventArgs e)
{
ip = "192.168.50.5";
}
private void button3_Click(object sender, EventArgs e)
{
ip = "192.168.50.31";
}
private void button4_Click(object sender, EventArgs e)
{
ip = "192.168.50.36";
}
private void button5_Click(object sender, EventArgs e)
{
ip = "192.168.50.33";
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Diagnostics;
using System.Collections;
using System.DirectoryServices;
using System.Threading;
namespace MatureVoice
{
class ListUsers
{
public static ArrayList GetComputerList()
{
ArrayList list = new ArrayList();
DirectoryEntry root = new DirectoryEntry("WinNT:");
DirectoryEntries domains = root.Children;
domains.SchemaFilter.Add("domain");
foreach (DirectoryEntry domain in domains)
{
DirectoryEntries computers = domain.Children;
computers.SchemaFilter.Add("computer");
foreach (DirectoryEntry computer in computers)
{
object[] arr = new string[3];
IPHostEntry iphe = null;
try
{
iphe = Dns.GetHostByName(computer.Name);
}
catch
{
continue;
}
arr[0] = domain.Name;
arr[1] = computer.Name;
if (iphe != null && iphe.AddressList.Length > 0)
{
arr[2] += iphe.AddressList[0].ToString();
}
else
arr[2] = "";
list.Add(arr);
}
}
return list;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace MatureVoice
{
class NetChat
{
private int intPointVariable = 1;//端口增长幅度
private IPEndPoint ipeLocal;
private Socket LocalSocket;
private IPEndPoint ipeRemote;
private int intMaxDataSize = 10000;//接收缓冲区长度
private VoiceCapture voicecapture1 = new VoiceCapture();
private IntPtr intptr;
public IntPtr Intptr
{
set
{
intptr = value;
}
}
public IPEndPoint LocalIPEnd
{
get { return ipeLocal; }
}
public NetChat(int intPort)
{
ipeLocal = new IPEndPoint(IPAddress.Any, intPort);//配置本地IP 和 端口
LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
public NetChat(string strIP, int intPort)
{
ipeLocal = new IPEndPoint(IPAddress.Parse(strIP), intPort);//配置本地IP 和 端口
LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
/// <summary>
/// 绑定自己的IP和端口
/// </summary>
/// <param name="ipe">IP端口对</param>
/// <returns>绑定成功返回true</returns>
public string BindSelf(IPEndPoint ipe)
{
while (true)
{
try
{
LocalSocket.Bind((EndPoint)ipeLocal);
return ipeLocal.Address.ToString()+" : "+ipeLocal.Port;
}
catch
{
ipeLocal.Port = 8000 + intPointVariable;
intPointVariable++;
}
}
}
/// <summary>
/// 设置远程IP端口节点
/// </summary>
/// <param name="strRemote">远程IP</param>
/// <param name="intPort">远程端口</param>
public void SetRemoteIPEnd(string strRemote, int intPort)
{
ipeRemote = new IPEndPoint(IPAddress.Parse(strRemote), intPort);
}
private Thread ListenThread;
private byte[] bytData;
/// <summary>
/// 监听方法,用于监听远程发送到本机的信息
/// </summary>
public void Listen()
{
ListenThread = new Thread(new ThreadStart(DoListen));
ListenThread.IsBackground = true;//设置为后台线程,这样当主线程结束后,该线程自动结束
ListenThread.Start();
}
private EndPoint epRemote;
/// <summary>
/// 监听线程
/// </summary>
private void DoListen()
{
bytData = new byte[intMaxDataSize];
epRemote = (EndPoint)(new IPEndPoint(IPAddress.Any, 0));
//可能会抛出一个异常
while (true)
{
if (LocalSocket.Poll(5000, SelectMode.SelectRead))
{//每5ms查询一下网络,如果有可读数据就接收
LocalSocket.BeginReceiveFrom(bytData, 0, bytData.Length, SocketFlags.None, ref epRemote, new AsyncCallback(ReceiveData), null);
}
}
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="iar"></param>
private void ReceiveData(IAsyncResult iar)
{
int intRecv = 0;
try
{
intRecv = LocalSocket.EndReceiveFrom(iar, ref epRemote);
}
catch
{
throw new Exception();
}
if (intRecv > 0)
{
byte[] bytReceivedData = new byte[intRecv];
Buffer.BlockCopy(bytData, 0, bytReceivedData, 0, intRecv);
voicecapture1.GetVoiceData(intRecv, bytReceivedData);//调用声音模块中的GetVoiceData来从字节数组中获取声音并播放
}
}
public void InitVoice()
{
voicecapture1 = new VoiceCapture();
voicecapture1.NotifyNum = 10;
voicecapture1.NotifySize = 4410;
voicecapture1.LocalSocket = LocalSocket;
voicecapture1.RemoteEndPoint = (EndPoint)ipeRemote;
voicecapture1.Intptr = intptr;
voicecapture1.InitVoice();
}
public void StartSendVoice()
{
voicecapture1.StartVoiceCapture();
}
public void Stop()
{
if (ListenThread != null && ListenThread.IsAlive == true)
{
ListenThread.Abort();
}
voicecapture1.Stop();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using System.Net.Sockets;
using System.Net;
namespace MatureVoice
{
class VoiceCapture
{
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;//窗口句柄
public IntPtr Intptr
{
set
{
intptr = value;
}
}
public int NotifySize
{
set
{
iNotifySize = value;
}
}
public int NotifyNum
{
set
{
iNotifyNum = value;
}
}
public Socket LocalSocket
{
set
{
Client = value;
}
}
public EndPoint RemoteEndPoint
{
set
{
epServer = value;
}
}
/// <summary>
/// 初始化相关操作
/// </summary>
public void InitVoice()
{//初始化声音相关设置:(1)捕捉缓冲区(2)播放缓冲区
if (!CreateCaputerDevice())
{
throw new Exception();
}//建立设备对象
CreateCaptureBuffer();//建立缓冲区对象
CreateNotification();//设置通知及事件
//======(2)==============
if (!CreatePlayDevice())
{
throw new Exception();
}
CreateSecondaryBuffer();
}
/// <summary>
/// 启动声音采集
/// </summary>
public void StartVoiceCapture()
{
capturebuffer.Start(true);//true表示设置缓冲区为循环方式,开始捕捉
}
/// <summary>
/// 创建用于播放的音频设备对象
/// </summary>
/// <returns>创建成功返回true</returns>
private bool CreatePlayDevice()
{
DevicesCollection dc = new DevicesCollection();
Guid g;
if (dc.Count > 0)
{
g = dc[0].DriverGuid;
}
else
{ return false; }
PlayDev = new Device(g);
PlayDev.SetCooperativeLevel(intptr, CooperativeLevel.Normal);
return true;
}
/// <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];
memstream = new MemoryStream(bytMemory, 0, 100000, true, true);
//g729 = new G729();
//g729.InitalizeEncode();
//g729.InitalizeDecode();
}
/// <summary>
/// 创建捕捉设备对象
/// </summary>
/// <returns>如果创建成功返回true</returns>
private bool CreateCaputerDevice()
{
//首先要玫举可用的捕捉设备
CaptureDevicesCollection capturedev = new CaptureDevicesCollection();
Guid devguid;
if (capturedev.Count > 0)
{
devguid = capturedev[0].DriverGuid;
}
else
{
System.Windows.Forms.MessageBox.Show("当前没有可用于音频捕捉的设备", "系统提示");
return false;
}
//利用设备GUID来建立一个捕捉设备对象
capture = new Capture(devguid);
return true;
}
/// <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;
capturebuffer = new CaptureBuffer(bufferdescription, capture);//建立设备缓冲区对象
}
//设置通知
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;
}
myNotify = new Notify(capturebuffer);
myNotify.SetNotificationPositions(bpn);
}
//线程中的事件
private void RecoData()
{
while (true)
{
// 等待缓冲区的通知消息
notifyEvent.WaitOne(Timeout.Infinite, true);
// 录制数据
RecordCapturedData(Client,epServer);
}
}
//真正转移数据的事件,其实就是把数据传送到网络上去。
private void RecordCapturedData(Socket Client,EndPoint epServer )
{
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.FromWriteCursor, locksize);
//capturedata = g729.Encode(capturedata);//语音编码
try
{
Client.SendTo(capturedata, epServer);//传送语音
}
catch
{
throw new Exception();
}
iBufferOffset += capturedata.Length;
iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
}
private int intPosWrite = 0;//内存流中写指针位移
private int intPosPlay = 0;//内存流中播放指针位移
private int intNotifySize = 5000;//设置通知大小
/// <summary>
/// 从字节数组中获取音频数据,并进行播放
/// </summary>
/// <param name="intRecv">字节数组长度</param>
/// <param name="bytRecv">包含音频数据的字节数组</param>
public void GetVoiceData(int intRecv, byte[] bytRecv)
{
//intPosWrite指示最新的数据写好后的末尾。intPosPlay指示本次播放开始的位置。
if (intPosWrite + intRecv <= memstream.Capacity)
{//如果当前写指针所在的位移+将要写入到缓冲区的长度小于缓冲区总大小
if ((intPosWrite - intPosPlay >= 0 && intPosWrite - intPosPlay < intNotifySize) || (intPosWrite - intPosPlay < 0 && intPosWrite - intPosPlay + memstream.Capacity < intNotifySize))
{
memstream.Write(bytRecv, 0, intRecv);
intPosWrite += intRecv;
}
else if (intPosWrite - intPosPlay >= 0)
{//先存储一定量的数据,当达到一定数据量时就播放声音。
buffDiscript.BufferBytes = intPosWrite - intPosPlay;//缓冲区大小为播放指针到写指针之间的距离。
SecondaryBuffer sec = new SecondaryBuffer(buffDiscript, PlayDev);//建立一个合适的缓冲区用于播放这段数据。
memstream.Position = intPosPlay;//先将memstream的指针定位到这一次播放开始的位置
sec.Write(0, memstream, intPosWrite - intPosPlay, LockFlag.FromWriteCursor);
sec.Play(0, BufferPlayFlags.Default);
memstream.Position = intPosWrite;//写完后重新将memstream的指针定位到将要写下去的位置。
intPosPlay = intPosWrite;
}
else if (intPosWrite - intPosPlay < 0)
{
buffDiscript.BufferBytes = intPosWrite - intPosPlay + memstream.Capacity;//缓冲区大小为播放指针到写指针之间的距离。
SecondaryBuffer sec = new SecondaryBuffer(buffDiscript, PlayDev);//建立一个合适的缓冲区用于播放这段数据。
memstream.Position = intPosPlay;
sec.Write(0, memstream, memstream.Capacity - intPosPlay, LockFlag.FromWriteCursor);
memstream.Position = 0;
sec.Write(memstream.Capacity - intPosPlay, memstream, intPosWrite, LockFlag.FromWriteCursor);
sec.Play(0, BufferPlayFlags.Default);
memstream.Position = intPosWrite;
intPosPlay = intPosWrite;
}
}
else
{//当数据将要大于memstream可容纳的大小时
int irest = memstream.Capacity - intPosWrite;//memstream中剩下的可容纳的字节数。
memstream.Write(bytRecv, 0, irest);//先写完这个内存流。
memstream.Position = 0;//然后让新的数据从memstream的0位置开始记录
memstream.Write(bytRecv, irest, intRecv - irest);//覆盖旧的数据
intPosWrite = intRecv - irest;//更新写指针位置。写指针指示下一个开始写入的位置而不是上一次结束的位置,因此不用减一
}
}
/// <summary>
/// 设置音频格式,如采样率等
/// </summary>
/// <returns>设置完成后的格式</returns>
private WaveFormat SetWaveFormat()
{
WaveFormat format = new WaveFormat();
format.FormatTag = WaveFormatTag.Pcm;//设置音频类型
format.SamplesPerSecond = 11025;//采样率(单位:赫兹)典型值:11025、22050、44100Hz
format.BitsPerSample = 16;//采样位数
format.Channels = 1;//声道
format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));//单位采样点的字节数
format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;
return format;
//按照以上采样规格,可知采样1秒钟的字节数为22050*2=44100B 约为 43K
}
/// <summary>
/// 停止语音采集
/// </summary>
public void Stop()
{
capturebuffer.Stop();
if (notifyEvent != null)
{
notifyEvent.Set();
}
if (notifyThread != null && notifyThread.IsAlive == true)
{
notifyThread.Abort();
}
}
}
}