Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "sdp.h"
- #include <algorithm>
- #include <sstream>
- #include <iostream>
- #include <regex>
- #include <string.h>
- SDP::SDP(string sdpInternal, string videoId, string audioId)
- {
- this->sdpInternal = sdpInternal;
- this->videoId = videoId;
- this->audioId = audioId;
- }
- SDP::SDP() : SDP("", "", "") {
- }
- string join(vector<string> sv, string delimeter) {
- stringstream joined;
- int index = 0;
- int len = sv.size();
- for(auto& s : sv) {
- joined << s;
- index ++;
- if(index != len) {
- joined << delimeter;
- }
- }
- return joined.str();
- }
- vector<xml_node> findElements(pugi::xml_node node, const char* name)
- {
- vector<xml_node> result;
- for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
- {
- if (strcmp(child.name(), name) == 0)
- result.push_back(child);
- const char* colon = strchr(child.name(), ':');
- if (colon && strcmp(colon + 1, name) == 0)
- result.push_back(child);
- }
- return result;
- }
- pugi::xml_node findElement(pugi::xml_node node, const char* name)
- {
- for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
- {
- if (strcmp(child.name(), name) == 0)
- return child;
- const char* colon = strchr(child.name(), ':');
- if (colon && strcmp(colon + 1, name) == 0)
- return child;
- }
- return pugi::xml_node();
- }
- vector<string> regexSplit(const string& toSplit, const string& rgx)
- {
- regex re(rgx);
- sregex_token_iterator
- first{toSplit.begin(), toSplit.end(), re, -1},
- last;
- return {first, last};
- }
- string findLine(string sdp, string header)
- {
- vector<string> lines = regexSplit(sdp, "[\r\n]+");
- for(string line : lines) {
- if(line.find(header) == 0) {
- return line;
- }
- }
- return "";
- }
- string RandomString(int length)
- {
- stringstream randomStr;
- const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- for(int i = 0; i < length; i ++)
- randomStr << chars[rand() % chars.length()];
- return randomStr.str();
- }
- vector<string> findLines(string sdp, string header)
- {
- vector<string> results;
- vector<string> lines = regexSplit(sdp, "[\r\n]+");
- for(string line : lines) {
- if(line.find(header) == 0) {
- results.push_back(line);
- }
- }
- return results;
- }
- vector<string> SDP::getMedias(string sdp)
- {
- vector<string> medias;
- vector<string> mediaReg = regexSplit(sdp, "[\r\n]+m=");
- int mSize = mediaReg.size();
- for(int i = 0; i < mSize; i ++)
- {
- stringstream media_i;
- media_i << "m=" << mediaReg[i];
- if(i != mSize - 1)
- {
- media_i << "\r\n";
- }
- medias.push_back(media_i.str());
- }
- return medias;
- }
- xml_node SDP::parseRtpMap(string rtpmap, xml_node parent)
- {
- xml_node payloadType = parent.append_child("payload-type");
- vector<string> parts = regexSplit(rtpmap.substr(RTP_MAP_HEAD.length()), "[\\s/]+");
- if(parts.size() >= 3)
- {
- payloadType.append_attribute("id") = parts[0].c_str();
- payloadType.append_attribute("name") = parts[1].c_str();
- payloadType.append_attribute("clockrate") = parts[2].c_str();
- }
- if(parts.size() > 3)
- {
- payloadType.append_attribute("channels") = parts[3].c_str();
- }
- return payloadType;
- }
- void SDP::rtcpFbToJingle(string media, string payloadType, xml_node parent)
- {
- vector<string> lines = findLines(media, RTCP_FB_HEAD + payloadType);
- for(string line : lines)
- {
- smatch match;
- if(regex_search(line, match, regex(RTCP_FB_HEAD + payloadType + " (.+)")))
- {
- vector<string> rtcpFbItems = regexSplit(match[1], " ");
- string rtcpFbType;
- if(rtcpFbItems.size() > 0)
- rtcpFbType = rtcpFbItems[0];
- rtcpFbItems.erase(rtcpFbItems.begin());
- if(rtcpFbType == "trr-int")
- {
- xml_node rtcpTrr = parent.append_child("rtcp-fb-trr-int");
- rtcpTrr.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
- if(rtcpFbItems.size() > 0)
- rtcpTrr.append_attribute("value") = rtcpFbItems[0].c_str();
- }
- else
- {
- xml_node rtcpElem = parent.append_child("rtcp-fb");
- rtcpElem.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
- rtcpElem.append_attribute("type") = rtcpFbType.c_str();
- if(rtcpFbItems.size() > 0)
- rtcpElem.append_attribute("subtype") = rtcpFbItems[0].c_str();
- }
- }
- }
- }
- void SDP::parseExtMap(string extmap, xml_node parent)
- {
- xml_node rtpHdrExt = parent.append_child("rtp-hdrext");
- rtpHdrExt.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0";
- vector<string> parts = regexSplit(extmap.substr(EXT_MAP_HEAD.length()), "[\\s]+");
- if(parts.size() > 0)
- {
- if(parts[0].find("/") != string::npos)
- {
- string direction = parts[0].substr(parts[0].find("/") + 1);
- string value = parts[0].substr(0, parts[0].find("/"));
- rtpHdrExt.append_attribute("id") = value.c_str();
- rtpHdrExt.append_attribute("direction") = direction.c_str();
- }
- else
- {
- rtpHdrExt.append_attribute("id") = parts[0].c_str();
- }
- }
- if(parts.size() > 1)
- {
- rtpHdrExt.append_attribute("uri") = parts[1].c_str();
- }
- string direction = rtpHdrExt.attribute("direction").value();
- if(direction.length() > 0)
- {
- if(direction == "sendonly")
- {
- rtpHdrExt.append_attribute("senders") = "responder";
- }
- else if(direction == "recvonly")
- {
- rtpHdrExt.append_attribute("senders") = "initiator";
- }
- else if(direction == "sendrecv")
- {
- rtpHdrExt.append_attribute("senders") = "both";
- }
- else if(direction == "inactive")
- {
- rtpHdrExt.append_attribute("senders") = "none";
- }
- }
- }
- void SDP::parseSctpMap(string sctpMap, xml_node parent)
- {
- xml_node sctpMapEl = parent.append_child("sctpmap");
- sctpMapEl.append_attribute("xmlns") = "urn:xmpp:jingle:transpoorts:dtls-sctp:1";
- vector<string> parts = regexSplit(sctpMap.substr(SCTP_MAP_HEAD.length()), " ");
- if(parts.size() >= 2)
- {
- sctpMapEl.append_attribute("number") = parts[0].c_str();
- sctpMapEl.append_attribute("protocol") = parts[1].c_str();
- }
- if(parts.size() > 2)
- {
- sctpMapEl.append_attribute("streams") = parts[2].c_str();
- }
- }
- xml_node SDP::parseFingerprint(string fingerprint, xml_node parent)
- {
- xml_node fingerEl = parent.append_child("fingerprint");
- fingerEl.append_attribute("xmlns") = "urn:xmpp:jingle:apps:dtls:0";
- vector<string> parts = regexSplit(fingerprint.substr(FINGERPRINT_HEAD.length()), " ");
- if(parts.size() >= 2)
- {
- fingerEl.append_attribute("hash") = parts[0].c_str();
- fingerEl.text().set(parts[1].c_str());
- }
- return fingerEl;
- }
- void SDP::candidateToJingle(string candidateLine, xml_node parent)
- {
- xml_node candidate = parent.append_child("candidate");
- candidate.append_attribute("xmlns") = "urn:xmpp:jingle:transports:ice-udp:1";
- if(candidateLine.find("candidate:") != 0)
- {
- cerr << "Candidate parser called with invalid candidate line " << candidateLine << endl;
- return;
- }
- if(candidateLine.length() > 2 &&
- candidateLine.substr(candidateLine.length() - 2) == "\r\n")
- {
- candidateLine = candidateLine.substr(0, candidateLine.length() - 2);
- }
- vector<string> elems = regexSplit(candidateLine, " ");
- if(elems.size() >= 7 && elems[6] != "typ")
- {
- cerr << "Invalid Candidate Line " << candidateLine << " typ not located in correct location." << endl;
- return;
- }
- if(elems.size() >= 8)
- {
- candidate.append_attribute("foundation") = elems[0].substr(CAND_HEAD.length()).c_str();
- candidate.append_attribute("component") = elems[1].c_str();
- candidate.append_attribute("protocol") = elems[2].c_str();
- candidate.append_attribute("priority") = elems[3].c_str();
- candidate.append_attribute("ip") = elems[4].c_str();
- candidate.append_attribute("port") = elems[5].c_str();
- candidate.append_attribute("type") = elems[7].c_str();
- }
- xml_attribute generation = candidate.append_attribute("generation");
- generation = "0";
- for(int i = 8; i < elems.size(); i ++)
- {
- if(elems[i] == "raddr")
- {
- candidate.append_attribute("rel-addr") = elems[i+1].c_str();
- }
- else if(elems[i] == "rport")
- {
- candidate.append_attribute("rel-port") = elems[i+1].c_str();
- }
- else if(elems[i] == "generation")
- {
- generation = elems[i+1].c_str();
- }
- else if(elems[i] == "tcptype")
- {
- candidate.append_attribute("tcptype") = elems[i+1].c_str();
- }
- else
- {
- cout << "Not translating " << elems[i] << endl;
- }
- }
- candidate.append_attribute("network") = "1";
- candidate.append_attribute("id") = RandomString(7).c_str();
- return;
- }
- void SDP::transportToJingle(string media, string session, vector<string>& candidatesProvided, xml_node parent)
- {
- string ufrag = findLine(media, ICE_UFRAG_HEAD);
- if(ufrag.length() == 0)
- ufrag = findLine(session, ICE_UFRAG_HEAD);
- string pwd = findLine(media, ICE_PWD_HEAD);
- if(pwd.length() == 0)
- pwd = findLine(session, ICE_PWD_HEAD);
- xml_node rtpHdrExt = parent.append_child("transport");
- if(ufrag.length() > 0 && pwd.length() > 0)
- {
- rtpHdrExt.append_attribute("xmlns") = "urn:xmpp:jingle:transports:ice-udp:1";
- ufrag = ufrag.substr(ICE_UFRAG_HEAD.length());
- pwd = pwd.substr(ICE_PWD_HEAD.length());
- }
- string sctpMap = findLine(media, SCTP_MAP_HEAD);
- if(sctpMap.length() > 0)
- parseSctpMap(sctpMap, rtpHdrExt);
- vector<string> fingerprints = findLines(media, FINGERPRINT_HEAD);
- vector<string> sessionFingerPrints = findLines(session, FINGERPRINT_HEAD);
- for(string line : fingerprints)
- {
- xml_node fingerprint = parseFingerprint(line, rtpHdrExt);
- string setupLine = findLine(media, SETUP_HEAD);
- if(setupLine.length() > 0)
- {
- fingerprint.append_attribute("setup") = setupLine.substr(SETUP_HEAD.length()).c_str();
- }
- }
- for(string line : sessionFingerPrints)
- {
- xml_node fingerprint = parseFingerprint(line, rtpHdrExt);
- string setupLine = findLine(media, SETUP_HEAD);
- if(setupLine.length() > 0)
- {
- fingerprint.append_attribute("setup") = setupLine.substr(SETUP_HEAD.length()).c_str();
- }
- }
- if(ufrag.length() > 0 && pwd.length() > 0)
- {
- rtpHdrExt.append_attribute("ufrag") = ufrag.c_str();
- rtpHdrExt.append_attribute("pwd") = pwd.c_str();
- }
- vector<string> candidates = findLines(media, CAND_HEAD);
- vector<string> sesCandidates = findLines(session, CAND_HEAD);
- for(string candidateLine : candidates)
- candidateToJingle(candidateLine, rtpHdrExt);
- for(string candidateLine : sesCandidates)
- candidateToJingle(candidateLine, rtpHdrExt);
- if(candidatesProvided.size() > 0)
- {
- for(string candidateLine : candidatesProvided)
- {
- candidateToJingle(candidateLine, rtpHdrExt);
- }
- }
- return;
- }
- string SDP::createJingle(bool isResponder, string to, string from,
- string sid, vector<string>& candidates)
- {
- xml_document doc;
- xml_node iq = doc.append_child("iq");
- iq.append_attribute("xmlns") = "jabber:client";
- iq.append_attribute("type") = "set";
- iq.append_attribute("to") = to.c_str();
- iq.append_attribute("from") = from.c_str();
- iq.append_attribute("id") = "MX_3";
- xml_node jingle = iq.append_child("jingle");
- jingle.append_attribute("xmlns") = "urn:xmpp:jingle:1";
- jingle.append_attribute("initiator") = to.c_str();
- jingle.append_attribute("action") = isResponder?"session-accept":"session-initiate";
- jingle.append_attribute("sid") = sid.c_str();
- if(this->sdpInternal.length() > 0)
- {
- vector<string> groups = findLines(sdpInternal, GROUP_TAG);
- for(string group : groups)
- {
- vector<string> tokens = regexSplit(group, " ");
- if(tokens.size() >= 1)
- {
- string semantics = tokens[0].substr(GROUP_TAG.length());
- xml_node el = jingle.append_child("group");
- el.append_attribute("xmlns") = "urn:xmpp:jingle:apps:grouping:0";
- el.append_attribute("semantics") = semantics.c_str();
- for(int i = 1; i < tokens.size(); i ++)
- {
- string cName = tokens[i];
- xml_node content = el.append_child("content");
- content.append_attribute("name") = cName.c_str();
- }
- }
- }
- vector<string> medias = getMedias(sdpInternal);
- if(medias.size() > 0) {
- string session = medias[0] + "\r\n";
- // Skip Session.
- medias.erase(medias.begin());
- for(string media : medias)
- {
- string mLine = regexSplit(media, "[\r\n]+")[0];
- smatch matches;
- if(regex_search(mLine, matches,
- regex(MEDIA_HEAD +
- "(video|audio|application) (\\d+) ([A-Za-z/]+) ([\\d\\s]+)"))
- && matches.size() >= 4
- )
- {
- string ssrc;
- string mediaName = matches[1];
- string mediaPort = matches[2];
- string mediaProto = matches[3];
- vector<string> mediaFmts = regexSplit(matches[4], " ");
- string aSsrcLine = findLine(media, SSRC_HEAD);
- if(aSsrcLine.length() > 0)
- {
- ssrc = regexSplit(aSsrcLine.substr(SSRC_HEAD.length()), " ")[0];
- }
- xml_node content = jingle.append_child("content");
- content.append_attribute("creator") = isResponder ? "responder" : "initiator";
- xml_attribute content_name = content.append_attribute("name");
- content_name = mediaName.c_str();
- string aMid = findLine(media, MID_HEAD);
- if(aMid.length() > 0)
- {
- smatch midMatch;
- if(regex_search(aMid, midMatch, regex(MID_HEAD + "(video|audio|data)")))
- {
- string midName = midMatch[1];
- if(midName.length() > 0)
- content_name = midName.c_str();
- }
- }
- string rtpMap = findLine(media, RTP_MAP_HEAD);
- if(rtpMap.length() > 0)
- {
- xml_node desc = content.append_child("description");
- desc.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:1";
- desc.append_attribute("media") = mediaName.c_str();
- if(ssrc.length() > 0)
- {
- desc.append_attribute("ssrc") = ssrc.c_str();
- }
- for(string fmt : mediaFmts)
- {
- string rtpmap = findLine(media, RTP_MAP_HEAD + fmt);
- if(rtpmap.length() > 0)
- {
- xml_node payloadType = parseRtpMap(rtpmap, desc);
- string fmtpLine = findLine(media, FORMAT_PARAM_HEAD + fmt);
- if(fmtpLine.length() > 0)
- {
- // a=fmtp:111 minptime=10; useinbandfec=1
- smatch fmtpPar;
- if(regex_search(fmtpLine, fmtpPar, regex(FORMAT_PARAM_HEAD + fmt + " ([a-zA-Z0-9=; ]+)")))
- {
- string fmtpParams = fmtpPar[1];
- vector<string> fmtpParamList = regexSplit(fmtpParams, ";");
- for(string paramEl : fmtpParamList)
- {
- smatch paramKeyVal;
- if(regex_search(paramEl, paramKeyVal, regex("([a-zA-Z]+)=([a-zA-Z\\-\\d]+)")))
- {
- string key = paramKeyVal[1];
- string value = paramKeyVal[2];
- xml_node paramXEl = payloadType.append_child("parameter");
- paramXEl.append_attribute("name") = key.c_str();
- paramXEl.append_attribute("value") = value.c_str();
- }
- }
- }
- }
- // rtcpFb
- rtcpFbToJingle(media, fmt, payloadType);
- }
- }
- if(ssrc.length() > 0)
- {
- xml_node source = desc.append_child("source");
- source.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
- source.append_attribute("ssrc") = ssrc.c_str();
- vector<string> ssrcLines = findLines(media, SSRC_HEAD);
- if(ssrcLines.size() > 0)
- {
- xml_node nSource = source;
- for(string ssrcLine : ssrcLines)
- {
- string::size_type idx = ssrcLine.find(" ");
- string lineSsrc = ssrcLine.substr(0, idx).substr(SSRC_HEAD.length());
- if(lineSsrc != ssrc)
- {
- ssrc = lineSsrc;
- nSource = desc.append_child("source");
- nSource.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
- nSource.append_attribute("ssrc") = ssrc.c_str();
- }
- string kv = ssrcLine.substr(idx + 1);
- xml_node parameter = nSource.append_child("parameter");
- if(kv.find(":") == string::npos)
- {
- parameter.append_attribute("name") = kv.c_str();
- }
- else {
- vector<string> kVSplit = regexSplit(kv, ":");
- parameter.append_attribute("name") = kVSplit[0].c_str();
- parameter.append_attribute("value") = kVSplit[1].c_str();
- }
- }
- }
- else {
- xml_node parameter = source.append_child("parameter");
- parameter.append_attribute("cname") = RandomString(7).c_str();
- string msid;
- if(mediaName == "audio")
- {
- msid = audioId;
- }
- else
- {
- msid = videoId;
- }
- if(msid.length() > 0)
- {
- msid = filterSpecialChars(msid);
- xml_node msIdParam = source.append_child("parameter");
- msIdParam.append_attribute("name") = "msid";
- msIdParam.append_attribute("value") = msid.c_str();
- xml_node msLabelParam = source.append_child("parameter");
- msLabelParam.append_attribute("name") = "mslabel";
- msLabelParam.append_attribute("value") = msid.c_str();
- xml_node parameterParam = source.append_child("parameter");
- parameterParam.append_attribute("name") = "mslabel";
- parameterParam.append_attribute("value") = msid.c_str();
- }
- }
- vector<string> ssrcGroupLines = findLines(media, SSRC_GROUP_HEAD);
- for(string line : ssrcGroupLines)
- {
- int idx = line.find(" ");
- string semantics = line.substr(0, idx).substr(SSRC_GROUP_HEAD.length());
- vector<string> ssrcs = regexSplit(line.substr(SSRC_GROUP_HEAD.length() + semantics.length()), " ");
- if(ssrcs.size() > 0)
- {
- xml_node ssrcGroup = desc.append_child("ssrc-group");
- ssrcGroup.append_attribute("xmlns") = "urn:xmpp:jingle:apps:rtp:ssma:0";
- ssrcGroup.append_attribute("semantics") = semantics.c_str();
- for(string ssrcL : ssrcs)
- {
- xml_node ssrcGroupSrc = ssrcGroup.append_child("source");
- ssrcGroupSrc.append_attribute("ssrc") = ssrc.c_str();
- }
- }
- }
- }
- string rtcpMuxLine = findLine(media, RTCP_MUX);
- if(rtcpMuxLine.length() > 0)
- desc.append_child("rtcp-mux");
- rtcpFbToJingle(media, "*", desc);
- vector<string> extmapLines = findLines(media, EXT_MAP_HEAD);
- if(extmapLines.size() > 0)
- {
- for(int j = 0; j < extmapLines.size(); j ++)
- {
- parseExtMap(extmapLines[j], desc);
- }
- }
- }
- transportToJingle(media, session, candidates, content);
- if(findLine(media, "a=sendrecv").length() > 0 ||
- findLine(session, "a=sendrecv").length() > 0)
- {
- content.append_attribute("senders") = "both";
- }
- else if(findLine(media, "a=sendonly").length() > 0 ||
- findLine(session, "a=sendonly").length() > 0)
- {
- content.append_attribute("senders") = "initiator";
- }
- else if(findLine(media, "a=recvonly").length() > 0 ||
- findLine(session, "a=recvonly").length() > 0)
- {
- content.append_attribute("senders") = "responder";
- }
- else if(findLine(media, "a=none").length() > 0 ||
- findLine(session, "a=none").length() > 0)
- {
- content.append_attribute("senders") = "rejected";
- }
- }
- }
- }
- }
- stringstream xmlResult;
- doc.print(xmlResult);
- return xmlResult.str();
- }
- void SDP::addGroup(string groupSemanticsOrType, vector<string> names) {
- stringstream groupss;
- groupss << GROUP_TAG << groupSemanticsOrType << " " << join(names, " ") << LNEND;
- sdpInternal += groupss.str();
- }
- string SDP::buildMLine(int port, string media,
- string proto, vector<int> fmt) {
- stringstream format;
- int fmtSize = fmt.size();
- for(int i = 0; i < fmtSize; i++) {
- format << fmt[i];
- if(i != fmtSize - 1) {
- format << " ";
- }
- }
- stringstream mLine;
- mLine << MEDIA_HEAD << media << " " << port << " " << proto << " " << format.str();
- return mLine.str();
- }
- string SDP::buildIceUFrag(string uFrag)
- {
- stringstream iceUFrag;
- iceUFrag << ICE_UFRAG_HEAD
- << uFrag;
- return iceUFrag.str();
- }
- string SDP::buildIcePwd(string pwd)
- {
- stringstream icePwd;
- icePwd << ICE_PWD_HEAD
- << pwd;
- return icePwd.str();
- }
- string SDP::buildRtpMap(xml_node payload)
- {
- stringstream rtpMap;
- rtpMap << RTP_MAP_HEAD
- << payload.attribute("id").value()
- << " "
- << payload.attribute("name").value()
- << "/"
- << payload.attribute("clockrate").value();
- string channels = payload.attribute("channels").value();
- if(channels.length() > 0 && channels != "1")
- {
- rtpMap << "/"
- << channels;
- }
- return rtpMap.str();
- }
- string SDP::filterSpecialChars(string value)
- {
- regex_replace(value, regex("[\\\\\\/\\{,\\}\\+]"), "");
- }
- string SDP::rtcpFbFromJingle(xml_node el, string payloadType)
- {
- stringstream media;
- vector<xml_node> rtcpFbTrrInts = findElements(el, "rtcp-fb-trr-int");
- for(auto rtcpFbTrrInt : rtcpFbTrrInts)
- {
- media << RTCP_FB_HEAD
- << "* trr-int";
- string rtcpTrrVal = rtcpFbTrrInt.attribute("value").value();
- if(rtcpTrrVal.length() > 0)
- {
- media << rtcpTrrVal;
- }
- else
- media << "0";
- media << LNEND;
- }
- vector<xml_node> rtcpFbs = findElements(el, "rtcp-fb");
- for(auto rtcpFb : rtcpFbs)
- {
- media << RTCP_FB_HEAD
- << payloadType
- << " "
- << rtcpFb.attribute("type").value();
- string subType = rtcpFb.attribute("subtype").value();
- if(subType.length() > 0)
- {
- media << " "
- << subType;
- }
- media << LNEND;
- }
- return media.str();
- }
- string SDP::candidateFromJingle(xml_node candidate)
- {
- string protocol = candidate.attribute("protocol").value();
- stringstream line;
- line << CAND_HEAD
- << candidate.attribute("foundation").value()
- << " "
- << candidate.attribute("component").value()
- << " "
- << protocol
- << " "
- << candidate.attribute("priority").value()
- << " "
- << candidate.attribute("ip").value()
- << " "
- << candidate.attribute("port").value()
- << " typ "
- << candidate.attribute("type").value()
- << " ";
- string typ = candidate.attribute("type").value();
- if(typ == "srflx" || typ == "prflx" || typ == "relay")
- {
- line << "raddr"
- << " "
- << candidate.attribute("rel-addr").value()
- << " "
- << "rport"
- << " "
- << candidate.attribute("rel-port").value()
- << " ";
- }
- if(protocol == "tcp")
- {
- line << "tcptype"
- << " "
- << candidate.attribute("tcptype").value()
- << " ";
- }
- line << "generation"
- << " "
- << candidate.attribute("generation").value()
- << LNEND;
- return line.str();
- }
- void SDP::addMedia(xml_node content) {
- int port = 1;
- string proto = "RTP/SAVPF";
- stringstream mediaSDP;
- xml_node desc = findElement(content, "description");
- string ssrc = desc.attribute("ssrc").value();
- xml_node transp = findElement(content, "transport");
- if(find(ssrcsAdded.begin(), ssrcsAdded.end(), ssrc)
- != ssrcsAdded.end()) {
- cerr << "Attempted to add existing SSRC " << ssrc << endl;
- return;
- }
- xml_node sctpElement;
- // Determine if SCTP is being used.
- if(transp) {
- sctpElement = findElement(transp, "sctpmap");
- }
- string media = desc.attribute("media").value();
- if(string(content
- .attribute("senders").value())
- .length() != 0 &&
- string(content
- .attribute("senders").value()) == "rejected") {
- port = 0;
- }
- xml_node fingerprint;
- if(transp)
- fingerprint = findElement(transp, "fingerprint");
- xml_node encryption;
- if(desc)
- encryption = findElement(transp, "encryption");
- if(fingerprint || encryption) {
- proto = (sctpElement) ? DTLS_SRTP : RTP_SAVPF;
- }
- if(!sctpElement) {
- vector<xml_node> payloadTypes = findElements(desc, "payload-type");
- vector<int> payloadTypeAr;
- for(auto payloadType : payloadTypes) {
- payloadTypeAr.push_back(payloadType
- .attribute("id").as_int());
- //cout << "PUSHING PAYLOAD TYPE " << payloadType.attribute("id").as_int() << endl;
- }
- string mLine = buildMLine(port, media, proto, payloadTypeAr);
- mediaSDP << mLine << LNEND;
- }
- else {
- mediaSDP << SCTP_APPLICATION_HEAD
- << " "
- << sctpElement.attribute("number").value()
- << LNEND;
- mediaSDP << SCTP_MAP_HEAD
- << sctpElement.attribute("number").value()
- << " "
- << sctpElement.attribute("protocol").value();
- string streamsAt = sctpElement.attribute("streams").value();
- if(streamsAt.length() > 0) {
- int streamCount = std::stoi(streamsAt);
- if(streamCount >= 0) {
- mediaSDP << " "
- << streamCount
- << LNEND;
- }
- else
- mediaSDP << LNEND;
- }
- else
- mediaSDP << LNEND;
- }
- mediaSDP << C_MEDIA_HEAD;
- if(!sctpElement)
- {
- mediaSDP << RTCP_MEDIA_HEAD;
- }
- if(transp)
- {
- string uFrag = transp.attribute("ufrag").value();
- string pwd = transp.attribute("pwd").value();
- if(uFrag.length() > 0) {
- mediaSDP << buildIceUFrag(uFrag)
- << LNEND;
- }
- if(pwd.length() > 0) {
- mediaSDP << buildIcePwd(pwd)
- << LNEND;
- }
- vector<xml_node> fingerprints = findElements(transp, "fingerprint");
- for(auto el : fingerprints)
- {
- mediaSDP << FINGERPRINT_HEAD
- << el.attribute("hash").value()
- << " "
- << el.child_value()
- << LNEND;
- string setup = el.attribute("setup").value();
- if(setup.length() > 0)
- {
- mediaSDP << SETUP_HEAD
- << setup
- << LNEND;
- }
- }
- }
- mediaSDP << SENDER_TO_ALINE[content
- .attribute("senders").value()]
- << LNEND;
- mediaSDP << MID_HEAD
- << content.attribute("name").value()
- << LNEND;
- if(findElement(desc, "rtcp-mux"))
- {
- mediaSDP << RTCP_MUX << LNEND;
- }
- vector<xml_node> encryptions = findElements(desc, "encryption");
- for(auto en : encryptions)
- {
- vector<xml_node> cryptos = findElements(en, "crypto");
- for(auto crypt : cryptos)
- {
- mediaSDP << CRYPT_HEAD
- << crypt.attribute("tag").value()
- << " "
- << crypt.attribute("crypto-suite").value()
- << " "
- << crypt.attribute("key-params").value();
- string sessionParams = crypt.attribute("session-params").value();
- if(sessionParams.length() > 0)
- {
- mediaSDP << " "
- << sessionParams;
- }
- mediaSDP << LNEND;
- }
- }
- vector<xml_node> payloads = findElements(desc, "payload-type");
- for(auto payload : payloads)
- {
- mediaSDP << buildRtpMap(payload)
- << LNEND;
- vector<xml_node> parameters = findElements(payload, "parameter");
- if(parameters.size() > 0)
- {
- mediaSDP << FORMAT_PARAM_HEAD
- << payload.attribute("id").value()
- << " ";
- stringstream parameterLine;
- for(int i = 0; i < parameters.size(); i ++)
- {
- xml_node parameter = parameters[i];
- string name = parameter.attribute("name").value();
- if(name.length() > 0)
- {
- parameterLine << name
- << "="
- << parameter.attribute("value").value();
- if(i != parameters.size() - 1)
- parameterLine << "; ";
- }
- }
- mediaSDP << parameterLine.str()
- << LNEND;
- }
- // http://www.xmpp.org/extensions/xep-0293.html
- mediaSDP << rtcpFbFromJingle(payload, payload.attribute("id").value());
- }
- mediaSDP << rtcpFbFromJingle(desc, "*");
- // http://www.xmpp.org/extensions/xep-0294.html
- vector<xml_node> rtpHdrExts = findElements(desc, "rtp-hdrext");
- for(xml_node rtpHdrExt : rtpHdrExts)
- {
- mediaSDP << EXT_MAP_HEAD
- << rtpHdrExt.attribute("id").value()
- << " "
- << rtpHdrExt.attribute("uri").value()
- << LNEND;
- }
- vector<xml_node> candidates;
- if(transp)
- candidates = findElements(transp, "candidate");
- for(auto cand : candidates)
- {
- string protocol = cand.attribute("protocol").value();
- if(protocol.length() > 0)
- {
- //std::transform(protocol.begin(),
- // protocol.end(), protocol.begin(), ::tolower);
- mediaSDP << candidateFromJingle(cand);
- }
- }
- if(desc)
- {
- vector<xml_node> ssrcGroups = findElements(desc, "ssrc-group");
- for(xml_node ssrcGroup : ssrcGroups)
- {
- string semantics = ssrcGroup.attribute("semantics").value();
- vector<xml_node> ssrcs = findElements(ssrcGroup, "source");
- stringstream ssrcStr;
- for(int i = 0; i < ssrcs.size(); i ++)
- {
- xml_node ssrc = ssrcs[i];
- string sStr = ssrc.attribute("ssrc").value();
- ssrcStr << sStr;
- if(sStr.length() > 0)
- {
- // Keep track of the fact this SDP contains this ssrc.
- ssrcsAdded.push_back(sStr);
- }
- if(i != ssrcs.size() -1)
- {
- ssrcStr << " ";
- }
- }
- mediaSDP << SSRC_GROUP_HEAD
- << semantics
- << " "
- << ssrcStr.str()
- << LNEND;
- }
- vector<xml_node> sources = findElements(desc, "source");
- for(auto source : sources)
- {
- string nSsrc = source.attribute("ssrc").value();
- vector<xml_node> parameters = findElements(source, "parameter");
- for(auto param : parameters)
- {
- string name = param.attribute("name").value();
- string value = param.attribute("value").value();
- filterSpecialChars(value);
- mediaSDP << SSRC_HEAD
- << nSsrc
- << " "
- << name;
- if(value.length() > 0)
- {
- mediaSDP << ":"
- << value;
- }
- mediaSDP << LNEND;
- }
- // JRT: For some reason extra source is provided... But doesn't appear in
- // web client? What is it?
- }
- }
- sdpInternal += mediaSDP.str();
- }
- string SDP::sdpStr()
- {
- return sdpInternal;
- }
- void SDP::resetToHead()
- {
- sdpInternal = SDP_HEADER;
- }
- /**
- * Construct new SDP instance from Jingle XML string.
- * Expects full IQ of containing the jingle element.
- */
- void SDP::fromJingle(string jingle, SDP& sdp)
- {
- sdp.resetToHead();
- sdp.jingle.load_string(jingle.c_str());
- xpath_node jingleRoot = sdp.jingle.select_node("//*[local-name()='jingle']");
- vector<xml_node> groups = findElements(jingleRoot.node(), "group");
- for (xml_node group : groups)
- {
- string semantics = group.attribute("semantics").value();
- string type = group.attribute("type").value();
- vector<string> contentNames;
- vector<xml_node> groupContents = findElements(group, "content");
- for (xml_node content : groupContents)
- {
- contentNames.push_back(content.attribute("name").value());
- }
- string value;
- if(semantics.length() > 0) {
- value = semantics;
- }
- if(type.length() > 0) {
- value = type;
- }
- if(semantics.length() > 0 || type.length() > 0) {
- sdp.addGroup(value, contentNames);
- }
- }
- vector<xml_node> contents = findElements(jingleRoot.node(), "content");
- for(auto& content : contents)
- sdp.addMedia(content);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement