Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  sdpUtils.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


var sdputils = {
  // Finds the codec id / payload type given a codec format
  // (e.g., "VP8", "VP9/90000"). `offset` tells us which one to use in case of
  // multiple matches.
  findCodecId(sdp, format, offset = 0) {
    let regex = new RegExp("rtpmap:([0-9]+) " + format, "gi");
    let match;
    for (let i = 0; i <= offset; ++i) {
      match = regex.exec(sdp);
      if (!match) {
        throw new Error(
          "Couldn't find offset " +
            i +
            " of codec " +
            format +
            " while looking for offset " +
            offset +
            " in sdp:\n" +
            sdp
        );
      }
    }
    // match[0] is the full matched string
    // match[1] is the first parenthesis group
    return match[1];
  },

  // Returns a list of all payload types, excluding rtx, in an sdp.
  getPayloadTypes(sdp) {
    const regex = /^a=rtpmap:([0-9]+) (?:(?!rtx).)*$/gim;
    const pts = [];
    for (const [line, pt] of sdp.matchAll(regex)) {
      pts.push(pt);
    }
    return pts;
  },

  // Finds all the extmap ids in the given sdp.  Note that this does NOT
  // consider m-sections, so a more generic version would need to
  // look at each m-section separately.
  findExtmapIds(sdp) {
    var sdpExtmapIds = [];
    extmapRegEx = /^a=extmap:([0-9+])/gm;
    // must call exec on the regex to get each match in the string
    while ((searchResults = extmapRegEx.exec(sdp)) !== null) {
      // returned array has the matched text as the first item,
      // and then one item for each capturing parenthesis that
      // matched containing the text that was captured.
      sdpExtmapIds.push(searchResults[1]);
    }
    return sdpExtmapIds;
  },

  findExtmapIdsUrnsDirections(sdp) {
    var sdpExtmap = [];
    extmapRegEx = /^a=extmap:([0-9+])([A-Za-z/]*) ([A-Za-z0-9_:#\-\/\.]+)/gm;
    // must call exec on the regex to get each match in the string
    while ((searchResults = extmapRegEx.exec(sdp)) !== null) {
      // returned array has the matched text as the first item,
      // and then one item for each capturing parenthesis that
      // matched containing the text that was captured.
      var idUrn = [];
      idUrn.push(searchResults[1]);
      idUrn.push(searchResults[3]);
      idUrn.push(searchResults[2].slice(1));
      sdpExtmap.push(idUrn);
    }
    return sdpExtmap;
  },

  verify_unique_extmap_ids(sdp) {
    const sdpExtmapIds = sdputils.findExtmapIdsUrnsDirections(sdp);

    return sdpExtmapIds.reduce(function (result, item, index) {
      const [id, urn, dir] = item;
      ok(
        !(id in result) || (result[id][0] === urn && result[id][1] === dir),
        "ID " + id + " is unique ID for " + urn + " and direction " + dir
      );
      result[id] = [urn, dir];
      return result;
    }, {});
  },

  getMSections(sdp) {
    return sdp
      .split(new RegExp("^m=""gm"))
      .slice(1)
      .map(s => "m=" + s);
  },

  getAudioMSections(sdp) {
    return this.getMSections(sdp).filter(section =>
      section.startsWith("m=audio")
    );
  },

  getVideoMSections(sdp) {
    return this.getMSections(sdp).filter(section =>
      section.startsWith("m=video")
    );
  },

  checkSdpAfterEndOfTrickle(description, testOptions, label) {
    info("EOC-SDP: " + JSON.stringify(description));

    const checkForTransportAttributes = msection => {
      info("Checking msection: " + msection);
      ok(
        msection.includes("a=end-of-candidates"),
        label + ": SDP contains end-of-candidates"
      );

      if (!msection.startsWith("m=application")) {
        if (testOptions.rtcpmux) {
          ok(
            msection.includes("a=rtcp-mux"),
            label + ": SDP contains rtcp-mux"
          );
        } else {
          ok(msection.includes("a=rtcp:"), label + ": SDP contains rtcp port");
        }
      }
    };

    const hasOwnTransport = msection => {
      const port0Check = new RegExp(/^m=\S+ 0 /).exec(msection);
      if (port0Check) {
        return false;
      }
      const midMatch = new RegExp(/\r\na=mid:(\S+)/).exec(msection);
      if (!midMatch) {
        return true;
      }
      const mid = midMatch[1];
      const bundleGroupMatch = new RegExp(
        "\\r\\na=group:BUNDLE \\S.* " + mid + "\\s+"
      ).exec(description.sdp);
      return bundleGroupMatch == null;
    };

    const msectionsWithOwnTransports = this.getMSections(
      description.sdp
    ).filter(hasOwnTransport);

    ok(
      msectionsWithOwnTransports.length,
      "SDP should contain at least one msection with a transport"
    );
    msectionsWithOwnTransports.forEach(checkForTransportAttributes);

    if (testOptions.ssrc) {
      ok(description.sdp.includes("a=ssrc"), label + ": SDP contains a=ssrc");
    } else {
      ok(
        !description.sdp.includes("a=ssrc"),
        label + ": SDP does not contain a=ssrc"
      );
    }
  },

  // Note, we don't bother removing the fmtp lines, which makes a good test
  // for some SDP parsing issues.
  removeCodec(sdp, codec) {
    var updated_sdp = sdp.replace(
      new RegExp("a=rtpmap:" + codec + ".*\\/90000\\r\\n"""),
      ""
    );
    updated_sdp = updated_sdp.replace(
      new RegExp("(RTP\\/SAVPF.*)( " + codec + ")(.*\\r\\n)"""),
      "$1$3"
    );
    updated_sdp = updated_sdp.replace(
      new RegExp("a=rtcp-fb:" + codec + " nack\\r\\n"""),
      ""
    );
    updated_sdp = updated_sdp.replace(
      new RegExp("a=rtcp-fb:" + codec + " nack pli\\r\\n"""),
      ""
    );
    updated_sdp = updated_sdp.replace(
      new RegExp("a=rtcp-fb:" + codec + " ccm fir\\r\\n"""),
      ""
    );
    return updated_sdp;
  },

  removeCodecs(sdp, codecs) {
    var updated_sdp = sdp;
    codecs.forEach(codec => {
      updated_sdp = this.removeCodec(updated_sdp, codec);
    });
    return updated_sdp;
  },

  removeAllButPayloadType(sdp, pt) {
    return sdp.replace(
      new RegExp("m=(\\w+ \\w+) UDP/TLS/RTP/SAVPF .*" + pt + ".*\\r\\n""gi"),
      "m=$1 UDP/TLS/RTP/SAVPF " + pt + "\r\n"
    );
  },

  removeRtpMapForPayloadType(sdp, pt) {
    return sdp.replace(new RegExp("a=rtpmap:" + pt + ".*\\r\\n""gi"), "");
  },

  removeRtcpMux(sdp) {
    return sdp.replace(/a=rtcp-mux\r\n/g, "");
  },

  removeSSRCs(sdp) {
    return sdp.replace(/a=ssrc.*\r\n/g, "");
  },

  removeBundle(sdp) {
    return sdp.replace(/a=group:BUNDLE .*\r\n/g, "");
  },

  reduceAudioMLineToPcmuPcma(sdp) {
    return sdp.replace(
      /m=audio .*\r\n/g,
      "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n"
    );
  },

  setAllMsectionsInactive(sdp) {
    return sdp
      .replace(/\r\na=sendrecv/g, "\r\na=inactive")
      .replace(/\r\na=sendonly/g, "\r\na=inactive")
      .replace(/\r\na=recvonly/g, "\r\na=inactive");
  },

  removeAllRtpMaps(sdp) {
    return sdp.replace(/a=rtpmap:.*\r\n/g, "");
  },

  reduceAudioMLineToDynamicPtAndOpus(sdp) {
    return sdp.replace(
      /m=audio .*\r\n/g,
      "m=audio 9 UDP/TLS/RTP/SAVPF 101 109\r\n"
    );
  },

  addTiasBps(sdp, bps) {
    return sdp.replace(/c=IN (.*)\r\n/g, "c=IN $1\r\nb=TIAS:" + bps + "\r\n");
  },

  removeSimulcastProperties(sdp) {
    return sdp
      .replace(/a=simulcast:.*\r\n/g, "")
      .replace(/a=rid:.*\r\n/g, "")
      .replace(
        /a=extmap:[^\s]* urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id.*\r\n/g,
        ""
      )
      .replace(
        /a=extmap:[^\s]* urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id.*\r\n/g,
        ""
      );
  },

  transferSimulcastProperties(offer_sdp, answer_sdp) {
    if (!offer_sdp.includes("a=simulcast:")) {
      return answer_sdp;
    }
    ok(
      offer_sdp.includes("a=simulcast:send "),
      "Offer contains simulcast attribute"
    );
    var o_simul = offer_sdp.match(/simulcast:send (.*)([\n$])*/i);
    var new_answer_sdp = answer_sdp + "a=simulcast:recv " + o_simul[1] + "\r\n";
    ok(offer_sdp.includes("a=rid:"), "Offer contains RID attribute");
    var o_rids = offer_sdp.match(/a=rid:(.*)/gi);
    o_rids.forEach(o_rid => {
      new_answer_sdp = new_answer_sdp + o_rid.replace(/send/, "recv") + "\r\n";
    });
    var extmap_id = offer_sdp.match(
      "a=extmap:([0-9+])/sendonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"
    );
    ok(extmap_id != null"Offer contains RID RTP header extension");
    new_answer_sdp =
      new_answer_sdp +
      "a=extmap:" +
      extmap_id[1] +
      "/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
    var extmap_id = offer_sdp.match(
      "a=extmap:([0-9+])/sendonly urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"
    );
    if (extmap_id != null) {
      new_answer_sdp =
        new_answer_sdp +
        "a=extmap:" +
        extmap_id[1] +
        "/recvonly urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\n";
    }

    return new_answer_sdp;
  },

  verifySdp(
    desc,
    expectedType,
    offerConstraintsList,
    offerOptions,
    testOptions
  ) {
    info("Examining this SessionDescription: " + JSON.stringify(desc));
    info("offerConstraintsList: " + JSON.stringify(offerConstraintsList));
    info("offerOptions: " + JSON.stringify(offerOptions));
    info("testOptions: " + JSON.stringify(testOptions));
    ok(desc, "SessionDescription is not null");
    is(desc.type, expectedType, "SessionDescription type is " + expectedType);
    ok(desc.sdp.length > 10, "SessionDescription body length is plausible");
    ok(desc.sdp.includes("a=ice-ufrag"), "ICE username is present in SDP");
    ok(desc.sdp.includes("a=ice-pwd"), "ICE password is present in SDP");
    ok(desc.sdp.includes("a=fingerprint"), "ICE fingerprint is present in SDP");
    //TODO: update this for loopback support bug 1027350
    ok(
      !desc.sdp.includes(LOOPBACK_ADDR),
      "loopback interface is absent from SDP"
    );
    var requiresTrickleIce = !desc.sdp.includes("a=candidate");
    if (requiresTrickleIce) {
      info("No ICE candidate in SDP -> requiring trickle ICE");
    } else {
      info("at least one ICE candidate is present in SDP");
    }

    //TODO: how can we check for absence/presence of m=application?

    var audioTracks =
      sdputils.countTracksInConstraint("audio", offerConstraintsList) ||
      (offerOptions && offerOptions.offerToReceiveAudio ? 1 : 0);

    info("expected audio tracks: " + audioTracks);
    if (audioTracks == 0) {
      ok(!desc.sdp.includes("m=audio"), "audio m-line is absent from SDP");
    } else {
      ok(desc.sdp.includes("m=audio"), "audio m-line is present in SDP");
      is(
        testOptions.opus,
        desc.sdp.includes("a=rtpmap:109 opus/48000/2"),
        "OPUS codec is present in SDP"
      );
      //TODO: ideally the rtcp-mux should be for the m=audio, and not just
      //      anywhere in the SDP (JS SDP parser bug 1045429)
      is(
        testOptions.rtcpmux,
        desc.sdp.includes("a=rtcp-mux"),
        "RTCP Mux is offered in SDP"
      );
    }

    var videoTracks =
      sdputils.countTracksInConstraint("video", offerConstraintsList) ||
      (offerOptions && offerOptions.offerToReceiveVideo ? 1 : 0);

    info("expected video tracks: " + videoTracks);
    if (videoTracks == 0) {
      ok(!desc.sdp.includes("m=video"), "video m-line is absent from SDP");
    } else {
      ok(desc.sdp.includes("m=video"), "video m-line is present in SDP");
      if (testOptions.h264) {
        ok(
          desc.sdp.includes("a=rtpmap:126 H264/90000") ||
            desc.sdp.includes("a=rtpmap:97 H264/90000") ||
            desc.sdp.includes("a=rtpmap:103 H264/90000") ||
            desc.sdp.includes("a=rtpmap:105 H264/90000"),
          "H.264 codec is present in SDP"
        );
      }
      if (testOptions.av1) {
        ok(
          desc.sdp.includes("a=rtpmap:99 AV1/90000"),
          "AV1 codec is present in SDP"
        );
      }
      if (!testOptions.h264 && !testOptions.av1) {
        ok(
          desc.sdp.includes("a=rtpmap:120 VP8/90000") ||
            desc.sdp.includes("a=rtpmap:121 VP9/90000"),
          "VP8 or VP9 codec is present in SDP"
        );
      }
      is(
        testOptions.rtcpmux,
        desc.sdp.includes("a=rtcp-mux"),
        "RTCP Mux is offered in SDP"
      );
      is(
        testOptions.ssrc,
        desc.sdp.includes("a=ssrc"),
        "a=ssrc signaled in SDP"
      );
    }

    return requiresTrickleIce;
  },

  /**
   * Counts the amount of audio tracks in a given media constraint.
   *
   * @param constraints
   *        The contraint to be examined.
   */

  countTracksInConstraint(type, constraints) {
    if (!Array.isArray(constraints)) {
      return 0;
    }
    return constraints.reduce((sum, c) => sum + (c[type] ? 1 : 0), 0);
  },
};

Messung V0.5
C=95 H=93 G=93

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge