How to use ssrcs method in wpt

Best JavaScript code snippet using wpt

index.js

Source:index.js Github

copy

Full Screen

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...

Full Screen

Full Screen

RtxModifier.spec.js

Source:RtxModifier.spec.js Github

copy

Full Screen

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});...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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');

Full Screen

Using AI Code Generation

copy

Full Screen

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.SS

Full Screen

Using AI Code Generation

copy

Full Screen

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);

Full Screen

Using AI Code Generation

copy

Full Screen

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 }

Full Screen

Using AI Code Generation

copy

Full Screen

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',

Full Screen

Using AI Code Generation

copy

Full Screen

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 });

Full Screen

Automation Testing Tutorials

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.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful