2012年7月15日星期日

【转】编写一个SIP软电话所需要的组件

     若要编制一个支持语音视频的SIP软电话,至少需要以下组件及相关技术:

1.  SIP协议栈:主要用于会话的建立,修改以及终止。

开源SIP协议栈:

[1]The GNU oSIP library - http://www.gnu.org/software/osip/

[2] reSIProcate - http://www.resiprocate.org/Main_Page

[3] libmsip - http://www.minisip.org/download.html

[4] Sofia - SIP - http://sofia-sip.sourceforge.net/

[5] pjsip - http://www.pjsip.org/

更多的内容可参考网站:http://www.pernau.at/kd/voip/index.html

 

2.  SDP协议栈:主要用于会话的媒体协商。

3.  RTP协议栈:为数据提供了具有实时特征的端对端传送服务。

[1] jrtplib - http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.html

[2] ortp - http://www.linphone.org/ortp

[3] GNU ccRTP - http://www.gnu.org/software/ccrtp

更多的内容可参考网站:http://www.pernau.at/kd/voip/index.html

 

4.  音频编解码库:主要用于对音频数据编解码,以适应网络传输。

G.711 A-law

G.711 Mu-law

GSM

G729

Speex - http://www.speex.org/

还有好多,不一一列举。

 

5.  视频编解码库:主要用于对视频数据编解码,以适应网络传输。

Xvid - http://www.xvid.org/

X264 - http://www.videolan.org/developers/x264.html

Ffmpeg - http://ffmpeg.org/

 

6.  界面皮肤及操作库:主要用于软电话界面的显示以及逻辑的控制。

7.  音频数据处理库:对音频数据的基本处理,例如通过声卡获取,然后播放等。

8.  视频数据处理库:对视频数据的基本处理,例如通过显卡获取,然后播放等。

9.  NAT以及防火墙穿越技术:穿越私网和防火墙。

10. 防窃听防封杀加密技术:防黑客窃听,防有关部门封杀


摘自:http://blog.csdn.net/shangweiji/article/details/6100831

【转】Sipdroid的前世今生

Sipdroid是一个开源的SIP客户端,用于Android系统的智能手机上。可以进行双向语音通话,若要进行视频通话,需要注册到PBXES这家网络电话提供商上面。若注册到普通的SIP服务器上时,用装有SIPDROID的手机呼叫PC上的软电话,可以在PC上的软电话看到手机发送来的视频,编码格式为H263。反过来就不可以了,即手机作为被叫,在PC上的软电话就看不到手机发送来的视频了。

 

以上是SIPDROID的功能使用情况,下面介绍一下这个项目的来源。最早可能是http://www.hsc.com/这个公司做了一个DEMO,现在在其网站上都可以下载到。能进行基本的SIP呼叫。后来呢 ,可能是PBXES这家公司,组织了些程序员开始完善该软件,当然了,服务器基于PBXES的软交换系统,所以就像视频通话这样的功能只能是他的注册用户之间才可以,当然了若我们老牛的程序员也能做一个类似PBXES那样的服务器,就可以进行视频通话了。并且,将该软件开源。随着软件的完善,很多人都知道了这款软件,其中有个公司Gizmo5也使用了SIPDROID的代码,但他没开源,所以SIPDROID项目组给这个公司的BOSS写了封信,原文如下:http://code.google.com/p/sipdroid/wiki/Illegal_Usage_of_Source_Code。当然了,GIZMO5也开源了代码。其实,GIZMO5这个公司很有来头的,被GOOGLE收购了。

 

基本情况就是这样,sipdroid的网址是:http://code.google.com/p/sipdroid/。现在有一个网站聚集了一批研究SIPDROID的爱好者,网址为:www.shouyanwang.org.或者也可以登陆:www.voip123.cn,一个专门研究通过网络传输语音视频的论坛。(QQ274307918


摘自: http://blog.csdn.net/shangweiji/article/details/6396630

2012年7月7日星期六

【转】delphi 枚举类型与字符串的转换

摘自:http://hi.baidu.com/%D4%F8%BD%F0%C1%BA/blog/item/38a6ed3a0495cee115cecb0e.html

uses
Classes,TypInfo ;


type
TCommandType = (ctEmptyCommand,ctAdd,ctModify);

TCommandTypeConvert=class
public
    class function CommandToString(ACommand: TCommandType): string;
    class function StringToCommand(const AStrCommand: string): TCommandType;
end;

implementation


class function TCommandTypeConvert.CommandToString(ACommand: TCommandType): string;
begin
Result := GetEnumName(TypeInfo(TCommandType),Ord(ACommand));
end;

