Asterisk Summary - 4

看了前面三小节的内容有什么收获和感想呢?是不是在为自己的第一个iax客户端程序能运行并接入asterisk server并连接到指定的电话号码而cheer up呢?是不是还想完善一下这个简单的testcall呢?比如实现holdunhold call,实现多条线路接入呢?开动你的大脑,想想怎么实现这些现实生活中常见的功能吧!!!!

           1. HOLD & UNHOLD

           其实在iaxclient.dll中已经实现了hold and unhold call,只需要调用两个函数。

           int  iaxc_quelch (int callNo, int MOH)  /* Causes the audio channel for callNo to QUELCH (be squelched).    */

int  iaxc_unquelch (int callNo)        /*Causes the audio channel for callNo to be UNQUELCH (unsquelched). */

iaxc_quelch() callNo可以是当前selectedcallNoMOHMusic On Hold)只需要>0就可以啦,通常为1,这样callNo就将hold住了,同时播放music on hold

iaxc_unquelch()callNo是之前传入 iaxc_quelch() callNo,这样讲unhold当前的callNo

2. Multiline access in iax client

IDEFISK是一款较出名的iax/sip soft phone,它实现了五条线的切换。为了让自己的程序也可以实现这样的功能,开始googling吧,遗憾的是在google上搜索的资料并没有太多的information,有的人说是要配置sip.conf / phone.conf,要switch支持,各种说法都有。我也考虑过,发现在上一节的testcall中第二次但电话进入后都是busytone,于是改写了extensions.conf中的from_sip extension如下:

[from_sip]

exten => _XXXXXX,1,Set(DISTRICT=cra)

exten => _XXXXXX,n,MixMonitor(/dev/shm/${DISTRICT}/${STRFTIME(${EPOCH},,%y%m%d)}/${CALLERID(ani)}.00.${STRFTIME(${EPOCH},,%Y%m%d%H%M%S)}.${EXTEN}.${UNIQUEID}.wav49,bv(0)V(0))  ;call rec

exten => _XXXXXX,n,Answer()

exten => _XXXXXX,n,Dial(IAX2/${EXTEN},30,rmM(sendUID,${UNIQUEID}))

exten => _XXXXXX,n,Hangup()

           主要是commentsif busy then hangup 的设定。

           再次运行testcall,发现第二个接入电话无法进入并马上断线,同时testcall输出:

IAXCLIENT: -1

Incoming Call, but no appearances

IAXCLIENT: Event (type 2) for a non-existant session. Dropping Incoming Call, but no appearances

asterisk serverCLI上输出为:

-- Called 111001

-- Call accepted by 192.168.121.181 (format gsm)

-- Format for call is gsm

-- IAX2/111001-3609 is busy

-- Hungup 'IAX2/111001-3609'

== Everyone is busy/congested at this time (1:1/0/0)

-- Executing [111001@from_sip:5] Hangup("SIP/87654321hk-08bcb290", "") in new stack

== Spawn extension (from_sip, 111001, 5) exited non-zero on 'SIP/35984523hk-08bcb290'

== End MixMonitor Recording SIP/87654321hk-08bcb290

-- Hungup 'IAX2/111001-2939'

== Spawn extension (from_sip, 111001, 4) exited non-zero on 'SIP/87654321hk-08b262d8'

