Browse Source

More progress towards external signaling support

Mario Danic 6 years ago
parent
commit
7bce24a850

+ 1 - 0
app/src/main/java/com/nextcloud/talk/api/ExternalSignaling.java

@@ -34,4 +34,5 @@ public interface ExternalSignaling {
 
 
     @Receive
     @Receive
     Flowable<WebSocket.Event.OnConnectionClosed> observeOnConnectionClosedEvent();
     Flowable<WebSocket.Event.OnConnectionClosed> observeOnConnectionClosedEvent();
+
 }
 }

+ 67 - 41
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -29,9 +29,11 @@ import android.graphics.Color;
 import android.os.Build;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Handler;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatActivity;
+
 import android.text.TextUtils;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater;
@@ -48,6 +50,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
 import com.bumptech.glide.load.resource.bitmap.CircleCrop;
 import com.bumptech.glide.load.resource.bitmap.CircleCrop;
 import com.bumptech.glide.request.RequestOptions;
 import com.bumptech.glide.request.RequestOptions;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.R;
+import com.nextcloud.talk.api.ExternalSignaling;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.controllers.base.BaseController;
@@ -55,6 +58,7 @@ import com.nextcloud.talk.events.ConfigurationChangeEvent;
 import com.nextcloud.talk.events.MediaStreamEvent;
 import com.nextcloud.talk.events.MediaStreamEvent;
 import com.nextcloud.talk.events.PeerConnectionEvent;
 import com.nextcloud.talk.events.PeerConnectionEvent;
 import com.nextcloud.talk.events.SessionDescriptionSendEvent;
 import com.nextcloud.talk.events.SessionDescriptionSendEvent;
+import com.nextcloud.talk.models.ExternalSignalingServer;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.call.CallOverall;
 import com.nextcloud.talk.models.json.call.CallOverall;
 import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
 import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
@@ -197,6 +201,7 @@ public class CallController extends BaseController {
     private MediaConstraints audioConstraints;
     private MediaConstraints audioConstraints;
     private MediaConstraints videoConstraints;
     private MediaConstraints videoConstraints;
     private MediaConstraints sdpConstraints;
     private MediaConstraints sdpConstraints;
+    private MediaConstraints sdpConstraintsForMCU;
     private MagicAudioManager audioManager;
     private MagicAudioManager audioManager;
     private VideoSource videoSource;
     private VideoSource videoSource;
     private VideoTrack localVideoTrack;
     private VideoTrack localVideoTrack;
@@ -238,6 +243,8 @@ public class CallController extends BaseController {
 
 
     private SpotlightView spotlightView;
     private SpotlightView spotlightView;
 
 
+    private ExternalSignalingServer externalSignalingServer;
+
     public CallController(Bundle args) {
     public CallController(Bundle args) {
         super(args);
         super(args);
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
@@ -351,6 +358,7 @@ public class CallController extends BaseController {
 
 
         //create sdpConstraints
         //create sdpConstraints
         sdpConstraints = new MediaConstraints();
         sdpConstraints = new MediaConstraints();
+        sdpConstraintsForMCU = new MediaConstraints();
         sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
         sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
         String offerToReceiveVideoString = "true";
         String offerToReceiveVideoString = "true";
 
 
@@ -358,14 +366,21 @@ public class CallController extends BaseController {
             offerToReceiveVideoString = "false";
             offerToReceiveVideoString = "false";
         }
         }
 
 
-        sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo",
-                offerToReceiveVideoString));
+        sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", offerToReceiveVideoString));
+
+        sdpConstraintsForMCU.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "false"));
+        sdpConstraintsForMCU.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "false"));
+
+        sdpConstraintsForMCU.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
+        sdpConstraintsForMCU.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
+
         sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
         sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
         sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
         sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
 
 
         if (!isVoiceOnlyCall) {
         if (!isVoiceOnlyCall) {
             cameraInitialization();
             cameraInitialization();
         }
         }
+
         microphoneInitialization();
         microphoneInitialization();
     }
     }
 
 
