`
touchinsert
  • 浏览: 1351430 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

[转]c#编写网络电话

 
阅读更多

本文转自:http://www.cnblogs.com/dfsxh/archive/2008/12/30/1355886.html

原文如下:

摘要:语音通话已经是IM的基本功能了,qq,MSN甚至连刚出来的百度HI都自带语音聊天的功能,大家可能觉得很炫,其实大家都是用的windows平台上的API,懂了原理之后自己也可以做,再说了微软也提供了DirectSound的托管互操作程序集,使.net开发人员也很容易的介入到这个领域,甚至你还可以写一个能跑在window mobile上的语音电话,现在好多手机都支持wifi,这样一个简单的wifi电话就由你的手里诞生了。本帖来和大家一起看看如何来做网络电话。

思路:要想做一个网络电话,基本遵循以下步骤
1、一方实时的录音,把模拟信号转换成数字信号;
2、把声音实时压缩;
3、通过网络协议把压缩后的数据传输给接收方;
4、接收方解压缩接受到的音频数据;
5、实时的把接收到的数字信号转换成模拟信号并播放出来。

下面我们来看看每一步面临的挑战及其解决方案。
1、第一步,实时录音,DirectxSound有录音方面的API,托管的类分别是Microsoft.DirectX.DirectSound.CaptureDevicesCollection,Microsoft.DirectX.DirectSound.Capture和Microsoft.DirectX.DirectSound.CaptureBuffer,CaptureDevicesCollection用来枚举本机的可用的录音设备,Capture则表示一个录音设备,CaptureBuffer是用来存放录音数据的缓冲区,我们开始录音后,音频数据会不断的写入到环形的流式缓冲区,然后我们定期从缓冲区中把录音数据取出来返回给上层应用层就可以了。关于环形的流式缓冲区,可以看参考链接部分。
2、声音的压缩是一个很难抉择的步骤,默认的DirectSound只能播放和录制PCM格式(WAV)的音频数据,但这种声音格式特别大。常用的声音压缩格式有h.7231,gsm,amr,h.711等等,各种压缩算法都有自己的码率和适用范围。因为我们做的是互联网的语音电话,不考虑慢速网络和无线连接下的情况,也不用考虑终端设备的CPU能不能支持我们选用的压缩算法,我们做的语音电话双方都是PC机,应该什么解压缩算法都不会引起什么性能上的问题,所以只要网络快一些,选择哪个压缩算法都无所谓了,网上有h.711的压缩算法,我打算就采用这个,他的码率是64Kbps,比PCM的1.544Mbps和2.048Mbps要小的多。然后我们进行了音频数据压缩后,还可以对字节流进行GZIP或者7ZIP压缩,前者用SharpZip,后者7zip的官方有c#的使用代码,大家可以测试一下这两个算法的性能后做出适合自己的决定。关于各种压缩格式的特性可以参考我做的PPT及提供的参考链接。
3、网络电话注重实时性,而把声音从网络上传输就要走IP网络,而IP网络不是一个等时系统,所以我们就要尽量的去模拟实时的语音传输,提到实时,肯定UDP比TCP要实时,因为TCP要保证传输的可靠性,有序性等,而专门用于实时传输有一个应用层协议是RTP协议,这个协议一般就是建立在UDP基础上的,它在每个包头提供了一些序列号、时间戳等信息,但UDP本身并不会使用这些信息,这时候就有一个RTCP协议来用这些信息进行流量控制和拥塞控制,比如说RTCP检测到网络拥挤,会告诉发送方变换一种低码率的语音压缩算法来传输数据。这些大多都需要自己去实现,本文的源码没有去实现这些,关于RTP和RTCP可以参考相关资料或者我做的PPT。
4、每个压缩算法都有相应的解压缩算法,呵呵。
5、播放声音肯定也需要用到DS,也需要用到StreamBuffer,大致流程如下
1)创建一个声音设备Microsoft.DirectX.DirectSound.Device dev = new Microsoft.DirectX.DirectSound.Device();
2)设置协调级别dev.SetCooperativeLevel(this, Microsoft.DirectX.DirectSound.CooperativeLevel.Normal);
3)创建声音格式、缓冲区描述、及辅助缓冲区;
4)给辅助缓冲区设定通知;
5)用声音数据填满缓冲区;
6)播放缓冲区的声音数据,播放到一定的通知点,通知填充线程,填充新的声音数据;
7)循环第6步,直到没有新的声音数据填充到缓冲区。

具体的过程参考PPT或者具体代码。


版权声明:
附件源代码里的CaptureSound,SoundPlayer和CircularBuffer类反编译自随意桌面的代码(注释是我加的),版权归作者所有。
PPT里的图片和一些文字选自一个叫做ch11-DxSound&Input2.ppt的文件,源链接已丢失,还有一些选择一个叫做“SIP之 穿越NAT.ppt”的文件,网上可以搜索到,版权均归原作者所有,源作者要是再引用别人的东西,我就不知道了。

下面看一些具体的代码

用户创建声音格式

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->publicclassDirectSoundManager
{
publicstaticWaveFormatCreateWaveFormat(inthz,shortbits,shortchannels)
{
WaveFormatformat
=newWaveFormat();
//声音的格式,通常使用WAVE_FORMAT_PCM来设定,
//因为PCM是比较常用的声音格式。
format.FormatTag=WaveFormatTag.Pcm;
//采样率(单位:赫兹)典型值:11025、22050、44100Hz
format.SamplesPerSecond=hz;
//每个采样点数;8-bit或16-bit;
format.BitsPerSample=bits;
//声道的设置,当其值为1时是单声道,为2时是双声道;
format.Channels=channels;
//每个采样点字节数
format.BlockAlign=(short)(format.Channels*(format.BitsPerSample/8));
//平均传输率,每秒的数据流量
format.AverageBytesPerSecond=format.BlockAlign*format.SamplesPerSecond;
returnformat;
}


属性#region属性
//Properties
publicstaticWaveFormatDefaultFormat
{
get
{
returnWaveFormat_8000_8_1;
}

}


publicstaticWaveFormatWaveFormat_11025_8_1
{
get
{
returnCreateWaveFormat(0x2b11,8,1);
}

}


publicstaticWaveFormatWaveFormat_22050_16_2
{
get
{
returnCreateWaveFormat(0x5622,0x10,2);
}

}


publicstaticWaveFormatWaveFormat_44100_16_2
{
get
{
returnCreateWaveFormat(0xac44,0x10,2);
}

}


publicstaticWaveFormatWaveFormat_8000_8_1
{
get
{
returnCreateWaveFormat(0x1f40,8,1);
}

}

#endregion

}


用于播放流式声音

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->publicclassSoundPlayer:IDisposable
{
私有成员#region私有成员
privateconstintMaxLatencyMs=300;
privateconstintNumberRecordNotifications=4;
privatereadonlyCircularBuffercircularBuffer;
privatereadonlyintm_BufferBytes;
privatereadonlyboolm_OwnsDevice;
privatereadonlyintnotifySize;
privatereadonlyBufferPositionNotify[]positionNotify;
privateboolisRunning;
privateSecondaryBufferm_Buffer;
privateDevicem_Device;
privateintnextWriteOffset;
privateAutoResetEventnotificationEvent;
privateNotifynotify;
privateThreadnotifyThread;
#endregion


构造函数#region构造函数
publicSoundPlayer(Controlowner,WaveFormatformat)
:
this(owner,null,format)
{
}


publicSoundPlayer(Controlowner,Devicedevice,WaveFormatformat)
{
positionNotify
=newBufferPositionNotify[5];
notificationEvent
=null;
notify
=null;
notifyThread
=null;
notifySize
=0;
m_Device
=device;
if(m_Device==null)
{
m_Device
=newDevice();
m_Device.SetCooperativeLevel(owner,CooperativeLevel.Normal);
m_OwnsDevice
=true;
}

//设定通知的大小,大小为播放一秒钟声音所需要的字节。这里为什么除以8,我不清楚
notifySize=(1024>(format.AverageBytesPerSecond/8))?(1024):((format.AverageBytesPerSecond/8));
notifySize
=(notifySize-(notifySize%format.BlockAlign));
m_BufferBytes
=(notifySize*4);//整体缓冲区的大小
BufferDescriptiondesc=newBufferDescription(format);
//缓冲区具有控制音量的能力;
desc.ControlVolume=true;
//缓冲区具有控制位置的能力。
desc.ControlPositionNotify=true;
//设置缓冲区能取到当前的播放位置
desc.CanGetCurrentPosition=true;
//缓冲区不具有控制3D音效的能力;
desc.Control3D=false;
//Specifieswhetherthebuffersupportseffectsprocessing.
desc.ControlEffects=false;
//缓冲区具有控制频率的能力;
desc.ControlFrequency=true;
//缓冲区具有控制左右声道的能力;
desc.ControlPan=true;
//设置是否使用全局缓存
desc.GlobalFocus=true;
//设置缓冲区大小为整个缓冲区的大小
desc.BufferBytes=m_BufferBytes;

//创建辅助缓冲区
m_Buffer=newSecondaryBuffer(desc,m_Device);
//创建环形缓冲区
circularBuffer=newCircularBuffer((m_BufferBytes*10));
InitNotifications();
m_Buffer.Play(
0,BufferPlayFlags.Looping);
}


publicSoundPlayer(Controlowner,intsr,shortbps,shortch)
:
this(owner,null,DirectSoundManager.CreateWaveFormat(sr,bps,ch))
{
}


publicSoundPlayer(Controlowner,Devicedevice,intsr,shortbps,shortch)
:
this(owner,device,DirectSoundManager.CreateWaveFormat(sr,bps,ch))
{
}

#endregion


公开属性#region公开属性
publicintBitsPerSample
{
get{returnm_Buffer.Format.BitsPerSample;}
}


publicintChannels
{
get{returnm_Buffer.Format.Channels;}
}


publicDeviceDevice
{
get{returnm_Device;}
}


publicintSamplingRate
{
get{returnm_Buffer.Format.SamplesPerSecond;}
}

#endregion


IDisposableMembers#regionIDisposableMembers

publicvoidDispose()
{
Stop();
if(m_Buffer!=null)
{
m_Buffer.Dispose();
m_Buffer
=null;
}

if(m_OwnsDevice&&<span
分享到:
评论

相关推荐

    用C#编写网络电话(含方法和源代码)

    ### 用C#编写网络电话的关键技术点 #### 一、引言 随着互联网技术的发展,网络电话成为了人们日常生活中不可或缺的一部分。利用编程语言如C#来开发网络电话应用程序不仅能够提升用户体验,还能够实现更加丰富的功能...

    网络电话的编写c#实现

    网路电话用c#实现,实现细节详细,详细描述了实现每个市县细节。

    c#编写的个人通讯录以及数据库连接方法应用

    总结起来,创建一个C#编写的个人通讯录应用程序涉及了用户界面设计、数据库连接、数据操作等多个方面,需要掌握C#编程基础、数据库管理以及良好的软件工程实践。通过以上步骤,我们可以构建出一个功能完备、用户体验...

    c#编写的个人简历系统

    本篇文章将深入探讨如何利用C#编写一个个人简历系统,旨在帮助公司收集和管理员工的简历信息,同时也方便求职者在网络上便捷地填写和提交简历。 首先,我们要理解个人简历系统的基本需求。这通常包括以下几个核心...

    C#编写的企业电话客服系统

    C#编写的企业电话客服系统,系统运用现代化的技术,为中小型企业提供现代化的管理手段,提高企业产品信息的收集、处理能力,联动及反映能力,为各级领导和管理人员提供准确、及时的分析数据,提高管理的科学性和工作...

    FreeTalk网络电话软件(c#)源代码

    FreeTalk网络电话软件是一款利用C#编程语言开发的、基于.NET框架和DirectX技术的通信应用,它允许用户进行点对点的网络语音聊天。在深入探讨其技术细节之前,让我们先了解一下C#、.NET框架和DirectX这三大核心技术。...

    C#开发的sip软电话源码

    在本项目中,C#用于编写SIP软电话的用户界面、网络通信模块、媒体处理等各个部分。 3. VS环境:Visual Studio是微软提供的集成开发环境(IDE),支持多种编程语言,包括C#。在这个项目中,用户可以直接在VS中打开...

    企业电话客服系统源程序 c#编写

    在电话客服系统中,C#提供了强大的类库和特性,如异常处理、多线程、网络通信等,支持高效稳定的系统开发。 2. .NET Framework:C#是基于.NET Framework运行的,它提供了一整套服务和库,如ASP.NET(用于Web应用)...

    c#实现的SIP软电话

    在C#中实现SIP软电话,意味着开发者需要深入理解SIP协议的规范,如RFC3261,以便编写能够解析和发送SIP消息的代码。这包括邀请(INVITE)、确认(ACK)、注册(REGISTER)、bye(结束会话)等关键消息。 2. **来电...

    c#编写银行管理系统

    总结起来,C#编写银行管理系统涉及用户认证、数据库交互、事务处理、异常处理、安全性设计以及用户界面开发等多个方面。掌握这些技能,不仅可以帮助你构建出高效稳定的银行管理系统,还能为其他类型的业务应用开发...

    C++编写基于socket的网络电话

    在IT领域,网络电话是一种利用互联网传输语音通信的技术,它基于IP协议,使得人们可以通过互联网进行实时通话。本文将深入探讨如何使用C++语言来实现一个基于socket的网络电话系统。 首先,我们要理解socket,它是...

    C# 编写的短信猫发送短信dll源码和一个简单的winform测试

    c#编写的短信猫(WAVECOM)发送短信程序dll,没有任何功能限制,在你的程序中引用SIMSMS.dll就可以了。帮助文档就不写了,在程序中有注释,在测试的winform中也有简单应用的示例。看看就明白了! 如果感觉功能不够,...

    基于c#编写的windows mobile 的电话来电防火墙

    本项目聚焦于一个特定的应用:基于C#编写的Windows Mobile电话来电防火墙。 电话来电防火墙是一种软件应用,它允许用户控制和管理他们的来电,根据预设规则筛选和阻止不必要的或烦人的来电。在Windows Mobile平台上...

    网络电话(SIP VoIP)

    **网络电话(SIP VoIP)** 网络电话,也称为VoIP(Voice over Internet Protocol),是一种利用互联网协议传输语音通信的技术。它通过将语音信号转换为数据包,并在网络上传输,实现了传统电话服务的功能,但成本更...

    开源sip协议 linphone C# 多account register 接打电话

    描述部分没有提供具体细节,但我们可以推断这可能是一个使用C#编写的软件或插件,利用Linphone库实现了多个SIP账号的注册功能,并且具备接打电话的能力。多账户注册意味着用户可以管理并使用多个不同的SIP账号,这样...

    C#简易电话薄

    【C#简易电话薄】项目是一个使用C#编程语言实现的简单电话簿应用程序,它集成了基本的联系人管理功能,如插入、删除和查找。这个应用设计为与服务器进行交互,因此它涉及到网络通信和数据同步的概念。下面将详细阐述...

    c#写的短息发送系统。

    总的来说,这个C#编写的短信发送系统利用第三方短信服务,通过C# SDK实现了向指定电话号码发送短信的功能,可能还包含了服务注册以便于后台自动化运行。开发这样的系统需要对C#编程、网络通信以及第三方API的使用有...

    C#常用网络验证技巧

    C#作为一种广泛使用的编程语言,在网络验证方面提供了强大的工具和方法。本文将深入探讨C#中常用的网络验证技巧及其背后的原理,帮助开发者更好地理解和运用这些技巧。 ### 一、网络验证应用技巧 #### 1. 验证E-...

    C# 基于LumiSoft.Net的Sip电话开发

    在C#中开发SIP电话应用,意味着我们需要利用它的网络编程能力,如套接字(Socket)和异步编程模型,来处理SIP报文的发送和接收。 LumiSoft.Net是一个全面的开源库,专为.NET开发者设计,提供了丰富的SIP协议实现。...

Global site tag (gtag.js) - Google Analytics