== End MixMonitor Recording SIP/87654321hk-08b262d8

           为了试验实现接入多条线是否需要conf文件的支持,我使用了知名的IDEFISK软件,正确配置了相关的iax设定后(参考http://www.asteriskguru.com/tutorials/idefisk_softphone.html),再次用多个电话呼叫87654321,发现IDEFISK在现有的asterisk conf不变的情况下可以使用多条线路,到这里,我们可以下结论啦:实现多条线路的接入不需要改变默认的asterisk cong 文件设置,而应该是在客户端编程实现的。 那么我们的程序到底又应该怎么样实现呢?????

           带着上面5个大问号,我有开始googling啦!不断的键入iax 2 line phone asterisk multiline phone等等,最终还是收获不大。正在郁闷之极是,查看lib iaxclient的在线帮助页面,不断的查看每一个函数的解释和使用,发现我视乎遗漏了什么,但我查看iaxc_select_call()的实现代码是,发现有一个重要的变量-- max_callsmax_calls有是什么呢?是否和我内心所想的一样呢?于是在iaxclient-2.1beta3/lib/下搜索max_calls,发现是在iaxc_initialize()中赋值的,同时其他很多的iaxc_ 函数都要对max_calls做检查。实现multiline接入的关键是否就在这个max_calls呢?为此需要查看iaxc_initialize()的解释:

           int iaxc_initialize  ( int  num_calls   )

Initializes the IAXClient library.

Parameters: num_calls  The maximum number of simultaneous calls to handle.

This initializes the IAXClient

           在查看源文件iaxclient_lib.c.实现如下:

EXPORT int iaxc_initialize(int num_calls)
{
  
                    int i;
                    int port;
 
                    os_init();
 
                    setup_jb_output();
 
                    MUTEXINIT(&iaxc_lock);
                    MUTEXINIT(&event_queue_lock);
 
                    iaxc_set_audio_prefs(0);
 
                    if ( iaxc_recvfrom != (iaxc_recvfrom_t)recvfrom )
                                         iax_set_networking(iaxc_sendto, iaxc_recvfrom);
 
                    /* Note that iax_init() only sets up the receive port when the
                     * sendto/recvfrom functions have not been replaced. We need
                     * to call iaxc_init in either case because there is other
                     * initialization beyond the socket setup that needs to be done.
                     */
                    if ( (port = iax_init(source_udp_port)) < 0 )
                    {
   
                                         iaxci_usermsg(IAXC_ERROR,
                                                                                 "Fatal error: failed to initialize iax with port %d",
                                                                                 port);
                                         return -1;
                    }
 
                    if ( iaxc_recvfrom == (iaxc_recvfrom_t)recvfrom )
                                         iaxci_bound_port = port;
                    else
                                         iaxci_bound_port = -1;
 
                    /* tweak the jitterbuffer settings */
                    iax_set_jb_target_extra( jb_target_extra );
 
                    max_calls = num_calls;
                    /* initialize calls */
                    if ( max_calls <= 0 )
                                         max_calls = 1; /* 0 == Default? */
 
                    /* calloc zeroes for us */
                    calls = (struct iaxc_call *)calloc(sizeof(struct iaxc_call), max_calls);
                    if ( !calls )
                    {
   
                                         iaxci_usermsg(IAXC_ERROR, "Fatal error: can't allocate memory");
                                         return -1;
                    }
 
                    selected_call = -1;
 
                    for ( i = 0; i < max_calls; i++ )
                    {
   
                                         strncpy(calls[i].callerid_name,   DEFAULT_CALLERID_NAME,   IAXC_EVENT_BUFSIZ);
                                         strncpy(calls[i].callerid_number, DEFAULT_CALLERID_NUMBER, IAXC_EVENT_BUFSIZ);
                    }
 
                    if ( !test_mode )
                    {
   
#ifndef AUDIO_ALSA
                                         if ( pa_initialize(&audio_driver, 8000) )
                                         {
   
                                                             iaxci_usermsg(IAXC_ERROR, "failed pa_initialize");
                                                             return -1;
                                         }
#else
                                         /* TODO: It is unknown whether this stuff for direct access to
                                         * alsa should be left in iaxclient. We're leaving it in here for
                                         * the time being, but unless it becomes clear that someone cares
                                         * about having it, it will be removed. Also note that portaudio
                                         * is capable of using alsa. This is another reason why this
                                         * direct alsa access may be unneeded.
                                         */
                                         if ( alsa_initialize(&audio_driver, 8000) )
                                                             return -1;
#endif
                    }
#ifdef USE_VIDEO
                    if ( video_initialize() )
                                         iaxci_usermsg(IAXC_ERROR,
                                                                                 "iaxc_initialize: cannot initialize video!/n");
#endif
 
                    /* Default audio format capabilities */
                    audio_format_capability =
                        IAXC_FORMAT_ULAW |
                        IAXC_FORMAT_ALAW |
#ifdef CODEC_GSM
                        IAXC_FORMAT_GSM |
#endif
                        IAXC_FORMAT_SPEEX;
                    audio_format_preferred = IAXC_FORMAT_SPEEX;
 
                    return 0;
}
 

           认真看完这些代码后更加肯定了实现多条线接入的话在初始化iaxc的时候就要传入线路数,为此改写testcall中的相关代码:

           #define MAX_ALLOW_LINE  2

if ( iaxc_initialize(MAX_ALLOW_LINE) ) // init iax client lib, max 2 calls in

                     fatal_error("cannot initialize iaxclient!");

           重新编译运行并多次呼叫87654321,此时第二条线有电话接通的嘟嘟声,同时testcall的输出有这一项:IAXCLIENT: Incoming call on line 1

           到这里,你是否对实现多条线接入iax client而有很好的想法呢,lets getting down to the sold work now.

           为实现这些功能的代码,我增加了一些变量:

int call_no=-1; //record current ringing call no

int curr_no[MAX_ALLOW_LINE]={IAXC_CALL_STATE_FREE ,IAXC_CALL_STATE_FREE }; //store line state

           另外为了更好的观察这些iaxclient call event,我屏蔽了很多其他eventconsole的输出。同时在接入line2的时候应该holdline 1,在结束line2通话后应回复line1的通话,为此改写了state_event_callback()如下:

int state_event_callback(struct iaxc_ev_call_state call){
  
                    int i=0;
 
                    printf("receive call[%d] state event: 0X%p/n",call.callNo,call.state);
    if((call.state & IAXC_CALL_STATE_RINGING))
    {
   
                                         curr_no[call.callNo]=call.state;
                                         call_no = call.callNo;
                                         display_line_state();
                                         if(call.state & IAXC_CALL_STATE_OUTGOING)
                                         {
   
                                                             printf("Make outgoing call call no.[%d].../n",call.callNo);
                                                             printf("Remote:[%s][%s] Local:[%s][%s]/n",
                                                                                 call.remote,call.remote_name,call.local,call.local_context);
                                         }
                                         else
                                         {
   
                                                             printf("Receiving Incoming Call Request call no.[%d].../n",call.callNo); 
                                                             printf("Remote:[%s][%s] Local:[%s][%s]/n",
                                                                                 call.remote,call.remote_name,call.local,call.local_context);
                                                             if ( intercom )
                                                             {
   
                                                                                 printf("Intercom mode, answer automatically/n");
                                                                                 return iaxc_select_call(call.callNo);
                                                             }
                                         }
    }
                    else if(call.state & IAXC_CALL_STATE_SELECTED  )
                    {
   
                                         curr_no[call.callNo]=call.state;
                                         display_line_state();
                                         if(call.state & IAXC_CALL_STATE_OUTGOING )
                                                             printf("IAX Out conn [%d] - Remote:[%s][%s] Local:[%s][%s]/n",
                                                             call.callNo,call.remote,call.remote_name,call.local,call.local_context);
                                         else
                                                             printf("IAX In conn [%d] - Remote:[%s][%s] Local:[%s][%s]/n",
                                                             call.callNo,call.remote,call.remote_name,call.local,call.local_context);
                    }
                    else if (call.state == IAXC_CALL_STATE_FREE )
                    {
    
                                         if(curr_no[call.callNo] == IAXC_CALL_STATE_FREE)  //already free?
                                                             return 0;
                                         curr_no[call.callNo]=call.state;
                                         printf("call [%d] free now! (%d)/n",call.callNo,iaxc_selected_call());
                                         display_line_state();
                                         if(call.callNo != iaxc_selected_call())//not the current call hang up
                                                             return 0;
                                         printf("we're going to select another waiting call/n");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值