Sfoglia il codice sorgente

Implements API that allows external applications to embed Jitsi Meet.

j8
hristoterezov 10 anni fa
parent
commit
667a8c1493
6 ha cambiato i file con 410 aggiunte e 27 eliminazioni
  1. 100
    0
      api_connector.js
  2. 4
    1
      app.js
  3. 80
    0
      doc/api.md
  4. 199
    0
      external_api.js
  5. 3
    2
      index.html
  6. 24
    24
      videolayout.js

+ 100
- 0
api_connector.js Vedi File

@@ -0,0 +1,100 @@
1
+/**
2
+ * Implements API class that communicates with external api class
3
+ * and provides interface to access Jitsi Meet features by external
4
+ * applications that embed Jitsi Meet
5
+ */
6
+var APIConnector = (function () {
7
+
8
+    function APIConnector() { }
9
+
10
+    /**
11
+     * List of the available commands.
12
+     * @type {{
13
+     *              displayName: inputDisplayNameHandler,
14
+     *              muteAudio: toggleAudio,
15
+     *              muteVideo: toggleVideo,
16
+     *              filmStrip: toggleFilmStrip
17
+     *          }}
18
+     */
19
+    var commands =
20
+    {
21
+        displayName: VideoLayout.inputDisplayNameHandler,
22
+        muteAudio: toggleAudio,
23
+        muteVideo: toggleVideo,
24
+        filmStrip: BottomToolbar.toggleFilmStrip
25
+    };
26
+
27
+    /**
28
+     * Check whether the API should be enabled or not.
29
+     * @returns {boolean}
30
+     */
31
+    APIConnector.isEnabled = function () {
32
+        var hash = location.hash;
33
+        if(hash && hash.indexOf("external") > -1 && window.postMessage)
34
+            return true;
35
+        return false;
36
+    };
37
+
38
+    /**
39
+     * Initializes the APIConnector. Setups message event listeners that will
40
+     * receive information from external applications that embed Jitsi Meet.
41
+     * It also sends a message to the external application that APIConnector
42
+     * is initialized.
43
+     */
44
+    APIConnector.init = function () {
45
+        if (window.addEventListener)
46
+        {
47
+            window.addEventListener('message',
48
+                APIConnector.processMessage, false);
49
+        }
50
+        else
51
+        {
52
+            window.attachEvent('onmessage', APIConnector.processMessage);
53
+        }
54
+        APIConnector.sendMessage({loaded: true});
55
+    };
56
+
57
+    /**
58
+     * Sends message to the external application.
59
+     * @param object
60
+     */
61
+    APIConnector.sendMessage = function (object) {
62
+        window.parent.postMessage(JSON.stringify(object), "*");
63
+    };
64
+
65
+    /**
66
+     * Processes a message event from the external application
67
+     * @param event the message event
68
+     */
69
+    APIConnector.processMessage = function(event)
70
+    {
71
+        var message;
72
+        try {
73
+            message = JSON.parse(event.data);
74
+        } catch (e) {}
75
+        for(var key in message)
76
+        {
77
+            if(commands[key])
78
+                commands[key].apply(null, message[key]);
79
+        }
80
+
81
+    };
82
+
83
+    /**
84
+     * Removes the listeners.
85
+     */
86
+    APIConnector.dispose = function () {
87
+        if(window.removeEventListener)
88
+        {
89
+            window.removeEventListener("message",
90
+                APIConnector.processMessage, false);
91
+        }
92
+        else
93
+        {
94
+            window.detachEvent('onmessage', APIConnector.processMessage);
95
+        }
96
+
97
+    };
98
+
99
+    return APIConnector;
100
+})();

+ 4
- 1
app.js Vedi File