class function TCommandTypeConvert.StringToCommand(const AStrCommand: string): TCommandType;
begin
Result := TCommandType(GetEnumValue(TypeInfo(TCommandType), AStrCommand));
end;


end.

【转】Delphi枚举类型与整形的转换示例

摘自:http://hi.baidu.com/lzj1981/blog/item/ae758ead39585c074a36d62c.html

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, TypInfo;

type
TDemoType = (dta, dtb, dtc);

TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Edit1: TEdit;
    procedure BitBtn1Click(Sender: TObject);
private
    {Private declarations}
    aDemoType: TDemoType;
public
    {Public declarations}
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
aDemoType := TDemoType(StrToInt(Edit1.Text));
ShowMessage(GetEnumName(TypeInfo(TDemoType),Ord(aDemoType)));
end;

end.


2012年7月6日星期五

【转】Delphi实现DBGrid列宽度自动调整

大多数程序设计的爱好者选择并使用Delphi来编写软件,都是被其中丰富而功能强大的VCL控件所吸引。Delphi自带的数据感知(Data- Aware)控件,更是成为开发MIS软件的程序员之首选。在那么多数据感知控件中,TDBGrid由于其使用方便、显示信息量大成为最引人注目的一员, 大量的国内外软件中都出现了它的身影。或许是由于使用的人多了,对于它的期望也会更高,永远追求无限趋向于完美境界的程序员不会放过每一个能够改良 TDBGrid的机会。

经常使用TDBGrid的用户都知道,它没有提供这样的一种选择,使得我们能够让它的每一列与所要显示的数据的宽度相匹配。使得用户需要在程序运行时,手工对每一列进行调整,在下次运行这个程序时又得再做一遍同样的工作(图1)。

在进行修改后,我们可以得到一个更加智能化的TDBGrid,如果TDBGrid中所有列的宽度加起来大于它本身的宽度,那么智能化的 TDBGrid将会在它所含的最后一列的右边留出空白(见图2);反之如果TDBGrid中所有列的宽度加起来小于它本身的宽度,则会在它的下部显示一个 水平滚动条,用户就可以左右拖动该滚动条,显示更多想要的内容。

解决方案:

在本文中我将提供一个简便的过程(Procedure)来解决上面的问题,它能够在程序运行时自动固定TDBGrid中所显示列的宽度。

首先,在TForm的OnCreate事件中添加下面的代码:

Procedure TForm1.FormCreate(Sender: TObject);
  begin
  //在Tag属性中设置需要自动调整的列的最小宽度(固定值)
  //这里将列宽值设为40px
  Table1.FieldByName('FirstName').Tag := 40;
  //这里设置一个变化的值
  //该值是做过运算的列标题的宽度值
  Table1.FieldByName('LastName').Tag := 4 + Canvas.TextWidth( Table1.FieldByName('LastName').DisplayName);
end;

其次,最关键的一个过程(Procedure),就是用它来控制列的宽度:

Procedure FixDBGridColumnsWidth(const DBGrid: TDBGrid);
var
  i : integer;
  TotWidth : integer;//定义整个宽度
  VarWidth : integer;//定义变化的宽度
  ResizableColumnCount : integer;//定义变化宽度列的总数
  AColumn : TColumn;
begin
  //在重新调整前所有列的宽度
  TotWidth := 0;
  VarWidth := 0;
  //有多少列需要自动调整
  ResizableColumnCount := 0;
  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
   TotWidth := TotWidth + DBGrid.Columns[i].Width;
   if DBGrid.Columns[i].Field.Tag <> 0 then
    Inc(ResizableColumnCount);
  end;
  //为每个列分隔线增加1PX
  if dgColLines in DBGrid.Options then
   TotWidth := TotWidth + DBGrid.Columns.Count;
  if dgIndicator in DBGrid.Options then
   TotWidth := TotWidth + IndicatorWidth;
  VarWidth := DBGrid.ClientWidth - TotWidth;
  //平均分配变化宽度的值
  //给所有需要自动调整的列
  if ResizableColumnCount > 0 then
   VarWidth := varWidth div ResizableColumnCount;
  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
   AColumn := DBGrid.Columns[i];
   if AColumn.Field.Tag <> 0 then
   begin
    AColumn.Width := AColumn.Width + VarWidth;
    if AColumn.Width < AColumn.Field.Tag then
     AColumn.Width := AColumn.Field.Tag;
   end;
  end;
end;

最后,应用这一个函数:

Procedure TForm1.FormResize(Sender: TObject);
begin
  FixDBGridColumnsWidth(DBGrid1);
end;

上面一个简单的函数解决了经常会碰到的关于数据列的问题,遇到问题时多多开动脑筋,而不要一味的去找第三方控件,这样长期坚持下去就会真正提高自己的水平,才会从一名程序泥水匠变成真正的软件设计师。

