有一段时间没有更新网站了,最近挺忙的,所以写书的进度慢了一些,两周只写了10多页设计模式相关的内容。希望在接下来的几周能加快进度,赶紧弄完。另外前两天,我被评为了Borland Delphi产品专家,加上这两天北京的非典形势也缓和多了,很高兴。为此公开很久以前写的一篇文章,与大家分享一下我的快乐。
偶然的起因
记得还是在去年情人节的时候,当时一直在为给女朋友送什么礼物而发愁,觉得送花实在没有什么创意,可又不知道什么样的礼物即能给她一个惊喜同事又不昂贵。这时,我的一个好朋友出了一个主意,说不如电话点歌吧,还比较特别。可是如果是通过电台点歌后,再告诉她收听的话就起不到意外的效果了。
就在没有什么好办法的时候,我在Delphi论坛上瞎逛的时候,一个人提出的问题突然启发了我,
问题是关于如果编程实现语音留言和电话按键的记录功能的。我突然想为什么我不能写一个程序来控制电话,然后再给女友打一个传呼,让她回电话,当电话接通后,我的
程序先播放一段事先录制好的话,提示她通过电话按键来选歌,并能提供留言的功能呢。主意一定,我就赶忙查阅这方面的
资料了,一开始朋友们告诉可以通过语音卡来实现这些功能,可是语音卡比较贵,而且我买了后,除了用一次以外以后也不会经常用到,实在是有点浪费,后来网友cced提到他听人说TurboPower公司出的Async Professional控件提供了一组基于Telephone Api的控件可以通过语音Modem来实现类似的功能。这个看来成本就低多了,我的Modem正好是语音Modem,于是我就
下载了Async Professional(官方网www.turbopower.com)试验了一下,果然不同反响,便宜且简单。
开始设计
下面我们就来看看如何利用这组控件实现语音功能,对于我们
程序的应用来说,只需要使用两个TAPI控件TApdComPort和TApdTapiDevice即可,其中TApdComPort控件是一个串口通讯控件,因为Modem是同串口相连接的,因此需要串口通讯控件来进行控制。而TapdTapiDevice则是提供语音功能的核心控件。
首先,新建一个
程序项目,在窗体上放置一个TApdComport控件,设置其属性为AutoOpen:=False;TapiMode=tmOn;这里TapiMode 设定为tmOn 表明TApdComPort 将由同其关联的TApdTapiDevice.控件来控制,而将AutoOpen设定为False 是因为串口的打开和关闭现在可以完全由TAPI来控制了。
然后,在窗体上放置一个TApdTapiDevice控件,设定其Comport属性为前面的TApdComPort控件。设定AnswerOnRing属性为1,表明第一次振铃后就开始由
程序控制电话的应答。设定ShowTapiDevices为True表明当调用控件的SelectDevice方法时,会显示一个选择TAPI设备的对话框。ShowPorts属性为false,表明调用SelectDevice方法不会显示串行口列表。
接下来,本
程序主要是采用有限状态机来控制流程的,下面我们来定义枚举状态
Type
TCurrentState = (csIdle, csWaiting, csConnected, csPlaying, csRecording, sDisconnected);
其中csIdle状态表示电话处于空闲状态,正等待接入。csWaiting则表示电话处于程序控制下,等待接入,如果有电话打入,
程序会自动应答。csConnected则表示有电话打入,处于连接状态,csRecording则用来表示当前处于记录电话留言状态。csDisconnected则表示当前连接挂断了。
程序初始化
下面就是
程序的OnCreate的事件处理函数,非常简单,就是先设置当前状态为csIdle,并设置ApdTapiDevice控件的TrimSeconds属性为5,表示当录音时如果有5秒的沉默时间就挂断。
procedure TFrmMain.FormCreate(Sender: TObject);
var
TeleIni: TIniFile;
begin
CurrentState := csIdle;
ApdTapiDevice.TrimSeconds := 5; //录音时有5秒静音就挂断
CommandList := TStringList.Create;
TeleIni := TIniFile.Create(ExtractFilePath(P