@@ -893,6 +908,13 @@ public class CallController extends BaseController {
                         IceServer iceServer;
                         IceServer iceServer;
                         if (signalingSettingsOverall != null && signalingSettingsOverall.getOcs() != null &&
                         if (signalingSettingsOverall != null && signalingSettingsOverall.getOcs() != null &&
                                 signalingSettingsOverall.getOcs().getSettings() != null) {
                                 signalingSettingsOverall.getOcs().getSettings() != null) {
+
+                            if (!TextUtils.isEmpty(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingServer()) &&
+                                    !TextUtils.isEmpty(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingTicket())) {
+                                externalSignalingServer.setExternalSignalingServer(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingServer());
+                                externalSignalingServer.setExternalSignalingTicket(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingTicket());
+                            }
+
                             if (signalingSettingsOverall.getOcs().getSettings().getStunServers() != null) {
                             if (signalingSettingsOverall.getOcs().getSettings().getStunServers() != null) {
                                 for (int i = 0; i < signalingSettingsOverall.getOcs().getSettings().getStunServers().size();
                                 for (int i = 0; i < signalingSettingsOverall.getOcs().getSettings().getStunServers().size();
                                      i++) {
                                      i++) {
@@ -1088,44 +1110,48 @@ public class CallController extends BaseController {
 
 
                         NotificationUtils.cancelExistingNotifications(getApplicationContext(), conversationUser);
                         NotificationUtils.cancelExistingNotifications(getApplicationContext(), conversationUser);
 
 
-                        ncApi.pullSignalingMessages(credentials, ApiUtils.getUrlForSignaling(baseUrl, urlToken))
-                                .subscribeOn(Schedulers.newThread())
-                                .observeOn(AndroidSchedulers.mainThread())
-                                .repeatWhen(observable -> observable)
-                                .takeWhile(observable -> inCall)
-                                .retry(3, observable -> inCall)
-                                .subscribe(new Observer<SignalingOverall>() {
-                                    @Override
-                                    public void onSubscribe(Disposable d) {
-                                        signalingDisposable = d;
-                                    }
+                        if (externalSignalingServer == null) {
+                            ncApi.pullSignalingMessages(credentials, ApiUtils.getUrlForSignaling(baseUrl, urlToken))
+                                    .subscribeOn(Schedulers.newThread())
+                                    .observeOn(AndroidSchedulers.mainThread())
+                                    .repeatWhen(observable -> observable)
+                                    .takeWhile(observable -> inCall)
+                                    .retry(3, observable -> inCall)
+                                    .subscribe(new Observer<SignalingOverall>() {
+                                        @Override
+                                        public void onSubscribe(Disposable d) {
+                                            signalingDisposable = d;
+                                        }
 
 
-                                    @Override
-                                    public void onNext(SignalingOverall signalingOverall) {
-                                        if (signalingOverall.getOcs().getSignalings() != null) {
-                                            for (int i = 0; i < signalingOverall.getOcs().getSignalings().size(); i++) {
-                                                try {
-                                                    receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
-                                                } catch (IOException e) {
-                                                    Log.e(TAG, "Failed to process received signaling" +
-                                                            " message");
+                                        @Override
+                                        public void onNext(SignalingOverall signalingOverall) {
+                                            if (signalingOverall.getOcs().getSignalings() != null) {
+                                                for (int i = 0; i < signalingOverall.getOcs().getSignalings().size(); i++) {
+                                                    try {
+                                                        receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
+                                                    } catch (IOException e) {
+                                                        Log.e(TAG, "Failed to process received signaling" +
+                                                                " message");
+                                                    }
                                                 }
                                                 }
                                             }
                                             }
                                         }
                                         }
-                                    }
 
 
-                                    @Override
-                                    public void onError(Throwable e) {
-                                        dispose(signalingDisposable);
-                                    }
+                                        @Override
+                                        public void onError(Throwable e) {
+                                            dispose(signalingDisposable);
+                                        }
 
 
-                                    @Override
-                                    public void onComplete() {
-                                        dispose(signalingDisposable);
-                                    }
-                                });
+                                        @Override
+                                        public void onComplete() {
+                                            dispose(signalingDisposable);
+                                        }
+                                    });
 
 
 
 
+                        } else {
+
+                        }
                     }
                     }
 
 
                     @Override
                     @Override
@@ -1497,7 +1523,7 @@ public class CallController extends BaseController {
                 .PeerConnectionEventType.SENSOR_FAR) ||
                 .PeerConnectionEventType.SENSOR_FAR) ||
                 peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
                 peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
                         .PeerConnectionEventType.SENSOR_NEAR)) {
                         .PeerConnectionEventType.SENSOR_NEAR)) {
-            
+
             if (!isVoiceOnlyCall) {
             if (!isVoiceOnlyCall) {
                 boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
                 boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
                         .PeerConnectionEventType.SENSOR_FAR) && videoOn;
                         .PeerConnectionEventType.SENSOR_FAR) && videoOn;
@@ -1559,14 +1585,14 @@ public class CallController extends BaseController {
 
 
         StringBuilder stringBuilder = new StringBuilder();
         StringBuilder stringBuilder = new StringBuilder();
         stringBuilder.append("{")
         stringBuilder.append("{")
-                     .append("\"fn\":\"")
-                     .append(StringEscapeUtils.escapeJson(LoganSquare.serialize(ncMessageWrapper.getSignalingMessage()))).append("\"")
-                     .append(",")
-                     .append("\"sessionId\":")
-                     .append("\"").append(StringEscapeUtils.escapeJson(callSession)).append("\"")
-                     .append(",")
-                     .append("\"ev\":\"message\"")
-                     .append("}");
+                .append("\"fn\":\"")
+                .append(StringEscapeUtils.escapeJson(LoganSquare.serialize(ncMessageWrapper.getSignalingMessage()))).append("\"")
+                .append(",")
+                .append("\"sessionId\":")
+                .append("\"").append(StringEscapeUtils.escapeJson(callSession)).append("\"")
+                .append(",")
+                .append("\"ev\":\"message\"")
+                .append("}");
 
 
         List<String> strings = new ArrayList<>();
         List<String> strings = new ArrayList<>();
         String stringToSend = stringBuilder.toString();
         String stringToSend = stringBuilder.toString();

+ 29 - 0
app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.java

@@ -0,0 +1,29 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models;
+
+import lombok.Data;
+
+@Data
+public class ExternalSignalingServer {
+    String externalSignalingServer;
+    String externalSignalingTicket;
+}

+ 37 - 0
app/src/main/java/com/nextcloud/talk/models/json/websocket/AuthParametersWebSocketMessage.java

@@ -0,0 +1,37 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models.json.websocket;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.squareup.moshi.Json;
+
+import lombok.Data;
+
+@Data
+@JsonObject
+public class AuthParametersWebSocketMessage {
+    @JsonField(name = "userid")
+    String userid;
+
+    @Json(name = "ticket")
+    String ticket;
+}

+ 37 - 0
app/src/main/java/com/nextcloud/talk/models/json/websocket/AuthWebSocketMessage.java

@@ -0,0 +1,37 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models.json.websocket;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.squareup.moshi.Json;
+
+import lombok.Data;
+
+@Data
+@JsonObject
+public class AuthWebSocketMessage {
+    @JsonField(name = "url")
+    String url;
+
+    @JsonField(name = "params")
+    AuthParametersWebSocketMessage authParametersWebSocketMessage;
+}

+ 33 - 0
app/src/main/java/com/nextcloud/talk/models/json/websocket/BaseWebSocketMessage.java

@@ -0,0 +1,33 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models.json.websocket;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+
+import lombok.Data;
+
+@Data
+@JsonObject
+public class BaseWebSocketMessage {
+    @JsonField(name = "type")
+    String type;
+}

+ 34 - 0
app/src/main/java/com/nextcloud/talk/models/json/websocket/HelloOverallWebSocketMessage.java

@@ -0,0 +1,34 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models.json.websocket;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.squareup.moshi.Json;
+
+import lombok.Data;
+
+@Data
+@JsonObject
+public class HelloOverallWebSocketMessage extends BaseWebSocketMessage {
+    @JsonField(name = "hello")
+    HelloWebSocketMessage helloWebSocketMessage;
+}

+ 40 - 0
app/src/main/java/com/nextcloud/talk/models/json/websocket/HelloWebSocketMessage.java

@@ -0,0 +1,40 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models.json.websocket;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.squareup.moshi.Json;
+
+import lombok.Data;
+
+@Data
+@JsonObject
+public class HelloWebSocketMessage {
+    @JsonField(name = "version")
+    String version;
+
+    @JsonField(name = "resumeid")
+    String resumeid;
+
+    @JsonField(name = "auth")
+    AuthWebSocketMessage authWebSocketMessage;
+}

+ 4 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -138,6 +138,10 @@ public class ApiUtils {
         return baseUrl + ocsApiVersion + spreedApiVersion + "/chat/" + token;
         return baseUrl + ocsApiVersion + spreedApiVersion + "/chat/" + token;
     }
     }
 
 
+    public static String getUrlForExternalServerAuthBackend(String baseUrl) {
+        return baseUrl + ocsApiVersion + spreedApiVersion + "/signaling/backend";
+    }
+
     public static String getUrlForMentionSuggestions(String baseUrl, String token) {
     public static String getUrlForMentionSuggestions(String baseUrl, String token) {
         return getUrlForChat(baseUrl, token) + "/mentions";
         return getUrlForChat(baseUrl, token) + "/mentions";
     }
     }

+ 19 - 5
app/src/main/java/com/nextcloud/talk/webrtc/ScarletHelper.java

@@ -47,18 +47,32 @@ public class ScarletHelper {
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
     }
     }
 
 
-    public ExternalSignaling getExternalSignalingInstanceForServer(String url) {
-        if (externalSignalingMap.containsKey(url)) {
-            return externalSignalingMap.get(url);
+    private String getExternalSignalingServerUrlFromSettingsUrl(String url) {
+        String generatedURL = url.replace("https://", "wss://").replace("http://", "ws://");
+
+        if (generatedURL.endsWith("/")) {
+            generatedURL += "spreed";
+        } else {
+            generatedURL += "/spreed";
+        }
+
+        return generatedURL;
+    }
+
+    public ExternalSignaling getExternalSignalingInstanceForServer(String url, boolean forceReconnect) {
+        String connectionUrl = getExternalSignalingServerUrlFromSettingsUrl(url);
+
+        if (externalSignalingMap.containsKey(connectionUrl) && !forceReconnect) {
+            return externalSignalingMap.get(connectionUrl);
         } else {
         } else {
             Scarlet scarlet = new Scarlet.Builder()
             Scarlet scarlet = new Scarlet.Builder()
                     .backoffStrategy(new LinearBackoffStrategy(500))
                     .backoffStrategy(new LinearBackoffStrategy(500))
-                    .webSocketFactory(OkHttpClientUtils.newWebSocketFactory(okHttpClient, url))
+                    .webSocketFactory(OkHttpClientUtils.newWebSocketFactory(okHttpClient, connectionUrl))
                     .addMessageAdapterFactory(new MoshiMessageAdapter.Factory())
                     .addMessageAdapterFactory(new MoshiMessageAdapter.Factory())
                     .addStreamAdapterFactory(new RxJava2StreamAdapterFactory())
                     .addStreamAdapterFactory(new RxJava2StreamAdapterFactory())
                     .build();
                     .build();
             ExternalSignaling externalSignaling = scarlet.create(ExternalSignaling.class);
             ExternalSignaling externalSignaling = scarlet.create(ExternalSignaling.class);
-            externalSignalingMap.put(url, externalSignaling);
+            externalSignalingMap.put(connectionUrl, externalSignaling);
             return externalSignaling;
             return externalSignaling;
         }
         }
     }
     }