摘自:http://www.bianceng.cn/Programming/Delphi/200710/4777.htm

2012年7月3日星期二

【转】delphi 播放声音 建议采用 异步方式,比较流畅

2008-06-06 08:57
//声明:  sndPlaySound(    lpszSoundName: PChar; {声音文件}    uFlags: UINT{播放选项}  ): BOOL;    //uFlags 参数可选值:  SND_SYNC      = 0; {同步播放, 程序须等到播放完毕才向下执行}  SND_ASYNC     = 1; {异步播放, 在函数返回之后开始播放, 不影响程序继续执行}  SND_NODEFAULT = 2; {声音文件缺失时, 函数自动返回不播放默认声音}  SND_MEMORY    = 4; {播放内存中的声音, 譬如资源文件中的声音}  SND_LOOP      = 8; {循环播放, 需要和 SND_ASYNC 组合使用}  SND_NOSTOP    = 16;{如果当前正在播放声音, 立即返回 False}  
//举例: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; {sndPlaySound 声明在该单元} const s = 'C:\WINDOWS\Media\Windows XP 启动.wav'; //同步播放 procedure TForm1.Button1Click(Sender: TObject); begin sndPlaySound(s, SND_SYNC); Beep; {播放完毕才会执行这句} end; //异步播放 procedure TForm1.Button2Click(Sender: TObject); begin sndPlaySound(s, SND_ASYNC); Beep; {马上会执行这句} end; //反复播放 procedure TForm1.Button3Click(Sender: TObject); begin sndPlaySound(s, SND_LOOP or SND_ASYNC); end; end.
//sndPlaySound 也可以用来播放资源或内存中的声音文件, 参加示例:
http://www.cnblogs.com/del/archive/2008/02/15/1069523.html

【转】学习使用资源文件[9] - WAVE 资源

//rc 文件:  sound1 WAVE "SoundFile1.wav"  sound2 WAVE "SoundFile2.wav"  
//代码: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls; type   TForm1 = class(TForm)     Button1: TButton;     Button2: TButton;     procedure Button1Click(Sender: TObject);     procedure Button2Click(Sender: TObject);   end; var   Form1: TForm1; implementation {$R *.dfm} uses MMSystem; {下面用到的 sndPlaySound、PlaySound 都是在此单元声明的} procedure TForm1.Button1Click(Sender: TObject); var   rs: TResourceStream; begin   rs := TResourceStream.Create(HInstance, 'sound1', 'WAVE');   sndPlaySound(rs.Memory, SND_ASYNC or SND_MEMORY);   rs.Free; end; procedure TForm1.Button2Click(Sender: TObject); var   rs: TResourceStream; begin   rs := TResourceStream.Create(HInstance, 'sound2', 'WAVE');   PlaySound(rs.Memory, HInstance, SND_ASYNC or SND_MEMORY);   rs.Free; end; end.

摘自:http://www.cnblogs.com/del/archive/2008/02/15/1069523.html

2012年7月2日星期一

【转】Delphi 枚举类型元素个数的确定方法

  枚举类型属于序数类型,但我们有时需要确定我们定义的枚举类型中的元素个数,也就是枚举类型的取值范围,但讨论这个问题的前提是“不要指定枚举元素的初始值”时才有意义。在 Delphi 中有两种方法可以做到:

方法一:使用 RTTI

  利用 TypInfo 单元的 GetEnumName() 和 GetEnumValue() 可以遍历任意枚举类型,并获取其名称和值。如果枚举类型指定初始值,将不具备 RTTI 能力,所以不要指定初始值。

uses TypInfo;

procedure TForm1.BtnTestClick(Sender: TObject);
var
    p: PTypeData;
    i: Integer;
    s: String;
    pt: PTypeInfo;
begin
    ListBox1.Items.Clear;
    pt := TypeInfo(TWindowState);
    if pt.Kind <> tkEnumeration then begin
        ShowMessage('不是枚举类型');
        Exit;
    end;

    p := GetTypeData(TypeInfo(TWindowState));

    //将获取的枚举类型信息,以“枚举名 = 枚举值” 的形式加入到 ListBox 中
    ListBox1.Items.beginUpdate;
    try
        for i := p.MinValue to p.MaxValue do begin
            S := GetEnumName(pt,i);
            ListBox1.Items.Values[S] := IntToStr(GetEnumValue(pt, S));
        end;
    finally
        ListBox1.Items.EndUpdate;
    end;
end;

使用 RTTI,速度会慢一些,如果整个程序在运行过程中并不需要 RTTI,可以使用下面的方法。



