freeswitch系列9 rtp

  1. 初始化

rtp在switch_rtp.c中实现,里面不仅包括rtp,还包括跟媒体传输相关的几个组件,rtcp、dtmf、 srtp、zrtp,本次先完成rtp部分。在core初始化的时候,同样会进行rtp初始化。

 

  1. SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool)  
  2. {  
  3. #ifdef ENABLE_ZRTP  
  4.     const char *zid_string = switch_core_get_variable_pdup("switch_serial", pool);  
  5.     const char *zrtp_enabled = switch_core_get_variable_pdup("zrtp_enabled", pool);  
  6.     zrtp_config_t zrtp_config;  
  7.     char zrtp_cache_path[256] = "";  
  8.     zrtp_on = zrtp_enabled ? switch_true(zrtp_enabled) : 0;  
  9. #endif  
  10.     if (global_init) {  
  11.         return;  
  12.     }  
  13.     switch_core_hash_init(&alloc_hash);  
  14. #ifdef ENABLE_SRTP  
  15.     srtp_init();  
  16. #endif  
  17.     switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool);  
  18.     global_init = 1;  
  19. }           );  

初始化通过宏进行加密相关的ZRTP和SRTP初始化,除了这些,还有一个全局初始化标志global_init。

 

  1. switch_rtp_new
  1. SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host,  
  2.                                               switch_port_t rx_port,  
  3.                                               const char *tx_host,  
  4.                                               switch_port_t tx_port,  
  5.                                               switch_payload_t payload,  
  6.                                               uint32_t samples_per_interval,  
  7.                                               uint32_t ms_per_packet,  
  8.                                               switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID], char *timer_name, const char **err, switch_memory_pool_t *pool)  
  9. {  
  10.     switch_rtp_t *rtp_session = NULL;  
  11.   
  12.     if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) {  
  13.         goto end;  
  14.     }  
  15.   
  16.     switch_mutex_lock(rtp_session->flag_mutex);  
  17.   
  18.     if (switch_rtp_set_local_address(rtp_session, rx_host, rx_port, err) != SWITCH_STATUS_SUCCESS) {  
  19.         switch_mutex_unlock(rtp_session->flag_mutex);  
  20.         rtp_session = NULL;  
  21.         goto end;  
  22.     }  
  23.   
  24.     if (switch_rtp_set_remote_address(rtp_session, tx_host, tx_port, 0, SWITCH_TRUE, err) != SWITCH_STATUS_SUCCESS) {  
  25.         switch_mutex_unlock(rtp_session->flag_mutex);  
  26.         rtp_session = NULL;  
  27.         goto end;  
  28.     }  
  29.   
  30.  end:  
  31.   
  32.     if (rtp_session) {  
  33.         switch_mutex_unlock(rtp_session->flag_mutex);  
  34.         rtp_session->ready = 2;  
  35.         rtp_session->rx_host = switch_core_strdup(rtp_session->pool, rx_host);  
  36.         rtp_session->rx_port = rx_port;  
  37.         switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH);  
  38.         switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_DETECT_SSRC);  
  39.     } else {  
  40.         switch_rtp_release_port(rx_host, rx_port);  
  41.     }  
  42.   
  43.     return rtp_session;  
  1.  

 

在新建rtp的时候,先使用create创建rtp实例,然后设置远程和本地的ip:port对。rtp实例的成员很多,这里就先不展开。

 

 

  1. switch_rtp_zerocopy_read_frame

上一章在media提到,会调用switch_rtp_zerocopy_read_frame读一帧,其中的zerocopy表示不拷贝数据,而是返回数据指针。

  1. SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_frame_t *frame, switch_io_flag_t io_flags)  
  2. {  
  3.     int bytes = 0;  
  4.   
  5.     if (!switch_rtp_ready(rtp_session)) {  
  6.         return SWITCH_STATUS_FALSE;  
  7.     }  
  8.   
  9.     bytes = rtp_common_read(rtp_session, &frame->payload, &frame->pmap, &frame->flags, io_flags);  
  10.   
  11.     frame->data = RTP_BODY(rtp_session);  
  12.   
  13.   
  14.         frame->packet = &rtp_session->recv_msg;  
  15.         frame->packetlen = bytes;  
  16.         frame->source = __FILE__;  
  17.   
  18.         switch_set_flag(frame, SFF_RAW_RTP);  
  19.         switch_set_flag(frame, SFF_EXTERNAL);  
  20.         if (frame->payload == rtp_session->recv_te) {  
  21.             switch_set_flag(frame, SFF_RFC2833);  
  22.         }  
  23.         frame->timestamp = ntohl(rtp_session->last_rtp_hdr.ts);  
  24.         frame->seq = (uint16_t) ntohs((uint16_t) rtp_session->last_rtp_hdr.seq);  
  25.         frame->ssrc = ntohl(rtp_session->last_rtp_hdr.ssrc);  
  26.         frame->m = rtp_session->last_rtp_hdr.m ? SWITCH_TRUE : SWITCH_FALSE;  
  27.   
  28.     frame->datalen = bytes;  
  29.     return SWITCH_STATUS_SUCCESS;  
  30. }  

 

调用rtp_common_read读取一个包,然后填充frame指针。data成员指向读到的数据,packet指向rtp头,其它的如ssrc啥的就不说了。

rtp_common_read会根据不同的类型、rtp rtcp srtp zrtp调用不同的读函数,这里只看rtp。

 

  1. while (switch_poll(rtp_session->read_pollfd, 1, &fdr, 0) == SWITCH_STATUS_SUCCESS) {  
  2.     status = read_rtp_packet(rtp_session, &bytes, flags, pmapP, SWITCH_STATUS_SUCCESS, SWITCH_FALSE);  

 

read_rtp_packet里面调用底层的socket读数据。

  1. if (poll_status == SWITCH_STATUS_SUCCESS) {  
  2.     status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);  
  3. else {  
  4.     *bytes = 0;  

 

 

  1. switch_rtp_write_frame

rtp写一帧跟读相反,先构造一个switch_frame_t结构体,调用底层的socket去发送,然后更新统计信息。这些统计信息主要用于rtcp、jitterbuffer等。

  1. if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) {  
  2.     return -1;  
  3. }  
  4.   
  5.   
  6. rtp_session->stats.outbound.raw_bytes += bytes;  
  7. rtp_session->stats.outbound.media_bytes += bytes;  
  8. rtp_session->stats.outbound.media_packet_count++;  
  9. rtp_session->stats.outbound.packet_count++;  
  10. return (int) bytes;  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值