@@ -1126,6 +1126,8 @@ function getCameraVideoSize(videoWidth,
1126 1126
 
1127 1127
 $(document).ready(function () {
1128 1128
     document.title = brand.appName;
1129
+    if(APIConnector.isEnabled())
1130
+        APIConnector.init();
1129 1131
 
1130 1132
     if(config.enableWelcomePage && window.location.pathname == "/" &&
1131 1133
         (!window.localStorage.welcomePageDisabled
@@ -1186,7 +1188,6 @@ $(document).ready(function () {
1186 1188
             }
1187 1189
         });
1188 1190
 
1189
-
1190 1191
         if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
1191 1192
             var updateTimeout;
1192 1193
             var animateTimeout;
@@ -1322,6 +1323,8 @@ $(window).bind('beforeunload', function () {
1322 1323
         });
1323 1324
     }
1324 1325
     disposeConference(true);
1326
+    if(APIConnector.isEnabled())
1327
+        APIConnector.dispose();
1325 1328
 });
1326 1329
 
1327 1330
 function disposeConference(onUnload) {

+ 80
- 0
doc/api.md Vedi File

@@ -0,0 +1,80 @@
1
+Jitsi Meet API
2
+============
3
+
4
+You can use Jitsi Meet API to embed Jitsi Meet in to your application.
5
+
6
+Installation
7
+==========
8
+
9
+To embed Jitsi Meet in your application you need to add Jitsi Meet API library
10
+```javascript
11
+<script src="https://meet.jit.si/external_api.js"></script>
12
+```
13
+
14
+The next step for embedding Jitsi Meet is to create the Jitsi Meet API object
15
+```javascript
16
+<script>
17
+    var domain = "meet.jit.si";
18
+    var room = "JitsiMeetAPIExample";
19
+    var width = 700;
20
+    var height = 700;
21
+    var api = new JitsiMeetExternalAPI(domain, room, width, height);
22
+</script>
23
+``` 
24
+You can paste that lines in your html code where you want to be placed the Jitsi Meet conference
25
+or you can specify the parent HTML element for the Jitsi Meet conference in the JitsiMeetExternalAPI
26
+constructor.
27
+```javascript
28
+    var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement);
29
+``` 
30
+If you don't specify room the user will enter in new conference with random room name.
31
+
32
+Controlling embedded Jitsi Meet Conference
33
+=========
34
+
35
+You can control the embedded Jitsi Meet conference using the JitsiMeetExternalAPI object.
36
+You can send command to Jitsi Meet conference using ```executeCommand```. 
37
+```
38
+api.executeCommand(command, arguments)
39
+```
40
+The ```command``` parameter is String object with the name of the command.
41
+The ```arguments``` parameter is array with the arguments required by the command. 
42
+If no arguments are required by the command this parameter can be omitted or you can pass empty array.
43
+Currently we support the following commands:
44
+
45
+
46
+* **displayName** - sets the display name of the local participant. This command requires one argument - 
47
+the new display name to be set
48
+```
49
+api.executeCommand('displayName', ['New Nickname']);
50
+```
51
+* **muteAudio** - mutes / unmutes the audio for the local participant. No arguments are required.
52
+```
53
+api.executeCommand('muteAudio', [])
54
+```
55
+* **muteVideo** - mutes / unmutes the video for the local participant. No arguments are required.
56
+```
57
+api.executeCommand('muteVideo', [])
58
+```
59
+* **filmStrip** - hides / shows the film strip. No arguments are required.
60
+```
61
+api.executeCommand('filmStrip', [])
62
+```
63
+
64
+You can also execute multiple commands using the method ```executeCommands```. 
65
+```
66
+api.executeCommands(commands)
67
+```
68
+The ```commands``` parameter is object with keys the names of the commands and values the arguments for the
69
+commands.
70
+
71
+```
72
+api.executeCommands({displayName: ['nickname'], muteAudio: []});
73
+```
74
+
75
+You can also remove the embedded Jitsi Meet Conference with the following code:
76
+```
77
+api.dispose()
78
+```
79
+
80
+It is a good practice to remove the conference before the page is unloaded. 

+ 199
- 0
external_api.js Vedi File

@@ -0,0 +1,199 @@
1
+/**
2
+ * Implements API class that embeds Jitsi Meet in external applications.
3
+ */
4
+var JitsiMeetExternalAPI = (function()
5
+{
6
+    /**
7
+     * The minimum width for the Jitsi Meet frame
8
+     * @type {number}
9
+     */
10
+    var MIN_WIDTH = 790;
11
+
12
+    /**
13
+     * The minimum height for the Jitsi Meet frame
14
+     * @type {number}
15
+     */
16
+    var MIN_HEIGHT = 300;
17
+
18
+    /**
19
+     * Constructs new API instance. Creates iframe element that loads
20
+     * Jitsi Meet.
21
+     * @param domain the domain name of the server that hosts the conference
22
+     * @param room_name the name of the room to join
23
+     * @param width width of the iframe
24
+     * @param height height of the iframe
25
+     * @param parent_node the node that will contain the iframe
26
+     * @constructor
27
+     */
28
+    function JitsiMeetExternalAPI(domain, room_name, width, height, parent_node)
29
+    {
30
+        this.parentNode = null;
31
+        if(parent_node)
32
+        {
33
+            this.parentNode = parent_node;
34
+        }
35
+        else
36
+        {
37
+            var scriptTag = document.scripts[document.scripts.length - 1];
38
+            this.parentNode = scriptTag.parentNode;
39
+        }
40
+
41
+        this.iframeHolder =
42
+            this.parentNode.appendChild(document.createElement("div"));
43
+        this.iframeHolder.id = "jitsiConference" + JitsiMeetExternalAPI.id;
44
+        if(width < MIN_WIDTH)
45
+            width = MIN_WIDTH;
46
+        if(height < MIN_HEIGHT)
47
+            height = MIN_HEIGHT;
48
+        this.iframeHolder.style.width = width + "px";
49
+        this.iframeHolder.style.height = height + "px";
50
+        this.frameName = "jitsiConferenceFrame" + JitsiMeetExternalAPI.id;
51
+        this.url = "https://" + domain + "/";
52
+        if(room_name)
53
+            this.url += room_name;
54
+        this.url += "#external";
55
+        JitsiMeetExternalAPI.id++;
56
+
57
+        this.frame = document.createElement("iframe");
58
+        this.frame.src = this.url;
59
+        this.frame.name = this.frameName;
60
+        this.frame.width = "100%";
61
+        this.frame.height = "100%";
62
+        this.frame = this.iframeHolder.appendChild(this.frame);
63
+
64
+        this.frameLoaded = false;
65
+        this.initialCommands = [];
66
+        this.initListeners();
67
+    }
68
+
69
+    /**
70
+     * Last id of api object
71
+     * @type {number}
72
+     */
73
+    JitsiMeetExternalAPI.id = 0;
74
+
75
+    /**
76
+     * Sends the passed object to Jitsi Meet
77
+     * @param object the object to be sent
78
+     */
79
+    JitsiMeetExternalAPI.prototype.sendMessage = function(object)
80
+    {
81
+        if(this.frameLoaded)
82
+        {
83
+            this.frame.contentWindow.postMessage(
84
+                JSON.stringify(object), this.frame.src);
85
+        }
86
+        else
87
+        {
88
+            this.initialCommands.push(object);
89
+        }
90
+
91
+    };
92
+
93
+    /**
94
+     * Executes command. The available commands are:
95
+     * displayName - sets the display name of the local participant to the value
96
+     * passed in the arguments array.
97
+     * muteAudio - mutes / unmutes audio with no arguments
98
+     * muteVideo - mutes / unmutes video with no arguments
99
+     * filmStrip - hides / shows the film strip with no arguments
100
+     * If the command doesn't require any arguments the parameter should be set
101
+     * to empty array or it may be omitted.
102
+     * @param name the name of the command
103
+     * @param arguments array of arguments
104
+     */
105
+    JitsiMeetExternalAPI.prototype.executeCommand = function(name,
106
+                                                             argumentsList)
107
+    {
108
+        var argumentsArray = argumentsList;
109
+        if(!argumentsArray)
110
+            argumentsArray = [];
111
+        var object = {};
112
+        object[name] = argumentsArray;
113
+        this.sendMessage(object);
114
+    };
115
+
116
+    /**
117
+     * Executes commands. The available commands are:
118
+     * displayName - sets the display name of the local participant to the value
119
+     * passed in the arguments array.
120
+     * muteAudio - mutes / unmutes audio with no arguments
121
+     * muteVideo - mutes / unmutes video with no arguments
122
+     * filmStrip - hides / shows the film strip with no arguments
123
+     * @param object the object with commands to be executed. The keys of the
124
+     * object are the commands that will be executed and the values are the
125
+     * arguments for the command.
126
+     */
127
+    JitsiMeetExternalAPI.prototype.executeCommands = function (object) {
128
+        this.sendMessage(object);
129
+    };
130
+
131
+    /**
132
+     * Processes message events sent from Jitsi Meet
133
+     * @param event the event
134
+     */
135
+    JitsiMeetExternalAPI.prototype.processMessage = function(event)
136
+    {
137
+        var message;
138
+        try {
139
+            message = JSON.parse(event.data);
140
+        } catch (e) {}
141
+        if(message.loaded)
142
+        {
143
+            this.onFrameLoaded();
144
+        }
145
+
146
+    };
147
+
148
+    /**
149
+     * That method is called when the Jitsi Meet is loaded. Executes saved
150
+     * commands that are send before the frame was loaded.
151
+     */
152
+    JitsiMeetExternalAPI.prototype.onFrameLoaded = function () {
153
+        this.frameLoaded = true;
154
+        for (var i = 0; i < this.initialCommands.length; i++)
155
+        {
156
+            this.sendMessage(this.initialCommands[i]);
157
+        }
158
+        this.initialCommands = null;
159
+    };
160
+
161
+    /**
162
+     * Setups the listener for message events from Jitsi Meet.
163
+     */
164
+    JitsiMeetExternalAPI.prototype.initListeners = function () {
165
+        var self = this;
166
+        this.eventListener = function (event) {
167
+            self.processMessage(event);
168
+        };
169
+        if (window.addEventListener)
170
+        {
171
+            window.addEventListener('message',
172
+                this.eventListener, false);
173
+        }
174
+        else
175
+        {
176
+            window.attachEvent('onmessage', this.eventListener);
177
+        }
178
+    };
179
+
180
+    /**
181
+     * Removes the listeners and removes the Jitsi Meet frame.
182
+     */
183
+    JitsiMeetExternalAPI.prototype.dispose = function () {
184
+        if (window.removeEventListener)
185
+        {
186
+            window.removeEventListener('message',
187
+                this.eventListener, false);
188
+        }
189
+        else
190
+        {
191
+            window.detachEvent('onmessage',
192
+                this.eventListener);
193
+        }
194
+        this.iframeHolder.parentNode.removeChild(this.iframeHolder);
195
+    };
196
+
197
+    return JitsiMeetExternalAPI;
198
+
199
+})();

+ 3
- 2
index.html Vedi File

@@ -34,7 +34,7 @@
34 34
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
35 35
     <script src="desktopsharing.js?v=3"></script><!-- desktop sharing -->
36 36
     <script src="data_channels.js?v=3"></script><!-- data channels -->
37
-    <script src="app.js?v=17"></script><!-- application logic -->
37
+    <script src="app.js?v=18"></script><!-- application logic -->
38 38
     <script src="commands.js?v=1"></script><!-- application logic -->
39 39
     <script src="chat.js?v=11"></script><!-- chat logic -->
40 40
     <script src="contact_list.js?v=4"></script><!-- contact list logic -->
@@ -47,7 +47,7 @@
47 47
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
48 48
     <script src="rtp_sts.js?v=4"></script><!-- RTP stats processing -->
49 49
     <script src="local_sts.js?v=2"></script><!-- Local stats processing -->
50
-    <script src="videolayout.js?v=21"></script><!-- video ui -->
50
+    <script src="videolayout.js?v=22"></script><!-- video ui -->
51 51
     <script src="connectionquality.js?v=1"></script>
52 52
     <script src="toolbar.js?v=6"></script><!-- toolbar ui -->
53 53
     <script src="toolbar_toggler.js?v=2"></script>
@@ -60,6 +60,7 @@
60 60
     <script src="tracking.js?v=1"></script><!-- tracking -->
61 61
     <script src="jitsipopover.js?v=3"></script>
62 62
     <script src="message_handler.js?v=1"></script>
63
+    <script src="api_connector.js?v=1"></script>
63 64
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
64 65
     <link rel="stylesheet" href="css/font.css?v=4"/>
65 66
     <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=26"/>

+ 24
- 24
videolayout.js Vedi File

@@ -622,36 +622,14 @@ var VideoLayout = (function (my) {
622 622
                     $('#editDisplayName').focus();
623 623
                     $('#editDisplayName').select();
624 624
 
625
-                    var inputDisplayNameHandler = function (name) {
626
-                        if (nickname !== name) {
627
-                            nickname = name;
628
-                            window.localStorage.displayname = nickname;
629
-                            connection.emuc.addDisplayNameToPresence(nickname);
630
-                            connection.emuc.sendPresence();
631
-
632
-                            Chat.setChatConversationMode(true);
633
-                        }
634
-
635
-                        if (!$('#localDisplayName').is(":visible")) {
636
-                            if (nickname)
637
-                                $('#localDisplayName').text(nickname + " (me)");
638
-                            else
639
-                                $('#localDisplayName')
640
-                                    .text(defaultLocalDisplayName);
641
-                            $('#localDisplayName').show();
642
-                        }
643
-
644
-                        $('#editDisplayName').hide();
645
-                    };
646
-
647 625
                     $('#editDisplayName').one("focusout", function (e) {
648
-                        inputDisplayNameHandler(this.value);
626
+                        VideoLayout.inputDisplayNameHandler(this.value);
649 627
                     });
650 628
 
651 629
                     $('#editDisplayName').on('keydown', function (e) {
652 630
                         if (e.keyCode === 13) {
653 631
                             e.preventDefault();
654
-                            inputDisplayNameHandler(this.value);
632
+                            VideoLayout.inputDisplayNameHandler(this.value);
655 633
                         }
656 634
                     });
657 635
                 });
@@ -659,6 +637,28 @@ var VideoLayout = (function (my) {
659 637
         }
660 638
     };
661 639
 
640
+    my.inputDisplayNameHandler = function (name) {
641
+        if (nickname !== name) {
642
+            nickname = name;
643
+            window.localStorage.displayname = nickname;
644
+            connection.emuc.addDisplayNameToPresence(nickname);
645
+            connection.emuc.sendPresence();
646
+
647
+            Chat.setChatConversationMode(true);
648
+        }
649
+
650
+        if (!$('#localDisplayName').is(":visible")) {
651
+            if (nickname)
652
+                $('#localDisplayName').text(nickname + " (me)");
653
+            else
654
+                $('#localDisplayName')
655
+                    .text(defaultLocalDisplayName);
656
+            $('#localDisplayName').show();
657
+        }
658
+
659
+        $('#editDisplayName').hide();
660
+    };
661
+
662 662
     /**
663 663
      * Shows/hides the display name on the remote video.
664 664
      * @param videoSpanId the identifier of the video span element

Loading…
Annulla
Salva