方法二: 使用 Low(),High(),Ord() 系统函数。使用该方法依然不要指定枚举元素初始值。

type
    TEnum = (a,b,c);

const
    Min = Low(TEnum);
    Max = High(TEnum);

    Count = Ord(Max) + 1;

procedure TForm1.Button1Click(Sender: TObject);
var
    i,j: Integer;
begin
    i := Ord(Min);
    j := Ord(Max);

    ShowMessage(IntToStr(i) + ' ' + IntToStr(j) + ' ' + IntToStr(Count));
end;


摘自:http://apps.hi.baidu.com/share/detail/16452783

2012年7月1日星期日

【转】delphi:语音合成之SpVoiceClass详解

AlertBoundary
取得或设置停顿分界线。

AllowAudioOutputFormatChangesOnNextSet
设置是否允许声音自动调整到合适状态以适应其音频输出。

AudioOutput
.取得或设置当前声音使用的的音频输出对象

AudioOutputStream
取得或设置当前声音使用的的音频输出流对象。

EventInterests
取得或设置当前声音返回的事件类型。

Priority
取得或设置声音的优先级。

Rate
取得或设置阅读的速度。

Status
返回一个ISpeechVoiceStatus 对象用于显示当前阅读和事件的状态

SynchronousSpeakTimeout
取得或设置一个时间间隔,用于标识多久未获得一个输出设备后,一个同步的Speak 和SpeakStream将终止,以毫秒计算。

Voice
取得或设置发音对象。

Volume
取得或设置声音的大小 。




方法
描述

DisplayUI
是否在控制面板中展示详细设置。

GetAudioOutputs
返回一个可用的音频输出标记。

GetVoices
返回一个可用的发音对象。

IsUISupported
决定是否能通过控制棉板的音频设置来控制。

Pause
暂停朗读。.

Resume
恢复暂停,继续播放。

Skip
在当前输入的文本流中向前或向后跳一定距离再播放。

Speak
阅读一个字符串。

SpeakCompleteEvent
得到一个朗读完毕的时间句柄

SpeakStream
朗读一个文本流或一个声音文件。

WaitUntilDone
阻塞进程,直到声音播放完毕或者超时。.

摘自:http://hi.baidu.com/xiaoxiaolq/blog/item/a42fc7ca7e6e854cf31fe7e8.html

【转】将文本保存为音频文件(wav)的方法

★★将文本保存为音频文件(wav)的方法
准备控件:SpVoice,SpFileStream,SaveDialog,Button
Procedure   TForm1.Button.click(sender:TObject);
begin
  savedialog.filter:= 'wave文件|*.wav ';
  if   savedialog.execute   then
    begin
      spfilestream.format.type_:=SAFT32KHz8BitMono;
      spfilestream.open(savedialog1.filename,SSFMCreateForWrite,False);
      SpVoice.allowAudioOutputFormatChangesOnNextSet:=false;
      Spvoice.AudioOutputStream:=SpFilestream.defaultInterface;
      SpVoice.Speak( '祝CSDN的朋友工作顺利! ',1);
      SpVoice.waitUntilDone(-1);
      Spfilestream.close;
    end;
end;

摘自:http://topic.csdn.net/t/20031110/14/2445499.html 【8楼】

[转]DELPHI VCL 控件如何卸载?

附带通用控件安装方法:
----------------------------------------------------------------
基本安装
1、对于单个控件,Componet--> install   component..--> PAS或DCU文件--> install;
2、对于带*.dpk文件的控件包,File--> Open(下拉列表框中选*.dpk)--> install即可;
3、对于带*.bpl文件的控件包,Install   Packages--> Add--> bpl文件名即可;
4、如果以上Install按钮为失效的话,试试Compile按钮;
5、是run   time   lib则在option下的packages下的runtimepackes加之。
        如果编译时提示文件找不到的话,一般是控件的安装目录不在Delphi的Lib目录中,有两种方法可以解决:
1、反安装的源文件拷入到Delphi的Lib目录下;
2、或者Tools--> Environment   Options中把控件源代码路径加入到Delphi的Lib目录中即可。
注意:所安装的控件是否与你所用的Delphi版本相适应。
----------------------------------------------------------------
控件删除
在Component/Install   Packages中删除。  
选Component/configure   Palette…
有pages和components两个区域
双击components区域,选中要删除得控件,下面有得Delete按钮
但系统提供的控件只能Hide,不能delete。
打开控件所在的包文件(*.dpk),从中删除控件那个文件,再重新编译该包即可。
如果是整个控件包都要删除的话,project-> Option-> Packages,删掉那个packages,收工。

摘自:http://topic.csdn.net/t/20041027/23/3497655.html