Advertisement
Guest User

Untitled

a guest
Mar 6th, 2017
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.97 KB | None | 0 0
  1. #include "sdp.h"
  2. #include <algorithm>
  3. #include <sstream>
  4. #include <iostream>
  5. #include <regex>
  6. #include <string.h>
  7.  
  8. SDP::SDP(string sdpInternal, string videoId, string audioId)
  9. {    
  10.     this->sdpInternal = sdpInternal;
  11.     this->videoId = videoId;
  12.     this->audioId = audioId;
  13. }
  14.  
  15. SDP::SDP() : SDP("", "", "") {
  16.  
  17. }
  18.  
  19. string join(vector<string> sv, string delimeter) {
  20.     stringstream joined;
  21.     int index = 0;
  22.     int len = sv.size();
  23.     for(auto& s : sv) {
  24.         joined << s;        
  25.         index ++;
  26.         if(index != len) {
  27.             joined << delimeter;
  28.         }
  29.     }
  30.     return joined.str();
  31. }
  32.  
  33. vector<xml_node> findElements(pugi::xml_node node, const char* name)
  34. {
  35.     vector<xml_node> result;
  36.     for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
  37.     {
  38.         if (strcmp(child.name(), name) == 0)
  39.             result.push_back(child);
  40.  
  41.         const char* colon = strchr(child.name(), ':');
  42.  
  43.         if (colon && strcmp(colon + 1, name) == 0)
  44.             result.push_back(child);
  45.     }
  46.  
  47.     return result;
  48. }
  49.  
  50. pugi::xml_node findElement(pugi::xml_node node, const char* name)
  51. {
  52.     for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
  53.     {
  54.         if (strcmp(child.name(), name) == 0)
  55.             return child;
  56.  
  57.         const char* colon = strchr(child.name(), ':');
  58.  
  59.         if (colon && strcmp(colon + 1, name) == 0)
  60.             return child;
  61.     }
  62.  
  63.     return pugi::xml_node();
  64. }
  65.  
  66. vector<string> regexSplit(const string& toSplit, const string& rgx)
  67. {
  68.     regex re(rgx);
  69.     sregex_token_iterator
  70.         first{toSplit.begin(), toSplit.end(), re, -1},
  71.         last;
  72.     return {first, last};
  73. }
  74.  
  75. string findLine(string sdp, string header)
  76. {
  77.     vector<string> lines = regexSplit(sdp, "[\r\n]+");
  78.     for(string line : lines) {
  79.         if(line.find(header) == 0) {
  80.             return line;
  81.         }
  82.     }
  83.     return "";
  84. }
  85.  
  86. string RandomString(int length)
  87. {
  88.     stringstream randomStr;
  89.     const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  90.     for(int i = 0; i < length; i ++)
  91.         randomStr << chars[rand() % chars.length()];
  92.     return randomStr.str();
  93. }
  94.  
  95.  
  96. vector<string> findLines(string sdp, string header)
  97. {
  98.     vector<string> results;
  99.     vector<string> lines = regexSplit(sdp, "[\r\n]+");
  100.     for(string line : lines) {
  101.         if(line.find(header) == 0) {
  102.             results.push_back(line);
  103.         }
  104.     }
  105.     return results;
  106. }
  107.  
  108. vector<string> SDP::getMedias(string sdp)
  109. {
  110.     vector<string> medias;
  111.     vector<string> mediaReg = regexSplit(sdp, "[\r\n]+m=");
  112.     int mSize = mediaReg.size();
  113.     for(int i = 0; i < mSize; i ++)
  114.     {
  115.         stringstream media_i;
  116.         media_i << "m=" << mediaReg[i];
  117.         if(i != mSize - 1)
  118.         {
  119.             media_i << "\r\n";
  120.         }
  121.         medias.push_back(media_i.str());
  122.     }
  123.     return medias;
  124. }
  125.  
  126. xml_node SDP::parseRtpMap(string rtpmap, xml_node parent)
  127. {
  128.     xml_node payloadType = parent.append_child("payload-type");    
  129.  
  130.     vector<string> parts = regexSplit(rtpmap.substr(RTP_MAP_HEAD.length()), "[\\s/]+");
  131.     if(parts.size() >= 3)
  132.     {
  133.         payloadType.append_attribute("id") = parts[0].c_str();
  134.         payloadType.append_attribute("name") = parts[1].c_str();
  135.         payloadType.append_attribute("clockrate") = parts[2].c_str();
  136.     }
  137.     if(parts.size() > 3)
  138.     {
  139.         payloadType.append_attribute("channels") = parts[3].c_str();
  140.     }
  141.     return payloadType;
  142. }
  143.  
  144. void SDP::rtcpFbToJingle(string media, string payloadType, xml_node parent)
  145. {
  146.     vector<string> lines = findLines(media, RTCP_FB_HEAD + payloadType);
  147.     for(string line : lines)
  148.     {
  149.         smatch match;
  150.         if(regex_search(line, match, regex(RTCP_FB_HEAD + payloadType + " (.+)")))
  151.         {            
  152.             vector<string> rtcpFbItems = regexSplit(match[1], " ");
  153.  
  154.             string rtcpFbType;
  155.             if(rtcpFbItems.size() > 0)
  156.                 rtcpFbType = rtcpFbItems[0];
  157.            
  158.             rtcpFbItems.erase(rtcpFbItems.begin());
  159.  
  160.             if(rtcpFbType == "trr-int")
  161.             {
  162.                 xml_node rtcpTrr = parent.append_child("rtcp-fb-trr-int");
  163.                 rtcpTrr.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
  164.                 if(rtcpFbItems.size() > 0)
  165.                     rtcpTrr.append_attribute("value") = rtcpFbItems[0].c_str();
  166.             }
  167.             else
  168.             {
  169.                 xml_node rtcpElem = parent.append_child("rtcp-fb");
  170.                 rtcpElem.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
  171.  
  172.                 rtcpElem.append_attribute("type") = rtcpFbType.c_str();
  173.  
  174.                 if(rtcpFbItems.size() > 0)
  175.                     rtcpElem.append_attribute("subtype") = rtcpFbItems[0].c_str();                
  176.             }
  177.         }
  178.     }
  179. }
  180.  
  181. void SDP::parseExtMap(string extmap, xml_node parent)
  182. {
  183.     xml_node rtpHdrExt = parent.append_child("rtp-hdrext");
  184.     rtpHdrExt.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0";
  185.     vector<string> parts = regexSplit(extmap.substr(EXT_MAP_HEAD.length()), "[\\s]+");
  186.  
  187.     if(parts.size() > 0)
  188.     {
  189.         if(parts[0].find("/") != string::npos)
  190.         {
  191.             string direction = parts[0].substr(parts[0].find("/") + 1);
  192.             string value = parts[0].substr(0, parts[0].find("/"));
  193.             rtpHdrExt.append_attribute("id") = value.c_str();
  194.             rtpHdrExt.append_attribute("direction") = direction.c_str();
  195.         }
  196.         else
  197.         {
  198.             rtpHdrExt.append_attribute("id") = parts[0].c_str();
  199.         }
  200.     }
  201.     if(parts.size() > 1)
  202.     {
  203.         rtpHdrExt.append_attribute("uri") = parts[1].c_str();
  204.     }
  205.     string direction = rtpHdrExt.attribute("direction").value();
  206.     if(direction.length() > 0)
  207.     {
  208.         if(direction == "sendonly")
  209.         {
  210.             rtpHdrExt.append_attribute("senders") = "responder";
  211.         }
  212.         else if(direction == "recvonly")
  213.         {
  214.             rtpHdrExt.append_attribute("senders") = "initiator";
  215.         }
  216.         else if(direction == "sendrecv")
  217.         {
  218.             rtpHdrExt.append_attribute("senders") = "both";
  219.         }        
  220.         else if(direction == "inactive")
  221.         {
  222.             rtpHdrExt.append_attribute("senders") = "none";
  223.         }
  224.     }
  225. }
  226.  
  227. void SDP::parseSctpMap(string sctpMap, xml_node parent)
  228. {
  229.     xml_node sctpMapEl = parent.append_child("sctpmap");
  230.     sctpMapEl.append_attribute("xmlns") = "urn:xmpp:jingle:transpoorts:dtls-sctp:1";
  231.  
  232.     vector<string> parts = regexSplit(sctpMap.substr(SCTP_MAP_HEAD.length()), " ");
  233.  
  234.     if(parts.size() >= 2)
  235.     {
  236.         sctpMapEl.append_attribute("number") = parts[0].c_str();
  237.         sctpMapEl.append_attribute("protocol") = parts[1].c_str();
  238.     }
  239.     if(parts.size() > 2)
  240.     {
  241.         sctpMapEl.append_attribute("streams") = parts[2].c_str();
  242.     }
  243. }
  244.  
  245. xml_node SDP::parseFingerprint(string fingerprint, xml_node parent)
  246. {
  247.     xml_node fingerEl = parent.append_child("fingerprint");
  248.     fingerEl.append_attribute("xmlns") = "urn:xmpp:jingle:apps:dtls:0";
  249.     vector<string> parts = regexSplit(fingerprint.substr(FINGERPRINT_HEAD.length()), " ");
  250.     if(parts.size() >= 2)
  251.     {
  252.         fingerEl.append_attribute("hash") = parts[0].c_str();
  253.         fingerEl.text().set(parts[1].c_str());
  254.     }
  255.     return fingerEl;
  256. }
  257.  
  258. void SDP::candidateToJingle(string candidateLine, xml_node parent)
  259. {
  260.     xml_node candidate = parent.append_child("candidate");
  261.     candidate.append_attribute("xmlns") = "urn:xmpp:jingle:transports:ice-udp:1";
  262.     if(candidateLine.find("candidate:") != 0)
  263.     {
  264.         cerr << "Candidate parser called with invalid candidate line " << candidateLine << endl;
  265.         return;
  266.     }
  267.     if(candidateLine.length() > 2 &&
  268.         candidateLine.substr(candidateLine.length() - 2) == "\r\n")
  269.     {
  270.         candidateLine = candidateLine.substr(0, candidateLine.length() - 2);
  271.     }
  272.  
  273.     vector<string> elems = regexSplit(candidateLine, " ");
  274.     if(elems.size() >= 7 && elems[6] != "typ")
  275.     {
  276.         cerr << "Invalid Candidate Line " << candidateLine << " typ not located in correct location." << endl;
  277.         return;
  278.     }
  279.     if(elems.size() >= 8)
  280.     {
  281.         candidate.append_attribute("foundation") = elems[0].substr(CAND_HEAD.length()).c_str();
  282.         candidate.append_attribute("component") = elems[1].c_str();
  283.         candidate.append_attribute("protocol") = elems[2].c_str();
  284.         candidate.append_attribute("priority") = elems[3].c_str();
  285.         candidate.append_attribute("ip") = elems[4].c_str();
  286.         candidate.append_attribute("port") = elems[5].c_str();
  287.         candidate.append_attribute("type") = elems[7].c_str();
  288.     }
  289.     xml_attribute generation = candidate.append_attribute("generation");
  290.     generation = "0";
  291.  
  292.     for(int i = 8; i < elems.size(); i ++)
  293.     {
  294.         if(elems[i] == "raddr")
  295.         {
  296.             candidate.append_attribute("rel-addr") = elems[i+1].c_str();
  297.         }
  298.         else if(elems[i] == "rport")
  299.         {
  300.             candidate.append_attribute("rel-port") = elems[i+1].c_str();
  301.         }
  302.         else if(elems[i] == "generation")
  303.         {            
  304.             generation = elems[i+1].c_str();
  305.         }
  306.         else if(elems[i] == "tcptype")
  307.         {
  308.             candidate.append_attribute("tcptype") = elems[i+1].c_str();
  309.         }
  310.         else
  311.         {
  312.             cout << "Not translating " << elems[i] << endl;
  313.         }        
  314.     }
  315.     candidate.append_attribute("network") = "1";
  316.     candidate.append_attribute("id") = RandomString(7).c_str();
  317.     return;
  318. }
  319.  
  320. void SDP::transportToJingle(string media, string session, vector<string>& candidatesProvided, xml_node parent)
  321. {
  322.     string ufrag = findLine(media, ICE_UFRAG_HEAD);
  323.     if(ufrag.length() == 0)
  324.         ufrag = findLine(session, ICE_UFRAG_HEAD);
  325.    
  326.     string pwd = findLine(media, ICE_PWD_HEAD);
  327.     if(pwd.length() == 0)
  328.         pwd = findLine(session, ICE_PWD_HEAD);
  329.    
  330.     xml_node rtpHdrExt = parent.append_child("transport");
  331.     if(ufrag.length() > 0 && pwd.length() > 0)
  332.     {
  333.         rtpHdrExt.append_attribute("xmlns") = "urn:xmpp:jingle:transports:ice-udp:1";
  334.         ufrag = ufrag.substr(ICE_UFRAG_HEAD.length());
  335.         pwd = pwd.substr(ICE_PWD_HEAD.length());
  336.     }
  337.     string sctpMap = findLine(media, SCTP_MAP_HEAD);
  338.     if(sctpMap.length() > 0)
  339.         parseSctpMap(sctpMap, rtpHdrExt);        
  340.  
  341.     vector<string> fingerprints = findLines(media, FINGERPRINT_HEAD);
  342.     vector<string> sessionFingerPrints = findLines(session, FINGERPRINT_HEAD);
  343.  
  344.     for(string line : fingerprints)
  345.     {
  346.         xml_node fingerprint = parseFingerprint(line, rtpHdrExt);
  347.         string setupLine = findLine(media, SETUP_HEAD);
  348.  
  349.         if(setupLine.length() > 0)
  350.         {
  351.             fingerprint.append_attribute("setup") = setupLine.substr(SETUP_HEAD.length()).c_str();
  352.         }
  353.     }
  354.     for(string line : sessionFingerPrints)
  355.     {
  356.         xml_node fingerprint = parseFingerprint(line, rtpHdrExt);
  357.         string setupLine = findLine(media, SETUP_HEAD);
  358.  
  359.         if(setupLine.length() > 0)
  360.         {
  361.             fingerprint.append_attribute("setup") = setupLine.substr(SETUP_HEAD.length()).c_str();
  362.         }
  363.     }
  364.  
  365.     if(ufrag.length() > 0 && pwd.length() > 0)
  366.     {
  367.         rtpHdrExt.append_attribute("ufrag") = ufrag.c_str();
  368.         rtpHdrExt.append_attribute("pwd") = pwd.c_str();
  369.     }
  370.  
  371.     vector<string> candidates = findLines(media, CAND_HEAD);
  372.     vector<string> sesCandidates = findLines(session, CAND_HEAD);
  373.    
  374.     for(string candidateLine : candidates)
  375.         candidateToJingle(candidateLine, rtpHdrExt);
  376.  
  377.     for(string candidateLine : sesCandidates)
  378.         candidateToJingle(candidateLine, rtpHdrExt);
  379.  
  380.     if(candidatesProvided.size() > 0)
  381.     {
  382.         for(string candidateLine : candidatesProvided)
  383.         {
  384.             candidateToJingle(candidateLine, rtpHdrExt);
  385.         }
  386.     }
  387.  
  388.     return;
  389. }
  390.  
  391. string SDP::createJingle(bool isResponder, string to, string from,
  392.     string sid, vector<string>& candidates)
  393. {
  394.     xml_document doc;
  395.     xml_node iq = doc.append_child("iq");
  396.     iq.append_attribute("xmlns") = "jabber:client";
  397.     iq.append_attribute("type") = "set";
  398.     iq.append_attribute("to") = to.c_str();
  399.     iq.append_attribute("from") = from.c_str();
  400.     iq.append_attribute("id") = "MX_3";
  401.  
  402.     xml_node jingle = iq.append_child("jingle");
  403.     jingle.append_attribute("xmlns") = "urn:xmpp:jingle:1";
  404.     jingle.append_attribute("initiator") = to.c_str();
  405.     jingle.append_attribute("action") = isResponder?"session-accept":"session-initiate";
  406.     jingle.append_attribute("sid") = sid.c_str();
  407.  
  408.     if(this->sdpInternal.length() > 0)
  409.     {
  410.         vector<string> groups = findLines(sdpInternal, GROUP_TAG);
  411.         for(string group : groups)
  412.         {
  413.             vector<string> tokens = regexSplit(group, " ");
  414.             if(tokens.size() >= 1)
  415.             {
  416.                 string semantics = tokens[0].substr(GROUP_TAG.length());
  417.                 xml_node el = jingle.append_child("group");
  418.                 el.append_attribute("xmlns") = "urn:xmpp:jingle:apps:grouping:0";
  419.                 el.append_attribute("semantics") = semantics.c_str();
  420.                 for(int i = 1; i < tokens.size(); i ++)
  421.                 {
  422.                     string cName = tokens[i];
  423.                     xml_node content = el.append_child("content");
  424.                     content.append_attribute("name") = cName.c_str();
  425.                 }
  426.             }
  427.         }
  428.  
  429.         vector<string> medias = getMedias(sdpInternal);
  430.         if(medias.size() > 0) {
  431.             string session = medias[0] + "\r\n";
  432.  
  433.             // Skip Session.
  434.             medias.erase(medias.begin());
  435.             for(string media : medias)
  436.             {
  437.                 string mLine = regexSplit(media, "[\r\n]+")[0];
  438.                 smatch matches;
  439.                 if(regex_search(mLine, matches,
  440.                     regex(MEDIA_HEAD +
  441.                     "(video|audio|application) (\\d+) ([A-Za-z/]+) ([\\d\\s]+)"))
  442.                     && matches.size() >= 4
  443.                     )
  444.                 {                    
  445.                     string ssrc;
  446.                     string mediaName = matches[1];
  447.                     string mediaPort = matches[2];
  448.                     string mediaProto = matches[3];
  449.                    
  450.                     vector<string> mediaFmts = regexSplit(matches[4], " ");
  451.                     string aSsrcLine = findLine(media, SSRC_HEAD);
  452.                     if(aSsrcLine.length() > 0)
  453.                     {                        
  454.                         ssrc = regexSplit(aSsrcLine.substr(SSRC_HEAD.length()), " ")[0];
  455.                     }
  456.  
  457.                     xml_node content = jingle.append_child("content");                    
  458.                     content.append_attribute("creator") = isResponder ? "responder" : "initiator";
  459.  
  460.                     xml_attribute content_name = content.append_attribute("name");
  461.                     content_name = mediaName.c_str();
  462.  
  463.                     string aMid = findLine(media, MID_HEAD);
  464.                     if(aMid.length() > 0)
  465.                     {
  466.                         smatch midMatch;
  467.                         if(regex_search(aMid, midMatch, regex(MID_HEAD + "(video|audio|data)")))
  468.                         {
  469.                             string midName = midMatch[1];
  470.                             if(midName.length() > 0)
  471.                                 content_name = midName.c_str();
  472.                         }
  473.                     }
  474.                     string rtpMap = findLine(media, RTP_MAP_HEAD);
  475.                     if(rtpMap.length() > 0)
  476.                     {
  477.                         xml_node desc = content.append_child("description");
  478.                         desc.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:1";                    
  479.                         desc.append_attribute("media") = mediaName.c_str();
  480.                         if(ssrc.length() > 0)
  481.                         {
  482.                             desc.append_attribute("ssrc") = ssrc.c_str();
  483.                         }
  484.                         for(string fmt : mediaFmts)
  485.                         {
  486.                             string rtpmap = findLine(media, RTP_MAP_HEAD + fmt);
  487.                             if(rtpmap.length() > 0)
  488.                             {
  489.                                 xml_node payloadType = parseRtpMap(rtpmap, desc);
  490.  
  491.                                 string fmtpLine = findLine(media, FORMAT_PARAM_HEAD + fmt);
  492.                                 if(fmtpLine.length() > 0)
  493.                                 {
  494.                                     // a=fmtp:111 minptime=10; useinbandfec=1
  495.                                     smatch fmtpPar;
  496.                                     if(regex_search(fmtpLine, fmtpPar, regex(FORMAT_PARAM_HEAD + fmt + " ([a-zA-Z0-9=; ]+)")))
  497.                                     {
  498.                                         string fmtpParams = fmtpPar[1];
  499.                                         vector<string> fmtpParamList = regexSplit(fmtpParams, ";");
  500.                                         for(string paramEl : fmtpParamList)
  501.                                         {
  502.                                             smatch paramKeyVal;
  503.                                             if(regex_search(paramEl, paramKeyVal, regex("([a-zA-Z]+)=([a-zA-Z\\-\\d]+)")))
  504.                                             {
  505.                                                 string key = paramKeyVal[1];
  506.                                                 string value = paramKeyVal[2];
  507.                                                 xml_node paramXEl = payloadType.append_child("parameter");
  508.                                                 paramXEl.append_attribute("name") = key.c_str();
  509.                                                 paramXEl.append_attribute("value") = value.c_str();
  510.                                             }
  511.                                         }
  512.                                     }
  513.                                 }
  514.                                 // rtcpFb
  515.                                 rtcpFbToJingle(media, fmt, payloadType);
  516.                             }
  517.                         }
  518.                         if(ssrc.length() > 0)
  519.                         {
  520.                             xml_node source = desc.append_child("source");
  521.                             source.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
  522.                            
  523.                             source.append_attribute("ssrc") = ssrc.c_str();
  524.  
  525.                             vector<string> ssrcLines = findLines(media, SSRC_HEAD);
  526.                             if(ssrcLines.size() > 0)
  527.                             {
  528.                                 xml_node nSource = source;
  529.                                 for(string ssrcLine : ssrcLines)
  530.                                 {
  531.                                     string::size_type idx = ssrcLine.find(" ");
  532.                                     string lineSsrc = ssrcLine.substr(0, idx).substr(SSRC_HEAD.length());
  533.                                     if(lineSsrc != ssrc)
  534.                                     {
  535.                                         ssrc = lineSsrc;
  536.                                         nSource = desc.append_child("source");
  537.                                         nSource.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
  538.                                         nSource.append_attribute("ssrc") = ssrc.c_str();                                        
  539.                                     }
  540.                                     string kv = ssrcLine.substr(idx + 1);
  541.                                     xml_node parameter = nSource.append_child("parameter");
  542.                                     if(kv.find(":") == string::npos)
  543.                                     {
  544.                                         parameter.append_attribute("name") =  kv.c_str();
  545.                                     }
  546.                                     else {
  547.                                         vector<string> kVSplit = regexSplit(kv, ":");
  548.                                         parameter.append_attribute("name") = kVSplit[0].c_str();
  549.                                         parameter.append_attribute("value") = kVSplit[1].c_str();
  550.                                     }                                    
  551.                                 }
  552.                             }
  553.                             else {
  554.                                 xml_node parameter = source.append_child("parameter");
  555.                                 parameter.append_attribute("cname") = RandomString(7).c_str();
  556.  
  557.                                 string msid;
  558.                                 if(mediaName == "audio")
  559.                                 {
  560.                                     msid = audioId;
  561.                                 }
  562.                                 else
  563.                                 {
  564.                                     msid = videoId;
  565.                                 }
  566.                                 if(msid.length() > 0)
  567.                                 {
  568.                                     msid = filterSpecialChars(msid);
  569.                                     xml_node msIdParam = source.append_child("parameter");
  570.                                     msIdParam.append_attribute("name") = "msid";
  571.                                     msIdParam.append_attribute("value") = msid.c_str();
  572.  
  573.                                     xml_node msLabelParam = source.append_child("parameter");
  574.                                     msLabelParam.append_attribute("name") = "mslabel";
  575.                                     msLabelParam.append_attribute("value") = msid.c_str();
  576.  
  577.                                     xml_node parameterParam = source.append_child("parameter");
  578.                                     parameterParam.append_attribute("name") = "mslabel";
  579.                                     parameterParam.append_attribute("value") = msid.c_str();                                    
  580.                                 }
  581.                             }
  582.  
  583.                             vector<string> ssrcGroupLines = findLines(media, SSRC_GROUP_HEAD);
  584.                             for(string line : ssrcGroupLines)
  585.                             {
  586.                                 int idx = line.find(" ");
  587.                                 string semantics = line.substr(0, idx).substr(SSRC_GROUP_HEAD.length());
  588.                                 vector<string> ssrcs = regexSplit(line.substr(SSRC_GROUP_HEAD.length() + semantics.length()), " ");
  589.                                 if(ssrcs.size() > 0)
  590.                                 {
  591.                                     xml_node ssrcGroup = desc.append_child("ssrc-group");
  592.                                     ssrcGroup.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
  593.                                     ssrcGroup.append_attribute("semantics") = semantics.c_str();
  594.  
  595.                                     for(string ssrcL : ssrcs)
  596.                                     {
  597.                                         xml_node ssrcGroupSrc = ssrcGroup.append_child("source");
  598.                                         ssrcGroupSrc.append_attribute("ssrc") = ssrc.c_str();
  599.                                     }
  600.                                 }
  601.                             }
  602.                         }
  603.                         string rtcpMuxLine = findLine(media, RTCP_MUX);
  604.                         if(rtcpMuxLine.length() > 0)
  605.                             desc.append_child("rtcp-mux");
  606.                        
  607.                         rtcpFbToJingle(media, "*", desc);
  608.  
  609.                         vector<string> extmapLines = findLines(media, EXT_MAP_HEAD);
  610.                         if(extmapLines.size() > 0)
  611.                         {
  612.                             for(int j = 0; j < extmapLines.size(); j ++)
  613.                             {
  614.                                 parseExtMap(extmapLines[j], desc);
  615.                             }
  616.                         }
  617.                     }
  618.                     transportToJingle(media, session, candidates, content);
  619.  
  620.                     if(findLine(media, "a=sendrecv").length() > 0 ||
  621.                         findLine(session, "a=sendrecv").length() > 0)
  622.                     {
  623.                         content.append_attribute("senders") = "both";
  624.                     }
  625.                     else if(findLine(media, "a=sendonly").length() > 0 ||
  626.                         findLine(session, "a=sendonly").length() > 0)
  627.                     {
  628.                         content.append_attribute("senders") = "initiator";
  629.                     }
  630.                     else if(findLine(media, "a=recvonly").length() > 0 ||
  631.                         findLine(session, "a=recvonly").length() > 0)
  632.                     {
  633.                         content.append_attribute("senders") = "responder";
  634.                     }
  635.                     else if(findLine(media, "a=none").length() > 0 ||
  636.                         findLine(session, "a=none").length() > 0)
  637.                     {
  638.                         content.append_attribute("senders") = "rejected";
  639.                     }
  640.                 }
  641.             }
  642.         }
  643.     }
  644.     stringstream xmlResult;
  645.     doc.print(xmlResult);
  646.  
  647.     return xmlResult.str();
  648. }
  649.  
  650. void SDP::addGroup(string groupSemanticsOrType, vector<string> names) {
  651.     stringstream groupss;
  652.     groupss << GROUP_TAG << groupSemanticsOrType << " " << join(names, " ") << LNEND;
  653.     sdpInternal += groupss.str();
  654. }
  655.  
  656. string SDP::buildMLine(int port, string media,
  657.     string proto, vector<int> fmt) {    
  658.     stringstream format;
  659.     int fmtSize = fmt.size();
  660.     for(int i = 0; i < fmtSize; i++) {
  661.         format << fmt[i];
  662.         if(i != fmtSize - 1) {
  663.             format << " ";
  664.         }
  665.     }
  666.     stringstream mLine;
  667.     mLine << MEDIA_HEAD << media << " " << port << " " << proto << " " << format.str();
  668.     return mLine.str();
  669. }
  670.  
  671. string SDP::buildIceUFrag(string uFrag)
  672. {
  673.     stringstream iceUFrag;
  674.     iceUFrag << ICE_UFRAG_HEAD
  675.         << uFrag;
  676.     return iceUFrag.str();
  677. }
  678. string SDP::buildIcePwd(string pwd)
  679. {
  680.     stringstream icePwd;
  681.     icePwd << ICE_PWD_HEAD
  682.         << pwd;
  683.     return icePwd.str();
  684. }
  685. string SDP::buildRtpMap(xml_node payload)
  686. {
  687.     stringstream rtpMap;
  688.     rtpMap << RTP_MAP_HEAD
  689.         << payload.attribute("id").value()
  690.         << " "
  691.         << payload.attribute("name").value()
  692.         << "/"
  693.         << payload.attribute("clockrate").value();
  694.     string channels = payload.attribute("channels").value();
  695.     if(channels.length() > 0 && channels != "1")
  696.     {
  697.         rtpMap << "/"
  698.             << channels;
  699.     }
  700.     return rtpMap.str();
  701.  
  702. }
  703. string SDP::filterSpecialChars(string value)
  704. {
  705.     regex_replace(value, regex("[\\\\\\/\\{,\\}\\+]"), "");
  706. }
  707.  
  708. string SDP::rtcpFbFromJingle(xml_node el, string payloadType)
  709. {
  710.     stringstream media;
  711.  
  712.     vector<xml_node> rtcpFbTrrInts = findElements(el, "rtcp-fb-trr-int");
  713.     for(auto rtcpFbTrrInt : rtcpFbTrrInts)
  714.     {
  715.         media << RTCP_FB_HEAD
  716.             << "* trr-int";
  717.         string rtcpTrrVal = rtcpFbTrrInt.attribute("value").value();
  718.         if(rtcpTrrVal.length() > 0)
  719.         {
  720.             media << rtcpTrrVal;            
  721.         }
  722.         else
  723.             media << "0";
  724.        
  725.         media << LNEND;
  726.     }
  727.     vector<xml_node> rtcpFbs = findElements(el, "rtcp-fb");
  728.     for(auto rtcpFb : rtcpFbs)
  729.     {
  730.         media << RTCP_FB_HEAD
  731.             << payloadType
  732.             << " "
  733.             << rtcpFb.attribute("type").value();
  734.         string subType = rtcpFb.attribute("subtype").value();
  735.         if(subType.length() > 0)
  736.         {
  737.             media << " "
  738.                 << subType;
  739.         }
  740.         media << LNEND;
  741.     }
  742.     return media.str();
  743. }
  744.  
  745. string SDP::candidateFromJingle(xml_node candidate)
  746. {
  747.     string protocol = candidate.attribute("protocol").value();
  748.     stringstream line;
  749.     line << CAND_HEAD
  750.         << candidate.attribute("foundation").value()
  751.         << " "
  752.         << candidate.attribute("component").value()
  753.         << " "
  754.         << protocol
  755.         << " "
  756.         << candidate.attribute("priority").value()
  757.         << " "
  758.         << candidate.attribute("ip").value()
  759.         << " "
  760.         << candidate.attribute("port").value()
  761.         << " typ "
  762.         << candidate.attribute("type").value()
  763.         << " ";
  764.     string typ = candidate.attribute("type").value();
  765.     if(typ == "srflx" || typ == "prflx" || typ == "relay")
  766.     {
  767.         line << "raddr"
  768.             << " "
  769.             << candidate.attribute("rel-addr").value()
  770.             << " "
  771.             << "rport"
  772.             << " "
  773.             << candidate.attribute("rel-port").value()
  774.             << " ";
  775.     }
  776.     if(protocol == "tcp")
  777.     {
  778.         line << "tcptype"
  779.             << " "
  780.             << candidate.attribute("tcptype").value()
  781.             << " ";
  782.     }
  783.     line << "generation"
  784.         << " "
  785.         << candidate.attribute("generation").value()
  786.         << LNEND;
  787.  
  788.     return line.str();
  789. }
  790.  
  791. void SDP::addMedia(xml_node content) {
  792.     int port = 1;
  793.     string proto = "RTP/SAVPF";
  794.     stringstream mediaSDP;
  795.    
  796.     xml_node desc = findElement(content, "description");
  797.     string ssrc = desc.attribute("ssrc").value();
  798.     xml_node transp = findElement(content, "transport");
  799.     if(find(ssrcsAdded.begin(), ssrcsAdded.end(), ssrc)
  800.         != ssrcsAdded.end()) {
  801.         cerr << "Attempted to add existing SSRC " << ssrc << endl;
  802.         return;
  803.     }
  804.  
  805.     xml_node sctpElement;
  806.     // Determine if SCTP is being used.
  807.     if(transp) {
  808.         sctpElement = findElement(transp, "sctpmap");
  809.     }
  810.  
  811.     string media = desc.attribute("media").value();
  812.    
  813.     if(string(content
  814.         .attribute("senders").value())
  815.         .length() != 0 &&
  816.         string(content
  817.         .attribute("senders").value()) == "rejected") {
  818.             port = 0;
  819.         }
  820.    
  821.     xml_node fingerprint;
  822.     if(transp)
  823.         fingerprint = findElement(transp, "fingerprint");        
  824.    
  825.     xml_node encryption;
  826.     if(desc)
  827.         encryption = findElement(transp, "encryption");
  828.    
  829.     if(fingerprint || encryption) {
  830.         proto = (sctpElement) ? DTLS_SRTP : RTP_SAVPF;
  831.     }
  832.     if(!sctpElement) {
  833.         vector<xml_node> payloadTypes = findElements(desc, "payload-type");
  834.        
  835.         vector<int> payloadTypeAr;
  836.         for(auto payloadType : payloadTypes) {
  837.             payloadTypeAr.push_back(payloadType
  838.                 .attribute("id").as_int());
  839.             //cout << "PUSHING PAYLOAD TYPE " << payloadType.attribute("id").as_int() << endl;
  840.         }
  841.         string mLine = buildMLine(port, media, proto, payloadTypeAr);
  842.         mediaSDP << mLine << LNEND;
  843.     }
  844.     else {
  845.         mediaSDP << SCTP_APPLICATION_HEAD
  846.             << " "
  847.             << sctpElement.attribute("number").value()
  848.             << LNEND;
  849.         mediaSDP << SCTP_MAP_HEAD
  850.             << sctpElement.attribute("number").value()
  851.             << " "
  852.             << sctpElement.attribute("protocol").value();
  853.  
  854.         string streamsAt = sctpElement.attribute("streams").value();
  855.         if(streamsAt.length() > 0) {
  856.             int streamCount = std::stoi(streamsAt);
  857.             if(streamCount >= 0) {
  858.                 mediaSDP << " "
  859.                     << streamCount
  860.                     << LNEND;
  861.             }
  862.             else
  863.                 mediaSDP << LNEND;            
  864.         }
  865.         else
  866.             mediaSDP << LNEND;
  867.     }
  868.  
  869.     mediaSDP << C_MEDIA_HEAD;
  870.     if(!sctpElement)
  871.     {
  872.         mediaSDP << RTCP_MEDIA_HEAD;
  873.     }
  874.     if(transp)
  875.     {
  876.         string uFrag = transp.attribute("ufrag").value();
  877.         string pwd = transp.attribute("pwd").value();
  878.         if(uFrag.length() > 0) {
  879.             mediaSDP << buildIceUFrag(uFrag)
  880.                 << LNEND;
  881.         }
  882.         if(pwd.length() > 0) {
  883.             mediaSDP << buildIcePwd(pwd)
  884.                 << LNEND;
  885.         }
  886.  
  887.         vector<xml_node> fingerprints = findElements(transp, "fingerprint");
  888.            
  889.         for(auto el : fingerprints)
  890.         {
  891.             mediaSDP << FINGERPRINT_HEAD
  892.                 << el.attribute("hash").value()
  893.                 << " "
  894.                 << el.child_value()
  895.                 << LNEND;
  896.             string setup = el.attribute("setup").value();
  897.             if(setup.length() > 0)
  898.             {
  899.                 mediaSDP << SETUP_HEAD
  900.                     << setup
  901.                     << LNEND;
  902.             }
  903.         }            
  904.     }
  905.     mediaSDP << SENDER_TO_ALINE[content
  906.         .attribute("senders").value()]
  907.         << LNEND;
  908.     mediaSDP << MID_HEAD
  909.         << content.attribute("name").value()
  910.         << LNEND;
  911.  
  912.     if(findElement(desc, "rtcp-mux"))
  913.     {
  914.         mediaSDP << RTCP_MUX << LNEND;
  915.     }
  916.     vector<xml_node> encryptions = findElements(desc, "encryption");
  917.     for(auto en : encryptions)
  918.     {
  919.         vector<xml_node> cryptos = findElements(en, "crypto");
  920.         for(auto crypt : cryptos)
  921.         {
  922.             mediaSDP << CRYPT_HEAD
  923.                 << crypt.attribute("tag").value()
  924.                 << " "
  925.                 << crypt.attribute("crypto-suite").value()
  926.                 << " "
  927.                 << crypt.attribute("key-params").value();
  928.             string sessionParams = crypt.attribute("session-params").value();
  929.             if(sessionParams.length() > 0)
  930.             {
  931.                 mediaSDP << " "
  932.                     << sessionParams;
  933.             }
  934.             mediaSDP << LNEND;
  935.         }
  936.     }
  937.  
  938.     vector<xml_node> payloads = findElements(desc, "payload-type");
  939.     for(auto payload : payloads)
  940.     {
  941.         mediaSDP << buildRtpMap(payload)
  942.             << LNEND;
  943.         vector<xml_node> parameters = findElements(payload, "parameter");
  944.         if(parameters.size() > 0)
  945.         {
  946.             mediaSDP << FORMAT_PARAM_HEAD
  947.                 << payload.attribute("id").value()
  948.                 << " ";
  949.             stringstream parameterLine;
  950.             for(int i = 0; i < parameters.size(); i ++)
  951.             {
  952.                 xml_node parameter = parameters[i];
  953.                 string name = parameter.attribute("name").value();
  954.                 if(name.length() > 0)
  955.                 {
  956.                     parameterLine << name
  957.                         << "="
  958.                         << parameter.attribute("value").value();
  959.                     if(i != parameters.size() - 1)
  960.                         parameterLine << "; ";
  961.                 }
  962.             }
  963.             mediaSDP << parameterLine.str()
  964.                 << LNEND;
  965.         }
  966.         // http://www.xmpp.org/extensions/xep-0293.html
  967.         mediaSDP << rtcpFbFromJingle(payload, payload.attribute("id").value());
  968.     }
  969.     mediaSDP << rtcpFbFromJingle(desc, "*");
  970.  
  971.     // http://www.xmpp.org/extensions/xep-0294.html
  972.     vector<xml_node> rtpHdrExts = findElements(desc, "rtp-hdrext");
  973.     for(xml_node rtpHdrExt : rtpHdrExts)
  974.     {
  975.         mediaSDP << EXT_MAP_HEAD
  976.             << rtpHdrExt.attribute("id").value()
  977.             << " "
  978.             << rtpHdrExt.attribute("uri").value()
  979.             << LNEND;
  980.     }
  981.     vector<xml_node> candidates;
  982.     if(transp)
  983.         candidates = findElements(transp, "candidate");
  984.        
  985.     for(auto cand : candidates)
  986.     {
  987.         string protocol = cand.attribute("protocol").value();
  988.         if(protocol.length() > 0)
  989.         {
  990.             //std::transform(protocol.begin(),
  991.             //    protocol.end(), protocol.begin(), ::tolower);
  992.             mediaSDP << candidateFromJingle(cand);
  993.         }
  994.     }    
  995.     if(desc)
  996.     {
  997.         vector<xml_node> ssrcGroups = findElements(desc, "ssrc-group");
  998.         for(xml_node ssrcGroup : ssrcGroups)
  999.         {
  1000.             string semantics = ssrcGroup.attribute("semantics").value();
  1001.             vector<xml_node> ssrcs = findElements(ssrcGroup, "source");
  1002.             stringstream ssrcStr;
  1003.             for(int i = 0; i < ssrcs.size(); i ++)
  1004.             {
  1005.                 xml_node ssrc = ssrcs[i];
  1006.                 string sStr = ssrc.attribute("ssrc").value();
  1007.                 ssrcStr << sStr;
  1008.                 if(sStr.length() > 0)
  1009.                 {
  1010.                     // Keep track of the fact this SDP contains this ssrc.
  1011.                     ssrcsAdded.push_back(sStr);
  1012.                 }
  1013.                 if(i != ssrcs.size() -1)
  1014.                 {
  1015.                     ssrcStr << " ";
  1016.                 }
  1017.             }
  1018.             mediaSDP << SSRC_GROUP_HEAD
  1019.                 << semantics
  1020.                 << " "
  1021.                 << ssrcStr.str()
  1022.                 << LNEND;
  1023.         }
  1024.  
  1025.         vector<xml_node> sources = findElements(desc, "source");
  1026.         for(auto source : sources)
  1027.         {
  1028.             string nSsrc = source.attribute("ssrc").value();
  1029.             vector<xml_node> parameters = findElements(source, "parameter");
  1030.             for(auto param : parameters)
  1031.             {
  1032.                 string name = param.attribute("name").value();
  1033.                 string value = param.attribute("value").value();
  1034.                 filterSpecialChars(value);
  1035.                 mediaSDP << SSRC_HEAD
  1036.                     << nSsrc
  1037.                     << " "
  1038.                     << name;
  1039.                 if(value.length() > 0)
  1040.                 {
  1041.                     mediaSDP << ":"
  1042.                         << value;
  1043.                 }
  1044.                 mediaSDP << LNEND;                                
  1045.             }
  1046.             // JRT: For some reason extra source is provided... But doesn't appear in
  1047.             // web client? What is it?            
  1048.         }
  1049.     }
  1050.     sdpInternal += mediaSDP.str();
  1051. }
  1052.  
  1053. string SDP::sdpStr()
  1054. {
  1055.     return sdpInternal;
  1056. }
  1057.  
  1058. void SDP::resetToHead()
  1059. {
  1060.     sdpInternal = SDP_HEADER;
  1061. }
  1062.  
  1063. /**
  1064.  * Construct new SDP instance from Jingle XML string.
  1065.  * Expects full IQ of containing the jingle element.
  1066.  */
  1067. void SDP::fromJingle(string jingle, SDP& sdp)
  1068. {  
  1069.     sdp.resetToHead();
  1070.     sdp.jingle.load_string(jingle.c_str());
  1071.    
  1072.     xpath_node jingleRoot = sdp.jingle.select_node("//*[local-name()='jingle']");
  1073.    
  1074.     vector<xml_node> groups = findElements(jingleRoot.node(), "group");
  1075.     for (xml_node group : groups)
  1076.     {
  1077.         string semantics = group.attribute("semantics").value();
  1078.         string type = group.attribute("type").value();
  1079.  
  1080.         vector<string> contentNames;
  1081.         vector<xml_node> groupContents = findElements(group, "content");
  1082.         for (xml_node content : groupContents)
  1083.         {
  1084.             contentNames.push_back(content.attribute("name").value());
  1085.         }
  1086.         string value;
  1087.         if(semantics.length() > 0) {
  1088.             value = semantics;
  1089.         }
  1090.         if(type.length() > 0) {
  1091.             value = type;
  1092.         }
  1093.         if(semantics.length() > 0 || type.length() > 0) {
  1094.             sdp.addGroup(value, contentNames);
  1095.         }
  1096.     }
  1097.  
  1098.     vector<xml_node> contents = findElements(jingleRoot.node(), "content");
  1099.     for(auto& content : contents)
  1100.         sdp.addMedia(content);
  1101. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement