Просмотр исходного кода

feat: JSON encoded sources. (#1695)

* feat: Support plain endpoint ID.

Support the ID of the owner of sources being encoded directly instead of
using the full JID.

* feat: Support JSON-encoded sources.

* feat: Advertise support for JSON-encoded sources.
dev1
bgrozev 4 лет назад
Родитель
Сommit
526d12bbbd
Аккаунт пользователя с таким Email не найден
3 измененных файлов: 193 добавлений и 2 удалений
  1. 11
    1
      modules/xmpp/JingleSessionPC.js
  2. 181
    1
      modules/xmpp/strophe.jingle.js
  3. 1
    0
      modules/xmpp/xmpp.js

+ 11
- 1
modules/xmpp/JingleSessionPC.js Просмотреть файл

@@ -47,6 +47,16 @@ const DEFAULT_MAX_STATS = 300;
47 47
  */
48 48
 const ICE_CAND_GATHERING_TIMEOUT = 150;
49 49
 
50
+/**
51
+ * Reads the endpoint ID given a string which represents either the endpoint's full JID, or the endpoint ID itself.
52
+ * @param {String} jidOrEndpointId A string which is either the full JID of a participant, or the ID of an
53
+ * endpoint/participant.
54
+ * @returns The endpoint ID associated with 'jidOrEndpointId'.
55
+ */
56
+function getEndpointId(jidOrEndpointId) {
57
+    return Strophe.getResourceFromJid(jidOrEndpointId) || jidOrEndpointId;
58
+}
59
+
50 60
 /**
51 61
  * @typedef {Object} JingleSessionPCOptions
52 62
  * @property {Object} abTesting - A/B testing related options (ask George).
@@ -886,7 +896,7 @@ export default class JingleSessionPC extends JingleSession {
886 896
                             } else {
887 897
                                 this.signalingLayer.setSSRCOwner(
888 898
                                     ssrc,
889
-                                    Strophe.getResourceFromJid(owner));
899
+                                    getEndpointId(owner));
890 900
                             }
891 901
                         }
892 902
                     });

+ 181
- 1
modules/xmpp/strophe.jingle.js Просмотреть файл

@@ -1,4 +1,4 @@
1
-/* global $, __filename */
1
+/* global $, $build, __filename */
2 2
 
3 3
 import { getLogger } from 'jitsi-meet-logger';
4 4
 import { $iq, Strophe } from 'strophe.js';
@@ -22,6 +22,174 @@ const logger = getLogger(__filename);
22 22
 // function call chains.
23 23
 /* eslint-disable newline-per-chained-call */
24 24
 
25
+/**
26
+ * Reads a JSON-encoded message (from a "json-message" element) and extracts source descriptions. Adds the extracted
27
+ * source descriptions to the given Jingle IQ in the standard Jingle format.
28
+ *
29
+ * Encoding sources in this compact JSON format instead of standard Jingle was introduced in order to reduce the
30
+ * network traffic and load on the XMPP server. The format is described in Jicofo [TODO: insert link].
31
+ *
32
+ * @param {*} iq the IQ to which source descriptions will be added.
33
+ * @param {*} jsonMessageXml The XML node for the "json-message" element.
34
+ * @returns nothing.
35
+ */
36
+function expandSourcesFromJson(iq, jsonMessageXml) {
37
+
38
+    let json;
39
+
40
+    try {
41
+        json = JSON.parse(jsonMessageXml.textContent);
42
+    } catch (error) {
43
+        logger.error(`json-message XML contained invalid JSON, ignoring: ${jsonMessageXml.textContent}`);
44
+
45
+        return;
46
+    }
47
+
48
+    if (!json || !json.sources) {
49
+        // It might be a message of a different type, no need to log.
50
+        return;
51
+    }
52
+
53
+    // This is where we'll add "source" and "ssrc-group" elements. Create them elements if they don't exist.
54
+    const videoRtpDescription = getOrCreateRtpDescription(iq, 'video');
55
+    const audioRtpDescription = getOrCreateRtpDescription(iq, 'audio');
56
+
57
+    for (const owner in json.sources) {
58
+        if (json.sources.hasOwnProperty(owner)) {
59
+
60
+            const ownerSources = json.sources[owner];
61
+
62
+            // The video sources, video ssrc-groups, audio sources and audio ssrc-groups are encoded in that order in
63
+            // the elements of the array.
64
+            const videoSources = ownerSources && ownerSources.length > 0 && ownerSources[0];
65
+            const videoSsrcGroups = ownerSources && ownerSources.length > 1 && ownerSources[1];
66
+            const audioSources = ownerSources && ownerSources.length > 2 && ownerSources[2];
67
+            const audioSsrcGroups = ownerSources && ownerSources.length > 3 && ownerSources[3];
68
+
69
+            if (videoSources && videoSources.length > 0) {
70
+                for (let i = 0; i < videoSources.length; i++) {
71
+                    videoRtpDescription.appendChild(createSourceExtension(owner, videoSources[i]));
72
+                }
73
+            }
74
+            if (videoSsrcGroups && videoSsrcGroups.length > 0) {
75
+                for (let i = 0; i < videoSsrcGroups.length; i++) {
76
+                    videoRtpDescription.appendChild(createSsrcGroupExtension(videoSsrcGroups[i]));
77
+                }
78
+            }
79
+            if (audioSources && audioSources.length > 0) {
80
+                for (let i = 0; i < audioSources.length; i++) {
81
+                    audioRtpDescription.appendChild(createSourceExtension(owner, audioSources[i]));
82
+                }
83
+            }
84
+            if (audioSsrcGroups && audioSsrcGroups.length > 0) {
85
+                for (let i = 0; i < audioSsrcGroups.length; i++) {
86
+                    audioRtpDescription.appendChild(createSsrcGroupExtension(audioSsrcGroups[i]));
87
+                }
88
+            }
89
+        }
90
+    }
91
+}
92
+
93
+/**
94
+ * Creates a "source" XML element for the source described in compact JSON format in [sourceCompactJson].
95
+ * @param {*} owner the endpoint ID of the owner of the source.
96
+ * @param {*} sourceCompactJson the compact JSON representation of the source.
97
+ * @returns the created "source" XML element.
98
+ */
99
+function createSourceExtension(owner, sourceCompactJson) {
100
+    const node = $build('source', {
101
+        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',
102
+        ssrc: sourceCompactJson.s
103
+    });
104
+
105
+    if (sourceCompactJson.m) {
106
+        node.c('parameter', {
107
+            name: 'msid',
108
+            value: sourceCompactJson.m
109
+        }).up();
110
+    }
111
+    node.c('ssrc-info', {
112
+        xmlns: 'http://jitsi.org/jitmeet',
113
+        owner
114
+    }).up();
115
+
116
+    return node.node;
117
+}
118
+
119
+/**
120
+ * Creates an "ssrc-group" XML element for the SSRC group described in compact JSON format in [ssrcGroupCompactJson].
121
+ * @param {*} ssrcGroupCompactJson the compact JSON representation of the SSRC group.
122
+ * @returns the created "ssrc-group" element.
123
+ */
124
+function createSsrcGroupExtension(ssrcGroupCompactJson) {
125
+    const node = $build('ssrc-group', {
126
+        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',
127
+        semantics: getSemantics(ssrcGroupCompactJson[0])
128
+    });
129
+
130
+    for (let i = 1; i < ssrcGroupCompactJson.length; i++) {
131
+        node.c('source', {
132
+            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',
133
+            ssrc: ssrcGroupCompactJson[i]
134
+        }).up();
135
+    }
136
+
137
+    return node.node;
138
+}
139
+
140
+/**
141
+ * Convert the short string representing SSRC group semantics in compact JSON format to the standard representation
142
+ * (i.e. convert "f" to "FID" and "s" to "SIM").
143
+ * @param {*} str the compact JSON format representation of an SSRC group's semantics.
144
+ * @returns the SSRC group semantics corresponding to [str].
145
+ */
146
+function getSemantics(str) {
147
+    if (str === 'f') {
148
+        return 'FID';
149
+    } else if (str === 's') {
150
+        return 'SIM';
151
+    }
152
+
153
+    return null;
154
+}
155
+
156
+/**
157
+ * Finds in a Jingle IQ the RTP description element with the given media type. If one does not exists, create it (as
158
+ *  well as the required  "content" parent element) and adds it to the IQ.
159
+ * @param {*} iq
160
+ * @param {*} mediaType The media type, "audio" or "video".
161
+ * @returns the RTP description element with the given media type.
162
+ */
163
+function getOrCreateRtpDescription(iq, mediaType) {
164
+    const jingle = $(iq).find('jingle')[0];
165
+    let content = $(jingle).find(`content[name="${mediaType}"]`);
166
+    let description;
167
+
168
+    if (content.length) {
169
+        content = content[0];
170
+    } else {
171
+        // I'm not suree if "creator" and "senders" are required.
172
+        content = $build('content', {
173
+            name: mediaType
174
+        }).node;
175
+        jingle.appendChild(content);
176
+    }
177
+
178
+    description = $(content).find('description');
179
+
180
+    if (description.length) {
181
+        description = description[0];
182
+    } else {
183
+        description = $build('description', {
184
+            xmlns: 'urn:xmpp:jingle:apps:rtp:1',
185
+            media: mediaType
186
+        }).node;
187
+        content.appendChild(description);
188
+    }
189
+
190
+    return description;
191
+}
192
+
25 193
 /**
26 194
  *
27 195
  */
@@ -132,6 +300,18 @@ export default class JingleConnectionPlugin extends ConnectionPlugin {
132 300
 
133 301
         // see http://xmpp.org/extensions/xep-0166.html#concepts-session
134 302
 
303
+        const jsonMessages = $(iq).find('jingle>json-message');
304
+
305
+        if (jsonMessages && jsonMessages.length > 0) {
306
+            logger.info(`Found a JSON-encoded element in ${action}, translating to standard Jingle.`);
307
+            for (let i = 0; i < jsonMessages.length; i++) {
308
+                expandSourcesFromJson(iq, jsonMessages[i]);
309
+            }
310
+
311
+            // TODO: is there a way to remove the json-message elements once we've extracted the information?
312
+            // removeChild doesn't seem to work.
313
+        }
314
+
135 315
         switch (action) {
136 316
         case 'session-initiate': {
137 317
             logger.log('(TIME) received session-initiate:\t', now);

+ 1
- 0
modules/xmpp/xmpp.js Просмотреть файл

@@ -206,6 +206,7 @@ export default class XMPP extends Listenable {
206 206
         this.caps.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');
207 207
         this.caps.addFeature('urn:xmpp:jingle:apps:rtp:audio');
208 208
         this.caps.addFeature('urn:xmpp:jingle:apps:rtp:video');
209
+        this.caps.addFeature('http://jitsi.org/json-encoded-sources');
209 210
 
210 211
         // Disable RTX on Firefox 83 and older versions because of
211 212
         // https://bugzilla.mozilla.org/show_bug.cgi?id=1668028

Загрузка…
Отмена
Сохранить