<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Doubango ims 框架 分析之 多媒體部分

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    序言

    RTP提供帶有實時特性的端對端數據傳輸服務,傳輸的數據如:交互式的音頻和視頻。那些服務包括有效載荷類型定義,序列號,時間戳和傳輸監測控制。應用程序在UDP上運行RTP來使用它的多路技術和checksum服務。2種協議都提供傳輸協議的部分功能。

    RTP本身沒有提供任何的機制來確保實時的傳輸或其他的服務質量保證,而是由低層的服務來完成。它不保證傳輸或防止亂序傳輸,它不假定下層網絡是否可靠,是否按順序傳送數據包。RTP包含的序列號允許接受方重構發送方的數據包順序,但序列號也用來確定一個數據包的正確位置,例如,在視頻解碼的時候不用按順序的對數據包進行解碼。

     

    1. 介紹

    doubango框架中tinyRTP文件夾實現RTP/RTCP/RTSP協議棧,目前只實現了

    RTP,RTCP;RTSP還沒實現。Rtp用來在網絡上傳輸音頻視頻,協議棧實現時主要在音視頻包的封裝,拆包。

     

    1. rtp包由消息頭及消息體組成,消息頭的結構封裝

    typedefstruct trtp_rtp_header_s 文件trtp_rtp_header.h

     

    {

     

    TSK_DECLARE_OBJECT;

     

    /*RFC 3550 section 5.1 - RTP Fixed Header Fields

     

    0 1 2 3

     

    01 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

     

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     

    |V=2|P|X| CC |M| PT | sequence number |

     

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     

    | timestamp |

     

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     

    | synchronization source (SSRC) identifier |

     

    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

     

    | contributing source (CSRC) identifiers |

     

    | .... |

     

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     

    */

     

    unsignedversion:2;

     

    //版本(V):2比特 此域定義了RTP的版本。此協議定義的版本是2。(值1被RTP草案版本使用,值0用在最初"vat"語音工具使用的協議中。) 

     

    unsignedpadding:1;

     

    //填充(P):1比特 若填料比特被設置,則此包包含一到多個附加在末端的填充比特,填充比特不算作負載的一部分。填充的最后一個字節指明可以忽略多少個填充比特。填充可能用于某些具有固定長度的加密算法,或者用于在底層數據單元中傳輸多個RTP包。

     

    unsignedextension:1;

    //擴展

    //擴展(X):1比特 若設置擴展比特,固定頭(僅)后面跟隨一個頭擴展。 

    unsignedcsrc_count:4;

     

     

    unsignedmarker:1;

    //標志位

    unsignedpayload_type:7;

    //負載類型,即承載的語音編碼類型

    //負載類型(PT):7比特 此域定義了負載的格式,由具體應用決定其解釋。協議可以規定負載類型碼和負載格式之間一個默認的匹配。其他的負載類型碼可以通過非RTP方法動態定義。RTP發送端在任意給定時間發出一個單獨的RTP負載類型;此域不用來復用不同的媒體流。

    uint16_tseq_num;

    //序列號,重新組包

    //序列號(sequencenumber):16比特 每發送一個RTP數據包,序列號加1,接收端可以據此檢測丟包和重建包序列。序列號的初始值是隨機的(不可預測),以使即便在源本身不加密時(有時包要通過翻譯器,它會這樣做),對加密算法泛知的普通文本攻擊也會更加困難。 

    uint32_ttimestamp;

    //時間戳,負責流同步

    uint32_tssrc;

    //同步源標識,32比特 用以識別同步源。標識符被隨機生成,以使在同一個RTP會話期中沒有任何兩個同步源有相同的SSRC識別符。盡管多個源選擇同一個SSRC識別符的概率很低,所有RTP實現工具都必須準備檢測和解決沖突。若一個源改變本身的源傳輸地址,必須選擇新的SSRC識別符,以避免被當作一個環路源。

    uint32_tcsrc[15];

    //貢獻源標識

    }

    trtp_rtp_header_t;

     

     

    1. rtp包結構,文件trtp_rtp_packet.h

    typedefstruct trtp_rtp_packet_s

    1. {

    2. TSK_DECLARE_OBJECT;

    3.  

    4. trtp_rtp_header_t*header; //包頭

    5.  

    6. struct{

    7. void*data;

    8. constvoid* data_const;

    9. tsk_size_tsize;

    10. }payload; //負載,即承載內容

    11.  

    12. /*extension header as per RFC 3550 section 5.3.1 */

    13. struct{

    14. void*data;

    15. tsk_size_tsize; /* contains the first two 16-bit fields */

    16. }extension;

    17. }

    18. trtp_rtp_packet_t;

     

    1. rtp包的控制

     

    上面兩個結構用來標示一個rtp包,同時提供了包的解析,創建等函數。

    結構trtp_manager_s負責rtp.rtcp包的管理,是更高層的抽象,上層應用直接通過trtp_manager_s提供的api控制

    rtp包,比如在網絡上發送音頻數據,在音頻session結構中包含trtp_manager_s用來管理經過封裝的rtp包。

    /**RTP/RTCP manager */

    typedefstruct trtp_manager_s

    {

    TSK_DECLARE_OBJECT;

     

    struct{

    uint16_tseq_num;

    uint32_ttimestamp;

    uint32_tssrc;

    uint8_tpayload_type;

     

    char*remote_ip;

    tnet_port_tremote_port;

    structsockaddr_storage remote_addr;

     

    char*public_ip;

    tnet_port_tpublic_port;

     

    constvoid* callback_data;

    trtp_manager_rtp_cb_fcallback;

    }rtp;

     

    struct{

    char*remote_ip;

    tnet_port_tremote_port;

    structsockaddr_storage remote_addr;

    tnet_socket_t*local_socket;

     

    char*public_ip;

    tnet_port_tpublic_port;

     

    constvoid* callback_data;

    trtp_manager_rtcp_cb_fcallback;

    }rtcp;

     

    char*local_ip;

    tsk_bool_tipv6;

    tsk_bool_tstarted;

    tsk_bool_tenable_rtcp;

    tsk_bool_tsocket_disabled;

    tnet_transport_t*transport;

    }

    trtp_manager_t;

     

    1. tdav是音視頻會話的抽象層,負責傳輸層的啟動,音頻會話,視頻會話,各種編碼的注冊。

     

     

     

     

    對于音頻/視頻會話(session)被tmedia_session_mgr_t管理,而tmedia_session_mgr_t則具體由sip信令控制會話的狀態。比如sip客戶端請求時通過tmedia_session_mgr_t構造自己的sdp信息要借助此結構,當客戶端對invite作ACK應答時同樣要指定自己的媒體信息。整個rtp流的啟動入口都由tmedia_session_mgr_t控制。

    各種媒體會話以插件的形式注冊,如音頻會話在啟動時注冊到tmedia_session_mgr_t的插件鏈表,并綁定start,stop,prepare回調。tmedia_session_mgr_t為sip信令控制媒體流的接口。

     

    tmedia_session_plugin_def_t為音頻視頻抽象接口,指定回調。如音頻會話,內部會實現相應的回調函數。

    /**Virtual table used to define a session plugin */

    typedefstruct tmedia_session_plugin_def_s

    {

    //!object definition used to create an instance of the session

    consttsk_object_def_t* objdef;

     

    //!the type of the session

    tmedia_type_ttype;

    //!the media name. e.g. "audio", "video", "message","image" etc.

    constchar* media;

     

    int(*set) (tmedia_session_t* , const tmedia_param_t*);

    int(* prepare) (tmedia_session_t* );

    int(* start) (tmedia_session_t* );

    int(* pause) (tmedia_session_t* );

    int(* stop) (tmedia_session_t* );

     

    struct{/* Special case */

    int(* send_dtmf) (tmedia_session_t*, uint8_t );

    }audio;

     

    consttsdp_header_M_t* (* get_local_offer) (tmedia_session_t* );

    /*return zero if can handle the ro and non-zero otherwise */

    int(* set_remote_offer) (tmedia_session_t* , const tsdp_header_M_t* );

    }

    tmedia_session_plugin_def_t;

     

    tmedia_session_t為會話的抽象層,包含tmedia_session_plugin_def_t,

    /**Base objct used for all media sessions */

    typedefstruct tmedia_session_s

    {

    TSK_DECLARE_OBJECT;

     

    //!unique id. If you want to modifiy this field then you must use @reftmedia_session_get_unique_id()

    uint64_tid;

    //!session type

    tmedia_type_ttype;

    //!list of codecs managed by this session

    tmedia_codecs_L_t*codecs;

    //!negociated codec

    tmedia_codecs_L_t*neg_codecs;

    //!whether the ro have been prepared (up to the manager to update thevalue)

    tsk_bool_tro_changed;

    //!whether the session have been initialized (up to the manager toupdate the value)

    tsk_bool_tinitialized;

    //!whether the session have been prepared (up to the manager to updatethe value)

    tsk_bool_tprepared;

    //!QoS

    tmedia_qos_tline_t*qos;

    //!bandwidth level

    tmedia_bandwidth_level_tbl;

     

    struct{

    tsdp_header_M_t*lo;

    tsdp_header_M_t*ro;

    }M;

     

    //!plugin used to create the session

    conststruct tmedia_session_plugin_def_s* plugin;

    }

    tmedia_session_t;

     

     

     

     

    sipsession

     

     

     

     

    trtp_manager_t

     

     

     

    tmedia_session_t tmedia_session_plugin_def_s

     

     

     

     

     

     

     

     

    使用過程:

    tdav_init注冊音頻,視頻,多媒體session;注冊支持的編碼類型,注冊支持的媒體信息承載類型(文本,流等)。

    tdav_init-> register sessions, codecs.

     

     

    tmedia_session_mgr_create-> tmedia_session_mgr_ctor ,sessions,qos,sdp.

     

    _tmedia_session_mgr_load_sessions,創建音視頻會話。

     

    tmedia_session_create,創建具體會話插件類型,tdav_session_video/audio_ctor

     

    tmedia_session_init,初始化

     

    tmedia_session_load_codecs,此會話支持的編碼類型

     

    tmedia_codec_create ,穿件具體編碼類型。

     

    創建過程

     

     

     

     

     

     

     

    準備階段

    trtp_manager_prepare,指定傳輸層接收數據回調trtp_transport_layer_cb

    tdav_session_audio_prepare,trtp_manager_create,trtp_manager_set_rtp_callback

    tnet_transport_create

    tnet_transport_set_callback

     

    啟動

     

    tmedia_session_mgr_start(),啟動所有上面創建的會話類型,啟動之前一定要設置sdp信息

    (Startsthe session manager by

    startingall underlying sessions.You should set

    bothremote and local offers before calling this

    session->plugin->start(),如視頻會話啟動 ,tdav_session_video/audio.c

     

    trtp_manager_set_rtp_remote, 設置對端ip,port,后續發送rtp包時構造包頭用

     

    trtp_manager_set_payload_type,設置此次會話用什么編碼類型,編碼類型通過協商后選擇最佳

    trtp_manager_start,啟動rtp,rtcp包管理,

    tnet_transport_start,啟動傳輸層線程,綁定socket地址,開始接收udp數據, tnet_transport_mainthread

     

     

     

     

    請求或響應中sdp與codec匹配過程

    tmedia_session_match_codec->tmedia_codec_match_fmtp->tdav_codec_h264_fmtp_match->

    tdav_codec_h264_get_profile(根據fmt獲取對方的profile版本),

     

    當發起外乎請求時codec與sdp處理關系,

    發起invite或對方更改媒體信息時要把codec信息加載到sdp消息體中,

    對于video,audio過程是一樣的。

     

    (videosession from codecs to sdp)

    tdav_session_video_get_lo

    |

    tsdp_header_M_create(創建sdp媒體頭)

     

    |

    tmedia_session_match_codec(此函數最終會返回一個協商成功的編碼類型)

     

    對于h264編碼格式,此函數內部調用過程,遍歷協議棧初始化時指定的編碼鏈表,用此次請求的sdp消息體中的編碼與自己的編碼鏈表比較。->tmedia_codec_match_fmtp->tdav_codec_h264_fmtp_match->

    tdav_codec_h264_get_profile

     

    tmedia_session_match_codec返回協商成功的編碼列表(即雙方都支持的編碼類型列表)后復制給協議棧,

    self->neg_codecs= tmedia_session_match_codec

    然后調用tmedia_codec_video_set_callback設置此編碼類型對應的回調函數,當想發送rtp包時直接觸發此回調函數即可完成發送rtp包的任務。

    tmedia_codec_video_set_callback((tmedia_codec_video_t*)TSK_LIST_FIRST_DATA(self->neg_codecs),tdav_session_video_raw_cb, self);

     

    tdav_session_video_raw_cb為具體的毀掉函數,內部為調用trtp_manager_send_rtp,發送rtp包。

     

    值得注意的是傳給函數的tdav_session_video_raw_cb數據只是未經過加工成rtp包的裸數據,tdav_session_video_raw_cb內部調用trtp_manager_send_rt,由trtp_manager_send_rt來把數據加工成rtp包,

    然后調用傳輸層發送到網絡上。

     

    /*Encapsulate raw data into RTP packet and send it over the network

    *Very IMPORTANT: For voice packets, the marker bits indicates thebeginning of a talkspurt */

    inttrtp_manager_send_rtp(trtp_manager_t* self, const void* data,tsk_size_t size, uint32_t duration, tsk_bool_t marker, tsk_bool_tlast_packet)

     

    trtp_manager_send_rtp內部又具體調用trtp_rtp_packet_create,創建rtp格式的數據包,包括rtp消息頭的創建,初始化默認參數(version,marker,payload_type,seq_num等)。然后調用trtp_rtp_packet_serialize把rtp包序列化到一個buffer中。

    trtp_manager_send_rtp最后調用tnet_sockfd_sendto傳輸層函數完成實際發送到網絡上。

     

     

     

    回到設置tmedia_codec_video_set_callback完畢后,tdav_session_video_get_lo調用tmedia_codec_to_sdp

    把協商后的編碼類型的信息轉換成sdp格式的信息。

    tmedia_codec_to_sdp(self->neg_codecs,self->M.lo); 保存到M.lo屬性,即本地的媒體信息。

    tmedia_codec_to_sdp分析:

    此函數的功能即把協商后的編碼鏈表放到協議棧的sdp屬性中,這樣以后發送invite請求時就可以直接用。

    /**@ingrouptmedia_codec_group

    *Serialize a list of codecs to sdp (m= line) message.<br>

    *Will add: fmt, rtpmap and fmtp.

    *@param codecs The list of codecs to convert

    *@param m The destination

    *@retval Zero if succeed and non-zero error code otherwise

    */

    inttmedia_codec_to_sdp(const tmedia_codecs_L_t* codecs, tsdp_header_M_t*m)

     

    TSK_DEBUG_INFO("Serializea list of codecs to sdp (m= line) message/n");

    tsk_list_foreach(item,codecs){

    遍歷每個編碼類型,添加fmt,rtpmap屬性,fmtp屬性(tmedia_codec_get_fmtp,對于h264格式即調用tmedia_codec_h264_get_fmtp)

     

    最后,tdav_session_video_get_lo內部在屬性M.ro(即已經有請求的sdp信息)非空時考慮此請求是否為

    保持還是接回,通過設置spd屬性,sendrecv,sendonly來提示類型。最后,設置Qos信息。

     

     

    流程tdav_session_video_get_lo

    |

    tsdp_header_M_create(創建sdp媒體頭)

     

    |

    tmedia_session_match_codec

    |

    tmedia_codec_video_set_callback

    |

    tmedia_codec_to_sdp

     

     

    但是

    tdav_session_video_get_lo又是由誰觸發的呢?tdav_session_video_get_lo為某一具體session的回調,

    比如視頻的session回調,音頻的回調,視頻,音頻的session以plugin的方式掛在到session中。

     

    /**Virtual table used to define a session plugin */

    typedefstruct tmedia_session_plugin_def_s

    {

    //!object definition used to create an instance of the session

    consttsk_object_def_t* objdef;

     

    //!the type of the session

    tmedia_type_ttype;

    //!the media name. e.g. "audio", "video", "message","image" etc.

    constchar* media;

     

    int(*set) (tmedia_session_t* , const tmedia_param_t*);

    int(* prepare) (tmedia_session_t* );

    int(* start) (tmedia_session_t* );

    int(* pause) (tmedia_session_t* );

    int(* stop) (tmedia_session_t* );

     

    struct{/* Special case */

    int(* send_dtmf) (tmedia_session_t*, uint8_t );

    }audio;

     

    consttsdp_header_M_t* (* get_local_offer) (tmedia_session_t* );

    /*return zero if can handle the ro and non-zero otherwise */

    int(* set_remote_offer) (tmedia_session_t* , const tsdp_header_M_t* );

    }

    tmedia_session_plugin_def_t;

     

     

    tdav_session_video_get_lo即為get_local_offer的具體回調。

    get_local_offer被tmedia_session_get_lo調用。tmedia_session_get_lo又被tmedia_session_mgr_get_lo】

    調用,正是上面提到的tmedia_session_mgr為管理session的抽象接口,用來與sip信令交互。

    整個流程為:

    tmedia_session_mgr

    |

    tmedia_session_get_lo

    |

    tdav_session_video_get_lo

    |

    tsdp_header_M_create(創建sdp媒體頭)

    |

    tmedia_session_match_codec

    |

    tmedia_codec_video_set_callback

    |

    tmedia_codec_to_sdp

     

     

     

    tmedia_session_mgr_get_lo又被誰觸發呢?

     

    剛才說了,是由sip協議棧調用的,具體有這樣幾個與sdp協商有關的sip點,我們知道,invite請求以及200ok應答,183響應,100響應的確認(prack)中有sdp信息:

     

     

    (1)發送或者更新請求(invite)

     

    send_INVITEorUPDATE

    //send INVITE/UPDATE request

    intsend_INVITEorUPDATE(tsip_dialog_invite_t *self, tsk_bool_t is_INVITE,tsk_bool_t force_sdp)

    1. prack響應

    //Send PRACK

    intsend_PRACK(tsip_dialog_invite_t *self, const tsip_response_t* r1xx)

    1. //Send ACK

    intsend_ACK(tsip_dialog_invite_t *self, const tsip_response_t*r2xxINVITE)

    初始請求中沒有sdp信息,在ack中需要攜帶sdp信息

     

    (4)發送響應時

    /Send any response

    intsend_RESPONSE(tsip_dialog_invite_t *self, const tsip_request_t*request, short code, const char* phrase, tsk_bool_t force_sdp)

     

     

    2.處理請求中的sdp信息過程

    tsip_dialog_invite_process_ro

    |

    tmedia_session_mgr_set_ro

     

    tsip_dialog_invite_process_ro為sip信令中處理sdp信息的入口,在狀態機的回調中適時調用

    。比如在保持狀態轉到接回狀態。

     

    tsip_dialog_invite_process_ro會初始化mgr,啟動,

    tmedia_session_mgr_create,tmedia_session_mgr_set_ro,tmedia_session_mgr_set_natt_ctx,

    tmedia_session_mgr_start

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全