Best JavaScript code snippet using wpt
index.js
Source:index.js  
1/* Copyright @ 2016 Atlassian Pty Ltd2 *3 * Licensed under the Apache License, Version 2.0 (the "License");4 * you may not use this file except in compliance with the License.5 * You may obtain a copy of the License at6 *7 *     http://www.apache.org/licenses/LICENSE-2.08 *9 * Unless required by applicable law or agreed to in writing, software10 * distributed under the License is distributed on an "AS IS" BASIS,11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12 * See the License for the specific language governing permissions and13 * limitations under the License.14 */15var transform = require('sdp-transform');16var transformUtils = require('./transform-utils');17var parseSsrcs = transformUtils.parseSsrcs;18var writeSsrcs = transformUtils.writeSsrcs;19//region Constants20var DEFAULT_NUM_OF_LAYERS = 3;21//endregion22function getSsrcAttribute (mLine, ssrc, attributeName) {23    return mLine24        .ssrcs25        .filter(function(ssrcInfo) { return ssrcInfo.id === ssrc; })26        .filter(function(ssrcInfo) { return ssrcInfo.attribute === attributeName; })27        .map(function(ssrcInfo) { return ssrcInfo.value; })[0];28}29//region Ctor30function Simulcast(options) {31    this.options = options ? options : {};32    if (!this.options.numOfLayers) {33        this.options.numOfLayers = DEFAULT_NUM_OF_LAYERS;34    }35    console.log("SdpSimulcast: using " + this.options.numOfLayers + " layers");36    /**37     * An IN-ORDER list of the simulcast ssrcs38     * @type {list<number>}39     */40    this.ssrcCache = [];41}42//endregion43//region Stateless private utility functions44/**45 * Returns a random integer between min (included) and max (excluded)46 * Using Math.round() gives a non-uniform distribution!47 * @returns {number}48 */49function generateSSRC() {50    var min = 0, max = 0xffffffff;51    return Math.floor(Math.random() * (max - min)) + min;52};53function processVideo(session, action) {54    if (session == null || !Array.isArray(session.media)) {55        return;56    }57    session.media.forEach(function (mLine) {58        if (mLine.type === 'video') {59            action(mLine);60        }61    });62};63function validateDescription(desc)64{65    return desc && desc != null66        && desc.type && desc.type != ''67        && desc.sdp && desc.sdp != '';68}69function explodeRemoteSimulcast(mLine) {70    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {71        return;72    }73    var sources = parseSsrcs(mLine);74    var order = [];75    // Find the SIM group and explode its sources.76    var j = mLine.ssrcGroups.length;77    while (j--) {78        if (mLine.ssrcGroups[j].semantics !== 'SIM') {79            continue;80        }81        var simulcastSsrcs = mLine.ssrcGroups[j].ssrcs.split(' ');82        for (var i = 0; i < simulcastSsrcs.length; i++) {83            var ssrc = simulcastSsrcs[i];84            order.push(ssrc);85            var parts = sources[ssrc].msid.split(' ');86            sources[ssrc].msid = [parts[0], '/', i, ' ', parts[1], '/', i].join('');87            sources[ssrc].cname = [sources[ssrc].cname, '/', i].join('');88            // Remove all the groups that this SSRC participates in.89            mLine.ssrcGroups.forEach(function (relatedGroup) {90                if (relatedGroup.semantics === 'SIM') {91                    return;92                }93                var relatedSsrcs = relatedGroup.ssrcs.split(' ');94                if (relatedSsrcs.indexOf(ssrc) === -1) {95                    return;96                }97                // Nuke all the related SSRCs.98                relatedSsrcs.forEach(function (relatedSSRC) {99                    sources[relatedSSRC].msid = sources[ssrc].msid;100                    sources[relatedSSRC].cname = sources[ssrc].cname;101                    if (relatedSSRC !== ssrc) {102                        order.push(relatedSSRC);103                    }104                });105                // Schedule the related group for nuking.106            })107        }108        mLine.ssrcs = writeSsrcs(sources, order);109        mLine.ssrcGroups.splice(j, 1);110    };111}112function implodeRemoteSimulcast(mLine) {113    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {114        console.info('Halt: There are no SSRC groups in the remote ' +115                'description.');116        return;117    }118    var sources = parseSsrcs(mLine);119    // Find the SIM group and nuke it.120    mLine.ssrcGroups.forEach(function (simulcastGroup) {121        if (simulcastGroup.semantics !== 'SIM') {122            return;123        }124        console.info("Imploding SIM group: " + simulcastGroup.ssrcs);125        // Schedule the SIM group for nuking.126        simulcastGroup.nuke = true;127        var simulcastSsrcs = simulcastGroup.ssrcs.split(' ');128        // Nuke all the higher layer SSRCs.129        for (var i = 1; i < simulcastSsrcs.length; i++) {130            var ssrc = simulcastSsrcs[i];131            delete sources[ssrc];132            // Remove all the groups that this SSRC participates in.133            mLine.ssrcGroups.forEach(function (relatedGroup) {134                if (relatedGroup.semantics === 'SIM') {135                    return;136                }137                var relatedSsrcs = relatedGroup.ssrcs.split(' ');138                if (relatedSsrcs.indexOf(ssrc) === -1) {139                    return;140                }141                // Nuke all the related SSRCs.142                relatedSsrcs.forEach(function (relatedSSRC) {143                    delete sources[relatedSSRC];144                });145                // Schedule the related group for nuking.146                relatedGroup.nuke = true;147            })148        }149        return;150    });151    mLine.ssrcs = writeSsrcs(sources);152    // Nuke all the scheduled groups.153    var i = mLine.ssrcGroups.length;154    while (i--) {155        if (mLine.ssrcGroups[i].nuke) {156            mLine.ssrcGroups.splice(i, 1);157        }158    }159}160function removeGoogConference(mLine) {161    if (!mLine || typeof mLine.xGoogleFlag === 'undefined') {162        return;163    }164    mLine.xGoogleFlag = undefined;165}166function assertGoogConference(mLine) {167    if (!mLine) {168        return;169    }170    if (!Array.isArray(mLine.invalid)) {171        mLine.invalid = [];172    }173    if (!mLine.invalid.some(174            function (i) { return i.value === 'x-google-flag:conference' })) {175        mLine.invalid.push({'value': 'x-google-flag:conference'});176    }177}178Simulcast.prototype.clearSsrcCache = function() {179    this.ssrcCache = [];180}181/**182 * When we start as video muted, all of the video183 *  ssrcs get generated so we can include them as part184 *  of the original session-accept.  That means we185 *  need this library to restore to those same ssrcs186 *  the first time we unmute, so we need the ability to187 *  force its cache188 */189Simulcast.prototype.setSsrcCache = function(ssrcs) {190    this.ssrcCache = ssrcs;191}192//endregion193//region "Private" functions194/**195 * Given a video mLine, return a list of the video ssrcs196 *  in simulcast layer order (returns a list of just197 *  the primary ssrc if there are no simulcast layers)198 */199Simulcast.prototype._parseSimLayers = function (mLine) {200    var simGroup = mLine.ssrcGroups &&201        mLine.ssrcGroups.find(function(group) { return group.semantics === "SIM"; });202    if (simGroup) {203        return simGroup.ssrcs204            .split(" ")205            .map(function(ssrcStr) { return parseInt(ssrcStr) });206    } else {207        return [mLine.ssrcs[0].id];208    }209}210Simulcast.prototype._buildNewToOldSsrcMap = function (newSsrcList, oldSsrcList) {211    var ssrcMap = {};212    for (var i = 0; i < newSsrcList.length; ++i) {213        var newSsrc = newSsrcList[i];214        var oldSsrc = oldSsrcList[i] || null;215        ssrcMap[newSsrc] = oldSsrc;216    }217    return ssrcMap;218}219Simulcast.prototype._fillInSourceDataFromCache = function(mLine) {220    console.log("SdpSimulcast restoring from cache: ", this.ssrcCache);221    var newSimSsrcs = this._parseSimLayers(mLine);222    console.log("SdpSimulcast Parsed new sim ssrcs: ", newSimSsrcs);223    var newMsid = getSsrcAttribute(mLine, newSimSsrcs[0], "msid");224    var newCname = getSsrcAttribute(mLine, newSimSsrcs[0], "cname");225    var ssrcsToReplace = this._buildNewToOldSsrcMap(newSimSsrcs, this.ssrcCache);226    console.log("SdpSimulcast built replacement map: ", ssrcsToReplace);227    // New sdp might only have 1 layer, so not every cached ssrc will have a new one228    //  to replace directly229    var ssrcsToAdd = this.ssrcCache230        .filter(function(ssrc) { return Object.values(ssrcsToReplace).indexOf(ssrc) === -1; });231    console.log("SdpSimulcast built ssrcs to add: ", ssrcsToAdd);232    // First do the replacements233    mLine.ssrcs.forEach(function(ssrc) {234        if (ssrcsToReplace[ssrc.id]) {235            ssrc.id = ssrcsToReplace[ssrc.id];236        }237    });238    // Now the adds239    ssrcsToAdd.forEach(function(ssrc) {240        mLine.ssrcs.push({241            id: ssrc,242            attribute: "msid",243            value: newMsid244        });245        mLine.ssrcs.push({246            id: ssrc,247            attribute: "cname",248            value: newCname249        });250    });251    mLine.ssrcGroups = mLine.ssrcGroups || [];252    mLine.ssrcGroups.push({253        semantics: "SIM",254        ssrcs: this.ssrcCache.join(" ")255    });256    return mLine;257}258Simulcast.prototype._generateSourceData = function(mLine, primarySsrc) {259    var addAssociatedStream = function(mLine, ssrc) {260        mLine.ssrcs.push({261            id: ssrc,262            attribute: "cname",263            value: primarySsrcCname264        });265        mLine.ssrcs.push({266            id: ssrc,267            attribute: "msid",268            value: primarySsrcMsid269        });270    }271    var primarySsrcMsid = getSsrcAttribute(mLine, primarySsrc, "msid");272    var primarySsrcCname = getSsrcAttribute(mLine, primarySsrc, "cname");273    // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present274    // in the answers that Chrome and Safari generate for an offer received from Jicofo.275    // Generate these a=ssrc lines using the msid values from the a=msid line.276    if (this.options.usesUnifiedPlan && !primarySsrcMsid) {277        primarySsrcMsid = mLine.msid;278        var primarySsrcs = mLine.ssrcs;279        primarySsrcs.forEach(ssrc => {280            mLine.ssrcs.push({281                id: ssrc.id,282                attribute: "msid",283                value: primarySsrcMsid284            });285        });286    }287    // Generate sim layers288    var simSsrcs = [];289    for (var i = 0; i < this.options.numOfLayers - 1; ++i) {290        var simSsrc = generateSSRC();291        addAssociatedStream(mLine, simSsrc);292        simSsrcs.push(simSsrc);293    }294    mLine.ssrcGroups = mLine.ssrcGroups || [];295    mLine.ssrcGroups.push({296        semantics: "SIM",297        ssrcs: primarySsrc + " " + simSsrcs.join(" ")298    });299    return mLine;300}301// Assumptions:302//  1) 'mLine' contains only a single primary video source303//   (i.e. it will not already have simulcast streams inserted)304//  2) 'mLine' MAY already contain an RTX stream for its video source305//  3) 'mLine' is in sendrecv or sendonly state306// Guarantees:307//  1) return mLine will contain 2 additional simulcast layers308//   generated309//  2) if the base video ssrc in mLine has been seen before,310//   then the same generated simulcast streams from before will311//   be used again312//  3) if rtx is enabled for the mLine, all generated simulcast313//   streams will have rtx streams generated as well314//  4) if rtx has been generated for a src before, we will generate315//   the same rtx stream again316Simulcast.prototype._restoreSimulcast = function(mLine) {317    // First, find the primary video source in the given318    // mLine and see if we've seen it before.319    var primarySsrc;320    var numSsrcs = mLine.ssrcs && mLine.ssrcs321        .map(function(ssrcInfo) { return ssrcInfo.id; })322        .filter(function(ssrc, index, array) {323            return array.indexOf(ssrc) === index;324        })325        .length || 0;326    var numGroups = (mLine.ssrcGroups && mLine.ssrcGroups.length) || 0;327    if (numSsrcs === 0 || numSsrcs > 2) {328        // Unsupported scenario329        return mLine;330    }331    if (numSsrcs == 2 && numGroups === 0) {332        // Unsupported scenario333        return mLine;334    }335    if (numSsrcs === 1) {336        primarySsrc = mLine.ssrcs[0].id;337    } else {338        // There must be an FID group, so parse339        //  that and pull the primary ssrc from there340        var fidGroup = mLine.ssrcGroups.filter(function(group) { return group.semantics === "FID"; })[0];341        if (fidGroup) {342            primarySsrc = parseInt(fidGroup.ssrcs.split(" ")[0]);343        } else {344            // Unsupported scenario345            return mLine;346        }347    }348    console.log("SdpSimulcast: current ssrc cache: ", this.ssrcCache);349    console.log("SdpSimulcast: parsed primary ssrc " + primarySsrc);350    var seenPrimarySsrc = this.ssrcCache.indexOf(primarySsrc) !== -1;351    if (seenPrimarySsrc) {352        console.log("SdpSimulcast: Have seen primary ssrc before, " +353            "filling in data from cache");354        mLine = this._fillInSourceDataFromCache(mLine);355    } else {356        console.log("SdpSimulcast: Have not seen primary ssrc before, " +357            "generating source data");358        mLine = this._generateSourceData(mLine, primarySsrc);359    }360    // Now update the cache to match whatever we've just put into this sdp361    this.ssrcCache = this._parseSimLayers(mLine);362    return mLine;363}364//endregion365//region "Public" functions366/**367 *368 * @param desc369 * @param enableConferenceFlag370 * @returns {RTCSessionDescription}371 */372Simulcast.prototype.mungeRemoteDescription = function (desc, enableConferenceFlag) {373    if (!validateDescription(desc)) {374        return desc;375    }376    var session = transform.parse(desc.sdp);377    var self = this;378    processVideo(session, function (mLine) {379        // Handle simulcast reception.380        if (self.options.explodeRemoteSimulcast) {381            explodeRemoteSimulcast(mLine);382        } else {383            implodeRemoteSimulcast(mLine);384        }385        // Add or remove "x-google-conference" from the remote description based on whether the client386        // has enabled simulcast for the local video source. For cases where we disable simulcast for desktop share,387        // it is necessary to remove the flag so that Chrome stops sending T1 temporal layers. It also fixes other388        // issues related to screensharing like https://bugs.chromium.org/p/chromium/issues/detail?id=1093819.389        if (!self.options.usesUnifiedPlan && enableConferenceFlag) {390            assertGoogConference(mLine);391        } else {392            removeGoogConference(mLine);393        }394    });395    return new RTCSessionDescription({396        type: desc.type,397        sdp: transform.write(session)398    });399};400/**401 *402 * NOTE this method should be called only if simulcast is supported by403 * the current browser, otherwise local SDP should not be munged.404 * @param desc405 * @returns {RTCSessionDescription}406 */407Simulcast.prototype.mungeLocalDescription = function (desc) {408    if (!validateDescription(desc)) {409        return desc;410    }411    var session = transform.parse(desc.sdp);412    var self = this;413    processVideo(session, function (mLine) {414        if (mLine.direction == 'recvonly' || mLine.direction == 'inactive')415        {416            return;417        }418        self._restoreSimulcast(mLine);419    });420    return new RTCSessionDescription({421        type: desc.type,422        sdp: transform.write(session)423    });424};425//endregion...RtxModifier.spec.js
Source:RtxModifier.spec.js  
1/* eslint-disable max-len*/2import * as transform from 'sdp-transform';3import RtxModifier from './RtxModifier.js';4import SDPUtil from './SDPUtil';5import { default as SampleSdpStrings } from './SampleSdpStrings.js';6/**7 * Returns the number of video ssrcs in the given sdp8 * @param {object} parsedSdp the sdp as parsed by transform.parse9 * @returns {number} the number of video ssrcs in the given sdp10 */11function numVideoSsrcs(parsedSdp) {12    const videoMLine = parsedSdp.media.find(m => m.type === 'video');13    return videoMLine.ssrcs14        .map(ssrcInfo => ssrcInfo.id)15        .filter((ssrc, index, array) => array.indexOf(ssrc) === index)16        .length;17}18/**19 * Return the (single) primary video ssrc in the given sdp20 * @param {object} parsedSdp the sdp as parsed by transform.parse21 * @returns {number} the primary video ssrc in the given sdp22 */23function getPrimaryVideoSsrc(parsedSdp) {24    const videoMLine = parsedSdp.media.find(m => m.type === 'video');25    return parseInt(SDPUtil.parsePrimaryVideoSsrc(videoMLine), 10);26}27/**28 * Get the primary video ssrc(s) in the given sdp.29 * Only handles parsing 2 scenarios right now:30 * 1) Single video ssrc31 * 2) Multiple video ssrcs in a single simulcast group32 * @param {object} parsedSdp the sdp as parsed by transform.parse33 * @returns {list<number>} the primary video ssrcs in the given sdp34 */35function getPrimaryVideoSsrcs(parsedSdp) {36    const videoMLine = parsedSdp.media.find(m => m.type === 'video');37    if (numVideoSsrcs(parsedSdp) === 1) {38        return [ videoMLine.ssrcs[0].id ];39    }40    const simGroups = getVideoGroups(parsedSdp, 'SIM');41    if (simGroups.length > 1) {42        return;43    }44    const simGroup = simGroups[0];45    return SDPUtil.parseGroupSsrcs(simGroup);46}47/**48 * Get the video groups that match the passed semantics from the49 *  given sdp50 * @param {object} parsedSDp the sdp as parsed by transform.parse51 * @param {string} groupSemantics the semantics string of the groups52 *  the caller is interested in53 * @returns {list<object>} a list of the groups from the given sdp54 *  that matched the passed semantics55 */56function getVideoGroups(parsedSdp, groupSemantics) {57    const videoMLine = parsedSdp.media.find(m => m.type === 'video');58    videoMLine.ssrcGroups = videoMLine.ssrcGroups || [];59    return videoMLine.ssrcGroups60        .filter(g => g.semantics === groupSemantics);61}62describe('RtxModifier', () => {63    let rtxModifier;64    beforeEach(() => {65        rtxModifier = new RtxModifier();66    });67    describe('modifyRtxSsrcs', () => {68        describe('when given an sdp with a single video ssrc', () => {69            let primaryVideoSsrc, singleVideoSdp;70            beforeEach(() => {71                singleVideoSdp = SampleSdpStrings.plainVideoSdp;72                primaryVideoSsrc = getPrimaryVideoSsrc(singleVideoSdp);73            });74            it('should add a single rtx ssrc', () => {75                // Call rtxModifier.modifyRtxSsrcs with an sdp that contains a single video76                //  ssrc.  The returned sdp should have an rtx ssrc and an fid group.77                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));78                const newSdp = transform.parse(newSdpStr);79                const newPrimaryVideoSsrc = getPrimaryVideoSsrc(newSdp);80                expect(newPrimaryVideoSsrc).toEqual(primaryVideoSsrc);81                // Should now have an rtx ssrc as well82                expect(numVideoSsrcs(newSdp)).toEqual(2);83                // Should now have an FID group84                const fidGroups = getVideoGroups(newSdp, 'FID');85                expect(fidGroups.length).toEqual(1);86                const fidGroup = fidGroups[0];87                const fidGroupPrimarySsrc = SDPUtil.parseGroupSsrcs(fidGroup)[0];88                expect(fidGroupPrimarySsrc).toEqual(primaryVideoSsrc);89            });90            it('should re-use the same rtx ssrc for a primary ssrc it\'s seen before', () => {91                // Have rtxModifier generate an rtx ssrc via modifyRtxSsrcs.  Then call it again92                //  with the same primary ssrc in the sdp (but no rtx ssrc).  It should use93                //  the same rtx ssrc as before.94                let newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));95                let newSdp = transform.parse(newSdpStr);96                let fidGroup = getVideoGroups(newSdp, 'FID')[0];97                const fidGroupRtxSsrc = SDPUtil.parseGroupSsrcs(fidGroup)[1];98                // Now pass the original sdp through again99                newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));100                newSdp = transform.parse(newSdpStr);101                fidGroup = getVideoGroups(newSdp, 'FID')[0];102                const newFidGroupRtxSsrc = SDPUtil.parseGroupSsrcs(fidGroup)[1];103                expect(newFidGroupRtxSsrc).toEqual(fidGroupRtxSsrc);104            });105            it('should NOT re-use the same rtx ssrc for a primary ssrc it\'s seen before if the cache has been cleared', () => {106                // Call modifyRtxSsrcs to generate an rtx ssrc107                // Clear the rtxModifier cache108                // Call modifyRtxSsrcs to generate an rtx ssrc again with the same primary ssrc109                // --> We should get a different rtx ssrc110                let newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));111                let newSdp = transform.parse(newSdpStr);112                let fidGroup = getVideoGroups(newSdp, 'FID')[0];113                const fidGroupRtxSsrc = SDPUtil.parseGroupSsrcs(fidGroup)[1];114                rtxModifier.clearSsrcCache();115                // Now pass the original sdp through again116                newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));117                newSdp = transform.parse(newSdpStr);118                fidGroup = getVideoGroups(newSdp, 'FID')[0];119                const newFidGroupRtxSsrc = SDPUtil.parseGroupSsrcs(fidGroup)[1];120                expect(newFidGroupRtxSsrc).not.toEqual(fidGroupRtxSsrc);121            });122            it('should use the rtx ssrc from the cache when the cache has been manually set', () => {123                // Manually set an rtx ssrc mapping in the cache124                // Call modifyRtxSsrcs125                // -->The rtx ssrc used should be the one we set126                const forcedRtxSsrc = 123456;127                const ssrcCache = new Map();128                ssrcCache.set(primaryVideoSsrc, forcedRtxSsrc);129                rtxModifier.setSsrcCache(ssrcCache);130                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(singleVideoSdp));131                const newSdp = transform.parse(newSdpStr);132                const fidGroup = getVideoGroups(newSdp, 'FID')[0];133                const fidGroupRtxSsrc = SDPUtil.parseGroupSsrcs(fidGroup)[1];134                expect(fidGroupRtxSsrc).toEqual(forcedRtxSsrc);135            });136        });137        describe('when given an sdp with multiple video ssrcs', () => {138            let multipleVideoSdp, primaryVideoSsrcs;139            beforeEach(() => {140                multipleVideoSdp = SampleSdpStrings.simulcastSdp;141                primaryVideoSsrcs = getPrimaryVideoSsrcs(multipleVideoSdp);142            });143            it('should add rtx ssrcs for all of them', () => {144                // Call rtxModifier.modifyRtxSsrcs with an sdp that contains multiple video145                //  ssrcs.  The returned sdp should have an rtx ssrc and an fid group for all of them.146                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));147                const newSdp = transform.parse(newSdpStr);148                const newPrimaryVideoSsrcs = getPrimaryVideoSsrcs(newSdp);149                expect(newPrimaryVideoSsrcs).toEqual(primaryVideoSsrcs);150                // Should now have rtx ssrcs as well151                expect(numVideoSsrcs(newSdp)).toEqual(primaryVideoSsrcs.length * 2);152                // Should now have FID groups153                const fidGroups = getVideoGroups(newSdp, 'FID');154                expect(fidGroups.length).toEqual(primaryVideoSsrcs.length);155                fidGroups.forEach(fidGroup => {156                    const fidGroupPrimarySsrc = SDPUtil.parseGroupSsrcs(fidGroup)[0];157                    expect(primaryVideoSsrcs.indexOf(fidGroupPrimarySsrc)).not.toEqual(-1);158                });159            });160            it('should re-use the same rtx ssrcs for any primary ssrc it\'s seen before', () => {161                // Have rtxModifier generate an rtx ssrc via modifyRtxSsrcs.  Then call it again162                //  with the same primary ssrc in the sdp (but no rtx ssrc).  It should use163                //  the same rtx ssrc as before.164                let newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));165                let newSdp = transform.parse(newSdpStr);166                const rtxMapping = new Map();167                let fidGroups = getVideoGroups(newSdp, 'FID');168                // Save the first mapping that is made169                fidGroups.forEach(fidGroup => {170                    const fidSsrcs = SDPUtil.parseGroupSsrcs(fidGroup);171                    const fidGroupPrimarySsrc = fidSsrcs[0];172                    const fidGroupRtxSsrc = fidSsrcs[1];173                    rtxMapping.set(fidGroupPrimarySsrc, fidGroupRtxSsrc);174                });175                // Now pass the original sdp through again and make sure we get the same mapping176                newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));177                newSdp = transform.parse(newSdpStr);178                fidGroups = getVideoGroups(newSdp, 'FID');179                fidGroups.forEach(fidGroup => {180                    const fidSsrcs = SDPUtil.parseGroupSsrcs(fidGroup);181                    const fidGroupPrimarySsrc = fidSsrcs[0];182                    const fidGroupRtxSsrc = fidSsrcs[1];183                    expect(rtxMapping.has(fidGroupPrimarySsrc)).toBe(true);184                    expect(rtxMapping.get(fidGroupPrimarySsrc)).toEqual(fidGroupRtxSsrc);185                });186            });187            it('should NOT re-use the same rtx ssrcs for any primary ssrc it\'s seen before if the cache has been cleared', () => {188                // Call modifyRtxSsrcs to generate an rtx ssrc189                // Clear the rtxModifier cache190                // Call modifyRtxSsrcs to generate rtx ssrcs again with the same primary ssrcs191                // --> We should get different rtx ssrcs192                let newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));193                let newSdp = transform.parse(newSdpStr);194                const rtxMapping = new Map();195                let fidGroups = getVideoGroups(newSdp, 'FID');196                // Save the first mapping that is made197                fidGroups.forEach(fidGroup => {198                    const fidSsrcs = SDPUtil.parseGroupSsrcs(fidGroup);199                    const fidGroupPrimarySsrc = fidSsrcs[0];200                    const fidGroupRtxSsrc = fidSsrcs[1];201                    rtxMapping.set(fidGroupPrimarySsrc, fidGroupRtxSsrc);202                });203                rtxModifier.clearSsrcCache();204                // Now pass the original sdp through again and make sure we get the same mapping205                newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));206                newSdp = transform.parse(newSdpStr);207                fidGroups = getVideoGroups(newSdp, 'FID');208                fidGroups.forEach(fidGroup => {209                    const fidSsrcs = SDPUtil.parseGroupSsrcs(fidGroup);210                    const fidGroupPrimarySsrc = fidSsrcs[0];211                    const fidGroupRtxSsrc = fidSsrcs[1];212                    expect(rtxMapping.has(fidGroupPrimarySsrc)).toBe(true);213                    expect(rtxMapping.get(fidGroupPrimarySsrc)).not.toEqual(fidGroupRtxSsrc);214                });215            });216            it('should use the rtx ssrcs from the cache when the cache has been manually set', () => {217                // Manually set an rtx ssrc mapping in the cache218                // Call modifyRtxSsrcs219                // -->The rtx ssrc used should be the one we set220                const rtxMapping = new Map();221                primaryVideoSsrcs.forEach(ssrc => {222                    rtxMapping.set(ssrc, SDPUtil.generateSsrc());223                });224                rtxModifier.setSsrcCache(rtxMapping);225                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(multipleVideoSdp));226                const newSdp = transform.parse(newSdpStr);227                const fidGroups = getVideoGroups(newSdp, 'FID');228                fidGroups.forEach(fidGroup => {229                    const fidSsrcs = SDPUtil.parseGroupSsrcs(fidGroup);230                    const fidGroupPrimarySsrc = fidSsrcs[0];231                    const fidGroupRtxSsrc = fidSsrcs[1];232                    expect(rtxMapping.has(fidGroupPrimarySsrc)).toBe(true);233                    expect(rtxMapping.get(fidGroupPrimarySsrc)).toEqual(fidGroupRtxSsrc);234                });235            });236        });237        describe('when given an sdp with a flexfec stream', () => {238            it('should not add rtx for the flexfec ssrc', () => {239                const flexFecSdp = SampleSdpStrings.flexFecSdp;240                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(flexFecSdp));241                const newSdp = transform.parse(newSdpStr);242                const fidGroups = getVideoGroups(newSdp, 'FID');243                expect(fidGroups.length).toEqual(1);244            });245        });246        describe('(corner cases)', () => {247            it('should handle a recvonly video mline', () => {248                const sdp = SampleSdpStrings.plainVideoSdp;249                const videoMLine = sdp.media.find(m => m.type === 'video');250                videoMLine.direction = 'recvonly';251                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(sdp));252                expect(newSdpStr).toEqual(transform.write(sdp));253            });254            it('should handle a video mline with no video ssrcs', () => {255                const sdp = SampleSdpStrings.plainVideoSdp;256                const videoMLine = sdp.media.find(m => m.type === 'video');257                videoMLine.ssrcs = [];258                const newSdpStr = rtxModifier.modifyRtxSsrcs(transform.write(sdp));259                expect(newSdpStr).toEqual(transform.write(sdp));260            });261        });262    });263    describe('stripRtx', () => {264        beforeEach(() => { }); // eslint-disable-line no-empty-function265        it('should strip all rtx streams from an sdp with rtx', () => {266            const sdpStr = transform.write(SampleSdpStrings.rtxVideoSdp);267            const newSdpStr = rtxModifier.stripRtx(sdpStr);268            const newSdp = transform.parse(newSdpStr);269            const fidGroups = getVideoGroups(newSdp, 'FID');270            expect(fidGroups.length).toEqual(0);271            expect(numVideoSsrcs(newSdp)).toEqual(1);272        });273        it('should do nothing to an sdp with no rtx', () => {274            const sdpStr = transform.write(SampleSdpStrings.plainVideoSdp);275            const newSdpStr = rtxModifier.stripRtx(sdpStr);276            expect(newSdpStr).toEqual(sdpStr);277        });278    });279});...Using AI Code Generation
1var wpt = require('webpagetest');2var wpt = new WebPageTest('www.webpagetest.org');3  if (err) {4    console.log(err);5  } else {6    console.log(data);7  }8});9var wpt = require('webpagetest');10var wpt = new WebPageTest('www.webpagetest.org');11  if (err) {12    console.log(err);13  } else {14    console.log(data);15  }16});17var wpt = require('webpagetest');18var wpt = new WebPageTest('www.webpagetest.org');19  if (err) {20    console.log(err);21  } else {22    console.log(data);23  }24});25var wpt = require('webpagetest');26var wpt = new WebPageTest('www.webpagetest.org');27wpt.getLocations(function(err, data) {28  if (err) {29    console.log(err);30  } else {31    console.log(data);32  }33});34var wpt = require('webpagetest');35var wpt = new WebPageTest('www.webpagetest.org');36wpt.getTesters(function(err, data) {37  if (err) {38    console.log(err);39  } else {40    console.log(data);41  }42});43var wpt = require('webpagetest');44var wpt = new WebPageTest('www.webpagetest.org');45wpt.getTesters(function(err, data) {46  if (err) {47    console.log(err);48  } else {49    console.log(data);50  }51});52var wpt = require('webpagetest');Using AI Code Generation
1var wpt = require('webpagetest');2var api = new wpt('www.webpagetest.org');3  if (err) return console.error(err);4  api.getTestResults(data.data.testId, function(err, data) {5    if (err) return console.error(err);6    console.log(data.data.median.firstView.SSUsing AI Code Generation
1const wptools = require('wptools');2const ss = wptools.ssrcs();3console.log(ss);4const wptools = require('wptools');5const wp = wptools();6console.log(wp);7const wptools = require('wptools');8const wp = wptools();9console.log(wp);10const wptools = require('wptools');11const wp = wptools();12console.log(wp);13const wptools = require('wptools');14const wp = wptools();15console.log(wp);16const wptools = require('wptools');17const wp = wptools();18console.log(wp);19const wptools = require('wptools');20const wp = wptools();21console.log(wp);22const wptools = require('wptools');23const wp = wptools();24console.log(wp);25const wptools = require('wptools');26const wp = wptools();27console.log(wp);28const wptools = require('wptools');29const wp = wptools();30console.log(wp);31const wptools = require('wptools');32const wp = wptools();33console.log(wp);34const wptools = require('wptools');35const wp = wptools();36console.log(wp);Using AI Code Generation
1module.exports = function (wpt, test, cb) {2  wpt.ssrcs(url, function (err, data) {3    if (err) {4      test.ok(false, 'Error: ' + err);5    } else {6      test.ok(true, 'Got data: ' + JSON.stringify(data));7    }8    cb();9  });10};11module.exports = function (wpt, test, cb) {12  wpt.ssrcs(url, function (err, data) {13    if (err) {14      test.ok(false, 'Error: ' + err);15    } else {16      test.ok(true, 'Got data: ' + JSON.stringify(data));17    }18    cb();19  });20};21module.exports = function (wpt, test, cb) {22  wpt.ssrcs(url, function (err, data) {23    if (err) {24      test.ok(false, 'Error: ' + err);25    } else {26      test.ok(true, 'Got data: ' + JSON.stringify(data));27    }28    cb();29  });30};31module.exports = function (wpt, test, cb) {32  wpt.ssrcs(url, function (err, data) {33    if (err) {34      test.ok(false, 'Error: ' + err);35    } else {36      test.ok(true, 'Got data: ' + JSON.stringify(data));37    }38    cb();39  });40};41module.exports = function (wpt, test, cb) {42  wpt.ssrcs(url, function (err, data) {43    if (err) {44      test.ok(false, 'Error: ' + err);45    } else {46      test.ok(true, 'Got data: ' + JSON.stringify(data));47    }Using AI Code Generation
1var wpt = require('./index.js');2var wpt = new WebPageTest('www.webpagetest.org', 'A.8c5f5e0a5b770d9a5f9c9a1a5c5f5e0a');3wpt.getLocations(function(err, data) {4  if (err) return console.error(err);5  console.log(data);6});7wpt.runTest(testUrl, function(err, data) {8  if (err) return console.error(err);9  console.log(data);10});11wpt.getTestResults('150509_4F_1R', function(err, data) {12  if (err) return console.error(err);13  console.log(data);14});15wpt.getTestStatus('150509_4F_1R', function(err, data) {16  if (err) return console.error(err);17  console.log(data);18});19wpt.getTestStatus('150509_4F_1R', function(err, data) {20  if (err) return console.error(err);21  console.log(data);22});23wpt.getTestStatus('150509_4F_1R', function(err, data) {24  if (err) return console.error(err);25  console.log(data);26});27wpt.getTestStatus('150509_4F_1R', function(err, data) {28  if (err) return console.error(err);29  console.log(data);30});31wpt.getTestStatus('150509_4F_1R', function(err, data) {32  if (err) return console.error(err);33  console.log(data);34});35wpt.getTestStatus('150509_4F_1R', function(err, data) {36  if (err) return console.error(err);37  console.log(data);38});39wpt.getTestStatus('150509_4F_1R', function(err, data) {40  if (err) return console.error(err);41  console.log(data);42});43wpt.getTestStatus('150509_4F_1R',Using AI Code Generation
1var wpt = require('webpagetest');2var wpt = new WebPageTest('www.webpagetest.org', 'A.2c9e7d9d9e1b1f6e1c2b2d2c1e1e1e1e');3    if (err) return console.log(err);4    wpt.getTestResults(data.data.testId, function(err, data) {5        if (err) return console.log(err);6        console.log(data.data.median.firstView.SpeedIndex);7    });8});9            if (err) throw err;10    at errnoException (dns.js:28:10)11    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)12            if (err) throw err;13    at errnoException (dns.js:28:10)14    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)15var wpt = require('webpagetest');16var wpt = new WebPageTest('www.webpagetest.org', 'A.2c9e7d9d9e1b1f6e1c2b2d2c1e1e1e1e');17    if (err) return console.log(err);18    wpt.getTestResults(data.data.testId, function(err, data) {19        if (err) return console.log(err);20        console.log(data.data.median.firstView.SpeedIndex);21    });Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
