| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /* global $ */
-
- /*
- The purpose of this hack is to re-use SSRC of first video stream ever created
- for any video streams created later on. In order to do that this hack:
-
- 1. Stores the SSRC of the first video stream created by
- a) scanning Jingle session-accept/session-invite for existing video SSRC
- b) watching for 'source-add' for new video stream if it has not been
- created in step a)
- 2. Exposes method 'mungeLocalVideoSSRC' which replaces any new video SSRC with
- the stored one. It is called by 'TracablePeerConnection' before local SDP is
- returned to the other parts of the application.
- 3. Scans 'source-remove'/'source-add' notifications for stored video SSRC and
- blocks those notifications. This makes Jicofo and all participants think
- that it exists all the time even if the video stream has been removed or
- replaced locally. Thanks to that there is no additional signaling activity
- on video mute or when switching to the desktop stream.
- */
-
- var SDP = require('./SDP');
-
- /**
- * Stored SSRC of local video stream.
- */
- var localVideoSSRC;
-
- /**
- * Method removes <source> element which describes <tt>localVideoSSRC</tt>
- * from given Jingle IQ.
- * @param modifyIq 'source-add' or 'source-remove' Jingle IQ.
- * @param actionName display name of the action which will be printed in log
- * messages.
- * @returns {*} modified Jingle IQ, so that it does not contain <source> element
- * corresponding to <tt>localVideoSSRC</tt> or <tt>null</tt> if no
- * other SSRCs left to be signaled after removing it.
- */
- var filterOutSource = function (modifyIq, actionName) {
- var modifyIqTree = $(modifyIq.tree());
-
- if (!localVideoSSRC)
- return modifyIqTree[0];
-
- var videoSSRC = modifyIqTree.find(
- '>jingle>content[name="video"]' +
- '>description>source[ssrc="' + localVideoSSRC + '"]');
-
- if (!videoSSRC.length) {
- return modifyIqTree[0];
- }
-
- console.info(
- 'Blocking ' + actionName + ' for local video SSRC: ' + localVideoSSRC);
-
- videoSSRC.remove();
-
- // Check if any sources still left to be added/removed
- if (modifyIqTree.find('>jingle>content>description>source').length) {
- return modifyIqTree[0];
- } else {
- return null;
- }
- };
-
- /**
- * Scans given Jingle IQ for video SSRC and stores it.
- * @param jingleIq the Jingle IQ to be scanned for video SSRC.
- */
- var storeLocalVideoSSRC = function (jingleIq) {
- var videoSSRCs =
- $(jingleIq.tree())
- .find('>jingle>content[name="video"]>description>source');
-
- console.info('Video desc: ', videoSSRCs);
- if (!videoSSRCs.length)
- return;
-
- var ssrc = videoSSRCs.attr('ssrc');
- if (ssrc) {
- localVideoSSRC = ssrc;
- console.info(
- 'Stored local video SSRC for future re-use: ' + localVideoSSRC);
- } else {
- console.error('No "ssrc" attribute present in <source> element');
- }
- };
-
- var LocalVideoSSRCHack = {
- /**
- * Method must be called before 'session-initiate' or 'session-invite' is
- * sent. Scans the IQ for local video SSRC and stores it if detected.
- *
- * @param sessionInit our 'session-initiate' or 'session-accept' Jingle IQ
- * which will be scanned for local video SSRC.
- */
- processSessionInit: function (sessionInit) {
- if (localVideoSSRC) {
- console.error("Local SSRC stored already: " + localVideoSSRC);
- return;
- }
- storeLocalVideoSSRC(sessionInit);
- },
- /**
- * If we have local video SSRC stored searched given
- * <tt>localDescription</tt> for video SSRC and makes sure it is replaced
- * with the stored one.
- * @param localDescription local description object that will have local
- * video SSRC replaced with the stored one
- * @returns modified <tt>localDescription</tt> object.
- */
- mungeLocalVideoSSRC: function (localDescription) {
- // IF we have local video SSRC stored make sure it is replaced
- // with old SSRC
- if (localVideoSSRC) {
- var newSdp = new SDP(localDescription.sdp);
- if (newSdp.media[1].indexOf("a=ssrc:") !== -1 &&
- !newSdp.containsSSRC(localVideoSSRC)) {
- // Get new video SSRC
- var map = newSdp.getMediaSsrcMap();
- var videoPart = map[1];
- var videoSSRCs = videoPart.ssrcs;
- var newSSRC = Object.keys(videoSSRCs)[0];
-
- console.info(
- "Replacing new video SSRC: " + newSSRC +
- " with " + localVideoSSRC);
-
- localDescription.sdp =
- newSdp.raw.replace(
- new RegExp('a=ssrc:' + newSSRC, 'g'),
- 'a=ssrc:' + localVideoSSRC);
- }
- }
- return localDescription;
- },
- /**
- * Method must be called before 'source-add' notification is sent. In case
- * we have local video SSRC advertised already it will be removed from the
- * notification. If no other SSRCs are described by given IQ null will be
- * returned which means that there is no point in sending the notification.
- * @param sourceAdd 'source-add' Jingle IQ to be processed
- * @returns modified 'source-add' IQ which can be sent to the focus or
- * <tt>null</tt> if no notification shall be sent. It is no longer
- * a Strophe IQ Builder instance, but DOM element tree.
- */
- processSourceAdd: function (sourceAdd) {
- if (!localVideoSSRC) {
- // Store local SSRC if available
- storeLocalVideoSSRC(sourceAdd);
- return sourceAdd;
- } else {
- return filterOutSource(sourceAdd, 'source-add');
- }
- },
- /**
- * Method must be called before 'source-remove' notification is sent.
- * Removes local video SSRC from the notification. If there are no other
- * SSRCs described in the given IQ <tt>null</tt> will be returned which
- * means that there is no point in sending the notification.
- * @param sourceRemove 'source-remove' Jingle IQ to be processed
- * @returns modified 'source-remove' IQ which can be sent to the focus or
- * <tt>null</tt> if no notification shall be sent. It is no longer
- * a Strophe IQ Builder instance, but DOM element tree.
- */
- processSourceRemove: function (sourceRemove) {
- return filterOutSource(sourceRemove, 'source-remove');
- }
- };
-
- module.exports = LocalVideoSSRCHack;
|