PJSIP学习笔记15 -- PJSUA应用程序中的会议桥



   注: 上面的tpport,是我为了帮助理解对应关系,为app_config增加的成员变量, 源码中并无这个成员。

可以使用PJSUA程序控制台命令cl来查看系统中的conference_port
未拨打电话时,如下:
Port #00[24KHz/20ms/1]         Master/sound  transmitting to:
Port #01[24KHz/20ms/1]             ringback  transmitting to:
Port #02[24KHz/20ms/1]                 ring  transmitting to:
拨打电话,并成功接通后如下:
Port #00[24KHz/20ms/1]              default  transmitting to: #3
Port #01[24KHz/20ms/1]             ringback  transmitting to:
Port #02[24KHz/20ms/1]                 ring  transmitting to:
Port #03[ 8KHz/20ms/1] sip:[email protected]:5062  transmitting to: #0


    可见:在默认配置条件下,pjsua程序启动后,只存在3个有效的会议桥端口, 通过跟踪调试app_init()函数也可以证实这一点;我们的个性化的铃声音效,可以通过添加wave文件的player连接到player.slot来实现。

    pjsua程序提供了会议桥端口的connect/disconnect命令, 可以实现会议桥的个端口的媒体数据的流动方向,我们可以使用这两个命令来加深对会议桥工作方式的理解。

    顺便写一句备忘: 关于彩铃,也就是早期媒体,可以看看这篇文章; 另外关于PRACK,相关的编准RFC5626,在SIP账户的配置参数中 use_rfc5626,与这个有关系,180响应携带SDP的原因应该与早期媒体由关系。

   pjsua还为我们分别演示了,在通话建立后,通过DTMF音频或INFO消息向对方发送按键音效的方法, 具体分别参考ui_send_dtmf_2833()函数和ui_send_dtmf_info()函数

    pjsua_call_send_request(current_call, &SIP_INFO, &msg_data_);被用来发送一个dialog内的SIP INFO信息
    pjsua_call_dial_dtmf(current_call, &digits);                 被用来发送一个dialog内的DTMF/RTP包

===== 下面重点分析一下DTMF音频的收发

     RF2833规定的DTMF字符表:
    /* RFC 2833 digit */
    static const char digitmap[17] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D', 'R'};
       使用DTMF事件event->event做索引, 可以查询对端发送的数字是哪一个。

    1)DTMF接收端的handle_incoming_dtmf():
        在handle_incoming_dtmf代码中: pjmedia_rtp_dtmf_event *event = (pjmedia_rtp_dtmf_event*) payload;
                说明DTMF/RRT负载包净负载是一个结构化的数据,共4个字节,负载类型101(---通过抓包工具验证)                
        解析出的DTMF数据,如果注册了回调函数, 则使用回调函数处理接收的事件, 否则数据包保存在stream->rx_dtmf_buf[]缓冲区里面
          *** pjsua程序中,该回调函数在pjsua_aud_channel_update()函数中被设置, 指向函数dtmf_callback()
                     该函数使用应用层pjsua_var.ua_cfg.cb.on_dtmf_digit回调函数继续向应用层回调,我们来看看应用层回调的设置:
            app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; 这个回调函数只是提供了一个打印log的操作。
          
        ***为什么dtmf_event的RTP负载类型是101?  在SDP解析函数get_audio_codec_info_param()中,由这么一句:
           si->rx_event_pt = pj_strtoul(&r.pt);

                

    2)DTMF发送端    
       pjsua_call_dial_dtmf(current_call, &digits);被用来发送一个dialog内的DTMF音频媒体
            我们来看看pjsua_call_dial_dtmf的内部实现的关键调用:
       pjmedia_stream_dial_dtmf(call->media[call->audio_idx].strm.a.stream, digits);
            对于每个pj_mediastream存在一个DTMF发送缓冲区,pjmedia_stream_dial_dtmf用来填充这个缓冲区:
                stream->tx_dtmf_buf[stream->tx_dtmf_count+i].event = pt;
                stream->tx_dtmf_buf[stream->tx_dtmf_count+i].duration = 0;
                stream->tx_dtmf_buf[stream->tx_dtmf_count+i].ebit_cnt = 0;
            这个缓冲区的数据将通过如下的途径被使用:
                  put_frame()->put_frame_imp()->create_dtmf_payload()->pjmedia_rtp_encode_rtp()


        对于DTMF:
        create_dtmf_payload函数每次构建一个4字节的event/RTP数据包的payload数据
        tx_dtmf_buf中的每个event会被重复发送多次(12次),
             在12次重复发送过程中, RTP时间标签不会发生变化,但RTP序列号或连续递增
                        并且,每次发送的event数据中duration会增加固定增量,该增量使用宏PJMEDIA_PIA_SPF计算, 计算原理暂时还没高明白
                         当发送下一个DTMF字符时, 下一个DTMF字符时间标签的增量等于,上一个DTMF字符的最后一个event数据序列中的duration -- 尚未仔细验证,大方向是这样的
           
        负载长度永远为4(负载是一个结构体, 结构体长度必须是4, 程序中存在如下代码:pj_assert(sizeof(pjmedia_rtp_dtmf_event) == 4))
                负载的赋值如下:
                    event->event = (pj_uint8_t)digit->event; //按键字符表digitmap[]数组索引
                    event->e_vol = 10;
                    event->duration = pj_htons((pj_uint16_t)digit->duration);//这个值像时间标签一样是单向递增的

       3)关于DTMF的频率成分



=== 关于电话音效, 主要在on_call_state()回调中


         回铃音: ringback_start() ->pjsua_conf_connect(app_config.ringback_slot, 0);   //0是master_port所在端口
          ring_stop () ->pjsua_conf_disconnect(app_config.ringback_slot, 0);   //0是master_port所在端口 -----注意是ring_stop,不是ringback_stop

        震铃音: ring_start() ->pjsua_conf_connect(app_config.ring_slot, 0);   //0是master_port所在端口
          ring_stop () ->pjsua_conf_disconnect(app_config.ring_slot, 0);   //0是master_port所在端口

         忙音(busy 486):   未实现


传统话机的铃音标准GB3380:http://ishare.iask.sina.com.cn/f/13367325.html

本机震铃音,给个下载网址:http://sc.chinaz.com/tag_yinxiao/DianHuaLingSheng.html








猜你喜欢

转载自blog.csdn.net/twd_1991/article/details/80776672