注: 上面的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:111@192.168.200.11: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

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

  1. Hadoop学习笔记—15.HBase框架学习(基础知识篇)

    Hadoop学习笔记-15.HBase框架学习(基础知识篇) HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase ...

  2. C++语言学习笔记15:Clean 垃圾清理插件

    C++语言学习笔记15:Clean 垃圾清理插件 对话框 STET1 图片切换功能 导入位图资源 插入图片控件并修改属性 添加消息处理函数 step2 开发思路及类关系图 step3 添加控件及MFC ...

  3. Linux进程线程学习笔记:运行新程序

    Linux进程线程学习笔记:运行新程序 周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下文并接着运行父进程中的代码,如果我们使新进程不运行原父进程的代码,转而运行另外一 ...

  4. Sharepoint学习笔记---如何在Sharepoint2010网站中整合Crystal Report水晶报表(显示数据 二)...

    在Sharepoint学习笔记---如何在Sharepoint2010网站中整合Crystal Report水晶报表(显示数据一)中,解释了如何把Crystal Report整合到Sharepoint ...

  5. 区块链学习笔记15——ETH状态树

    区块链学习笔记15--ETH状态树 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 引入 要实现的功 ...

  6. oracle复制另一个字段,【学习笔记】Oracle存储过程 表中列不同时动态复制表中数据到另一个表中...

    天萃荷净 分享一篇关于Oracle存储过程实现表之间数据复制功能.两表中列不同,动态的将一表中的数据复制到另一个表中案例 因为要用到回收站功能,删除一条记录,要先放到一个delete表中,以便以后恢复 ...

  7. 数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配

    数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配 引入小题:最短路径 最大流问题(maximum flow problem) ...

  8. 点云学习笔记15——PCL常用的基础代码

    点云学习笔记15--PCL基础 命名规范 常用代码 1.时间计算 2.pcl::PointCloud::Ptr和pcl::PointCloud的两个类相互转换 3.如何查找点云的x,y,z的极值? 4 ...

  9. 10-1Python学习笔记 10-2C语言学习笔记 : 在文本编辑器中新建一个文件, 写几句话来总结一下你至此学到的Python知识

    10-1 Python学习笔记 : 在文本编辑器中新建一个文件, 写几句话来总结一下你至此学到的Python知识, 其中每一行都以"In Python you can"打头. 将这 ...

最新文章

  1. 我们是如何解决复杂系统扩展性问题的
  2. SDUT 1265-马停下过河卒(DFS)
  3. CG CTF WEB 签到题
  4. 学会Python,我们可以从事哪几类工作呢?
  5. ML.NET Cookbook:(10)如何使用模型做出一个预测?
  6. centos桥接模式怎么联网_今日回收 | 互联网+废品回收模式是怎么兴起的呢?
  7. 彻夜怒肝!SpringBoot+Sentinel+Nacos高并发已撸完
  8. 25k英里高速建48个充电走廊,美国电动汽车产业迎来春天
  9. King's Quest - poj 1904(强连通分量+外挂输入输出)
  10. 【每日一题(26)】初等排序算法(3) 插入排序 希尔排序 (更正)
  11. 业务中台--如何设计企业级权限管理系统
  12. 详解三相直流无刷电机驱动器硬件原理图
  13. 基于MODIS数据的NDVI与LST相关性分析(IDL代码实现)
  14. iOS中Instrument的使用
  15. 喹啉羧酸类 DHODH 抑制剂用于治疗急性髓系白血病
  16. 使用ffmpeg在视频中心添加透明水印
  17. pr2020lut导入_pr lut预设怎么安装-PR下导入lut预设的方法 - 河东软件园
  18. linux打包文件夹命令
  19. SysML图例-核聚变
  20. CSS空格和换行的处理

热门文章

  1. 三、Python学习(三)海龟模块turtle使用案列-奥迪图标
  2. 如何在合并多段视频时,共用同一个片头片尾
  3. SDL介绍----2、SDL安全设计核心原则
  4. node 生产的env文件怎么注入_前端各种文件上传攻略,从小图片到大文件断点续传...
  5. android动画sin cos,Android开发中计算器的sin、cos及tan值计算问题分析
  6. 如何使用Excel的数据做条件去数据库查询数据?
  7. 关于RF射频走线的开窗和Soder层的避让
  8. 如何配置路由器接口IP,手把手教你配置DHCP
  9. 风变编程python小课怎么样_风变编程Python小课最近很火,大家学完感受如何?
  10. linux bond设备删除,删除修改bond