freeswitch系列8 media

  1. 初始化

media在switch_core_media.c实现,完成媒体协商的功能。这部分本来是在mod_sofia实现的,后来增加了webrtc支持,就独立出来。还有一个media_bug.c,实现监控媒体。在core初始化的时候,会调用media的初始化。

 

  1. SWITCH_DECLARE(void) switch_core_media_init(void)  
  2. {  
  3.     switch_core_gen_certs(DTLS_SRTP_FNAME ".pem");    
  4.   
  5.     video_globals.cpu_count = switch_core_cpu_count();  
  6.     video_globals.cur_cpu = 0;  
  7.   
  8.     switch_core_new_memory_pool(&video_globals.pool);  
  9.     switch_mutex_init(&video_globals.mutex, SWITCH_MUTEX_NESTED, video_globals.pool);  
  10.   

这里主要是跟视频相关的一些初始化,我们主要关注音频,因此忽略。

  1. 数据结构

media定义了音频/视频两种媒体类型

  1. typedef enum {  
  2.     SWITCH_MEDIA_TYPE_AUDIO,  
  3.     SWITCH_MEDIA_TYPE_VIDEO  
  4. } switch_media_type_t;  
  5. #define SWITCH_MEDIA_TYPE_TOTAL 2 

 

每个session定义一个媒体句柄,媒体句柄隐藏了SDP媒体协商细节,里面有音频视频组成的引擎数组。

  1. struct switch_media_handle_s {  
  2.     switch_core_session_t *session;  
  3.     switch_channel_t *channel;  
  4.     switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL];  //媒体引擎
  5.     const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];  
  6.     switch_core_media_params_t *mparams;  
  7. }; 

 

  1. switch_core_media_activate_rtp

启动rtp收发,先获取音视频的媒体引擎

  1. a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];  
  2. v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];  

 

设置codec

  1. if ((status = switch_core_media_set_codec(session, 0, smh->mparams->codec_flags)) != SWITCH_STATUS_SUCCESS) {  
  2.     goto end;  
  3. }  
  4.   
  5. switch_core_media_set_video_codec(session, 0);  

 

创建引擎的rtp_session

  1. a_engine->rtp_session = switch_rtp_new(a_engine->local_sdp_ip,  
  2.                                    a_engine->local_sdp_port,  
  3.                                    a_engine->cur_payload_map->remote_sdp_ip,  
  4.                                    a_engine->cur_payload_map->remote_sdp_port,  
  5.                                    a_engine->cur_payload_map->pt,  
  6.                                    a_engine->read_impl.samples_per_packet,  
  7.                                    a_engine->cur_payload_map->codec_ms * 1000,  
  8.                 flags, timer_name, &err, switch_core_session_get_pool(session));  

 

激活ICE,这里猜测跟NAT相关的网络。

  1.             switch_rtp_activate_ice(a_engine->rtp_session,   
  2.                                     a_engine->ice_in.ufrag,  
  3.                                     a_engine->ice_out.ufrag,  
  4.                                     a_engine->ice_out.pwd,  
  5.                                     a_engine->ice_in.pwd,  
  6.                                     IPR_RTP,  
  7. #ifdef GOOGLE_ICE  
  8.                                     ICE_GOOGLE_JINGLE,  
  9.                                     NULL  
  10. #else  
  11.                                     switch_ice_direction(a_engine, session) ==   
  12.                                     SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),  
  13.                                     &a_engine->ice_in  
  14. #endif  
  15.                                     );  

 

激活RTCP

switch_rtp_activate_rtcp(a_engine->rtp_session, interval, remote_rtcp_port, a_engine->rtcp_mux > 0);

 

 

  1. switch_core_media_read_frame

获取媒体引擎

  1. switch_media_handle_t *smh;  
  2.   
  3. if (!(smh = session->media_handle)) {  
  4.     return SWITCH_STATUS_FALSE;  
  5. }  
  6.   
  7. engine = &smh->engines[type];  

 

调用底层读取一个RTP包

  1. while (smh->media_flags[SCMF_RUNNING] && engine->read_frame.datalen == 0) {  
  2.     engine->read_frame.flags = SFF_NONE;  
  3.     status = switch_rtp_zerocopy_read_frame(engine->rtp_session, &engine->read_frame, flags);  

 

同样读取一个RTCP包

  1. /* Try to read an RTCP frame, if successful raise an event */  
  2. if (switch_rtcp_zerocopy_read_frame(engine->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) {  
  3.     switch_event_t *event;  

 

正常后把帧传出去

  1. /* Fast PASS! */  
  2. if (switch_test_flag((&engine->read_frame), SFF_PROXY_PACKET)) {  
  3.     *frame = &engine->read_frame;  
  4.     switch_goto_status(SWITCH_STATUS_SUCCESS, end);  

 

 

  1. switch_core_media_write_frame

获取媒体引擎

  1. switch_media_handle_t *smh;  
  2.   
  3. if (!(smh = session->media_handle)) {  
  4.     return SWITCH_STATUS_FALSE;  
  5. }  
  6.   
  7. engine = &smh->engines[type];  

 

调用底层RTP接口发送RTP包

  1. if (switch_rtp_write_frame(engine->rtp_session, frame) < 0) {  
  2.     status = SWITCH_STATUS_FALSE;  
  3. }  

 

 

你可能感兴趣的:(freeswitch,freeswitch,sip)