C# UDP+NAUDIO局域网声音组播传送与播放
本实例通过采集麦克声音数据,利用udp组播方式在局域网中进行组播传送(类似在组内进行广播,udp广播、组播、单播请自行查阅相关资料),组内成员通过接收并播放到扬声器。
程序中引用了 Naudio 声音处理类库进行声音的采集与播放,可通过VS NuGet 查找并引用,关于声音处理相关技术请查阅相关文档。
防火墙要做好响应放行或直接关闭,否则数据无法接收和发送。另外可网管交换机也要做相应放行,否则也无法通讯。
运行效果:
注意:两台pc要设置相同广播端口才可以。
using System;
using System.Windows.Forms;
using NAudio.Wave;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace Test
{
public partial class FormNetSound : Form
{
private WaveIn mic;//音频输入,从mic采集,如果电脑硬件没有mic会报错
private WaveOut speaker;//音频输出
private BufferedWaveProvider _BWP;//接收声音缓冲
private UdpClient2 receiver;//接收用
private UdpClient2 multicaster;//组播用
public FormNetSound()
{
InitializeComponent();
lbl_mic.Visible = false;//声音输入设备打开标志
lbl_speaker.Visible = false;//声音输出设备打开标志
}
/// <summary>
/// udp音频接收响应
/// </summary>
/// <param name="obj">pcm音频数据</param>
private void receive_sound(byte[] obj)
{
_BWP.AddSamples(obj, 0, obj.Length);//添加到待播放缓存中
}
/// <summary>
/// mic声音udp组播
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (!lbl_mic.Visible) return;
multicaster.SendMessageByMulticast(e.Buffer,int.Parse(tb_dest_port.Text));
}
private void btn_receive_Click(object sender, EventArgs e)
{
if (btn_receive.Text.Equals("静音"))
{
//接收udp组播数据用
receiver = new UdpClient2(int.Parse(tb_dest_port.Text) , tb_dest_ip.Text);
//生成默认声音播放对象
speaker = new WaveOut();
//设置声音格式
WaveFormat wf = new WaveFormat(16000, 16, 1);
//初始化待播放声音缓存对象
_BWP = new BufferedWaveProvider(wf);
//初始化播放设备
speaker.Init(_BWP);
if (receiver.recvMessageEvent == null)
{
//绑定udpclient接收数据响应事件
receiver.recvMessageEvent += new Action<byte[]>(receive_sound);
}
receiver.Start();//开始接收数据
btn_receive.Text = "打开";
speaker.Play();//开始播放声音
lbl_speaker.Visible = true;
}else
{
btn_receive.Text = "静音";
speaker.Stop();//停止播放声音
receiver.CloseUdpCliend();//关闭接收
lbl_speaker.Visible = false;
}
}
private void btn_send_Click(object sender, EventArgs e)
{
if (btn_send.Text.Equals("静音"))
{
//发送声音数据用
multicaster = new UdpClient2(int.Parse(tb_local_port.Text) , tb_dest_ip.Text);
mic = new WaveIn();//生成音频输入设备
mic.WaveFormat = new WaveFormat(16000, 16 ,1); // 16bit,16KHz,Mono的录音格式
//绑定声音输入处理事件
mic.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
multicaster.Start();//开始广播
btn_send.Text = "打开";
mic.StartRecording();//开始采集声音
lbl_mic.Visible = true;
}
else
{
btn_send.Text = "静音";
mic.StopRecording();//停止采集声音
multicaster.CloseUdpCliend();//关闭组播
lbl_mic.Visible = false;
}
}
}
public class UdpClient2
{
//接收数据事件
public Action<byte[]> recvMessageEvent = null;
//发送结果事件
public Action<int> sendResultEvent = null;
//本地监听端口
public int localPort = 0;
//组播地址
public string MultiCastHost = "";
private UdpClient udpClient = null;
public UdpClient2(int localPort, string MultiCastHost)
{
if (localPort < 0 || localPort > 65535)
throw new ArgumentOutOfRangeException("localPort is out of range");
if (string.IsNullOrEmpty(MultiCastHost))
throw new ArgumentNullException("message cant not null");
this.localPort = localPort;
this.MultiCastHost = MultiCastHost;
}
public void Start()
{
while (true)
{
try
{
udpClient = new UdpClient(localPort);
udpClient.JoinMulticastGroup(IPAddress.Parse(MultiCastHost));
ReceiveMessage();
break;
}
catch (Exception)
{
Thread.Sleep(100);
}
}
}
private async void ReceiveMessage()
{
while (true)
{
if (udpClient == null)
return;
try
{
UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync();
byte[] message = udpReceiveResult.Buffer;
if (recvMessageEvent != null)
recvMessageEvent(message);
}
catch (Exception ex)
{
}
}
}
public async void SendMessageByMulticast(byte[] message,int destport)
{
if (udpClient == null) return;
byte[] buffer = message;
int len = 0;
for (int i = 0; i < 1; i++)
{
try
{
len = await udpClient.SendAsync(buffer, buffer.Length, new IPEndPoint(IPAddress.Parse(MultiCastHost), destport));
}
catch (Exception)
{
len = 0;
}
if (len <= 0)
Thread.Sleep(100);
else
break;
}
if (sendResultEvent != null)
sendResultEvent(len);
}
public void CloseUdpCliend()
{
if (udpClient == null)
throw new ArgumentNullException("udpClient cant not null");
try
{
udpClient.Client.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
}
udpClient.Close();
udpClient = null;
}
}
}