|
@@ -66,7 +66,6 @@ import com.nextcloud.talk.events.ConfigurationChangeEvent;
|
|
|
import com.nextcloud.talk.events.MediaStreamEvent;
|
|
|
import com.nextcloud.talk.events.NetworkEvent;
|
|
|
import com.nextcloud.talk.events.PeerConnectionEvent;
|
|
|
-import com.nextcloud.talk.events.SessionDescriptionSendEvent;
|
|
|
import com.nextcloud.talk.events.WebSocketCommunicationEvent;
|
|
|
import com.nextcloud.talk.models.ExternalSignalingServer;
|
|
|
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
|
|
@@ -79,13 +78,13 @@ import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
|
|
|
import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
|
|
|
import com.nextcloud.talk.models.json.signaling.DataChannelMessageNick;
|
|
|
import com.nextcloud.talk.models.json.signaling.NCMessagePayload;
|
|
|
-import com.nextcloud.talk.models.json.signaling.NCMessageWrapper;
|
|
|
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage;
|
|
|
import com.nextcloud.talk.models.json.signaling.Signaling;
|
|
|
import com.nextcloud.talk.models.json.signaling.SignalingOverall;
|
|
|
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
|
|
|
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
|
|
|
import com.nextcloud.talk.signaling.SignalingMessageReceiver;
|
|
|
+import com.nextcloud.talk.signaling.SignalingMessageSender;
|
|
|
import com.nextcloud.talk.ui.dialog.AudioOutputDialog;
|
|
|
import com.nextcloud.talk.users.UserManager;
|
|
|
import com.nextcloud.talk.utils.ApiUtils;
|
|
@@ -262,6 +261,9 @@ public class CallActivity extends CallBaseActivity {
|
|
|
private InternalSignalingMessageReceiver internalSignalingMessageReceiver = new InternalSignalingMessageReceiver();
|
|
|
private SignalingMessageReceiver signalingMessageReceiver;
|
|
|
|
|
|
+ private InternalSignalingMessageSender internalSignalingMessageSender = new InternalSignalingMessageSender();
|
|
|
+ private SignalingMessageSender signalingMessageSender;
|
|
|
+
|
|
|
private Map<String, SignalingMessageReceiver.CallParticipantMessageListener> callParticipantMessageListeners =
|
|
|
new HashMap<>();
|
|
|
|
|
@@ -1369,6 +1371,7 @@ public class CallActivity extends CallBaseActivity {
|
|
|
signalingMessageReceiver = internalSignalingMessageReceiver;
|
|
|
signalingMessageReceiver.addListener(participantListMessageListener);
|
|
|
signalingMessageReceiver.addListener(offerMessageListener);
|
|
|
+ signalingMessageSender = internalSignalingMessageSender;
|
|
|
joinRoomAndCall();
|
|
|
}
|
|
|
}
|
|
@@ -1572,6 +1575,7 @@ public class CallActivity extends CallBaseActivity {
|
|
|
signalingMessageReceiver = webSocketClient.getSignalingMessageReceiver();
|
|
|
signalingMessageReceiver.addListener(participantListMessageListener);
|
|
|
signalingMessageReceiver.addListener(offerMessageListener);
|
|
|
+ signalingMessageSender = webSocketClient.getSignalingMessageSender();
|
|
|
} else {
|
|
|
if (webSocketClient.isConnected() && currentCallStatus == CallStatus.PUBLISHER_FAILED) {
|
|
|
webSocketClient.restartWebSocket();
|
|
@@ -1615,11 +1619,6 @@ public class CallActivity extends CallBaseActivity {
|
|
|
performCall();
|
|
|
}
|
|
|
break;
|
|
|
- case "peerReadyForRequestingOffer":
|
|
|
- Log.d(TAG, "onMessageEvent 'peerReadyForRequestingOffer'");
|
|
|
- webSocketClient.requestOfferForSessionIdWithType(
|
|
|
- webSocketCommunicationEvent.getHashMap().get("sessionId"), "video");
|
|
|
- break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1955,7 +1954,8 @@ public class CallActivity extends CallBaseActivity {
|
|
|
true,
|
|
|
true,
|
|
|
type,
|
|
|
- signalingMessageReceiver);
|
|
|
+ signalingMessageReceiver,
|
|
|
+ signalingMessageSender);
|
|
|
|
|
|
} else if (hasMCU) {
|
|
|
peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
|
|
@@ -1967,7 +1967,8 @@ public class CallActivity extends CallBaseActivity {
|
|
|
false,
|
|
|
true,
|
|
|
type,
|
|
|
- signalingMessageReceiver);
|
|
|
+ signalingMessageReceiver,
|
|
|
+ signalingMessageSender);
|
|
|
} else {
|
|
|
if (!"screen".equals(type)) {
|
|
|
peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
|
|
@@ -1979,7 +1980,8 @@ public class CallActivity extends CallBaseActivity {
|
|
|
false,
|
|
|
false,
|
|
|
type,
|
|
|
- signalingMessageReceiver);
|
|
|
+ signalingMessageReceiver,
|
|
|
+ signalingMessageSender);
|
|
|
} else {
|
|
|
peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
|
|
|
iceServers,
|
|
@@ -1990,7 +1992,8 @@ public class CallActivity extends CallBaseActivity {
|
|
|
false,
|
|
|
false,
|
|
|
type,
|
|
|
- signalingMessageReceiver);
|
|
|
+ signalingMessageReceiver,
|
|
|
+ signalingMessageSender);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2234,80 +2237,6 @@ public class CallActivity extends CallBaseActivity {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Subscribe(threadMode = ThreadMode.BACKGROUND)
|
|
|
- public void onMessageEvent(SessionDescriptionSendEvent sessionDescriptionSend) throws IOException {
|
|
|
- NCMessageWrapper ncMessageWrapper = new NCMessageWrapper();
|
|
|
- ncMessageWrapper.setEv("message");
|
|
|
- ncMessageWrapper.setSessionId(callSession);
|
|
|
- NCSignalingMessage ncSignalingMessage = new NCSignalingMessage();
|
|
|
- ncSignalingMessage.setTo(sessionDescriptionSend.getPeerId());
|
|
|
- ncSignalingMessage.setRoomType(sessionDescriptionSend.getVideoStreamType());
|
|
|
- ncSignalingMessage.setType(sessionDescriptionSend.getType());
|
|
|
- NCMessagePayload ncMessagePayload = new NCMessagePayload();
|
|
|
- ncMessagePayload.setType(sessionDescriptionSend.getType());
|
|
|
-
|
|
|
- if (!"candidate".equals(sessionDescriptionSend.getType())) {
|
|
|
- ncMessagePayload.setSdp(sessionDescriptionSend.getSessionDescription().description);
|
|
|
- ncMessagePayload.setNick(conversationUser.getDisplayName());
|
|
|
- } else {
|
|
|
- ncMessagePayload.setIceCandidate(sessionDescriptionSend.getNcIceCandidate());
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // Set all we need
|
|
|
- ncSignalingMessage.setPayload(ncMessagePayload);
|
|
|
- ncMessageWrapper.setSignalingMessage(ncSignalingMessage);
|
|
|
-
|
|
|
-
|
|
|
- if (!hasExternalSignalingServer) {
|
|
|
- StringBuilder stringBuilder = new StringBuilder();
|
|
|
- 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("}");
|
|
|
-
|
|
|
- List<String> strings = new ArrayList<>();
|
|
|
- String stringToSend = stringBuilder.toString();
|
|
|
- strings.add(stringToSend);
|
|
|
-
|
|
|
- int apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, new int[]{ApiUtils.APIv3, 2, 1});
|
|
|
-
|
|
|
- ncApi.sendSignalingMessages(credentials, ApiUtils.getUrlForSignaling(apiVersion, baseUrl, roomToken),
|
|
|
- strings.toString())
|
|
|
- .retry(3)
|
|
|
- .subscribeOn(Schedulers.io())
|
|
|
- .subscribe(new Observer<SignalingOverall>() {
|
|
|
- @Override
|
|
|
- public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
|
|
- // unused atm
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onNext(@io.reactivex.annotations.NonNull SignalingOverall signalingOverall) {
|
|
|
- receivedSignalingMessages(signalingOverall.getOcs().getSignalings());
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
|
|
- Log.e(TAG, "", e);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onComplete() {
|
|
|
- // unused atm
|
|
|
- }
|
|
|
- });
|
|
|
- } else {
|
|
|
- webSocketClient.sendCallMessage(ncMessageWrapper);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
|
|
@NonNull int[] grantResults) {
|
|
@@ -2644,6 +2573,93 @@ public class CallActivity extends CallBaseActivity {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private class InternalSignalingMessageSender implements SignalingMessageSender {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void send(NCSignalingMessage ncSignalingMessage) {
|
|
|
+ addLocalParticipantNickIfNeeded(ncSignalingMessage);
|
|
|
+
|
|
|
+ String serializedNcSignalingMessage;
|
|
|
+ try {
|
|
|
+ serializedNcSignalingMessage = LoganSquare.serialize(ncSignalingMessage);
|
|
|
+ } catch (IOException e) {
|
|
|
+ Log.e(TAG, "Failed to serialize signaling message", e);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The message wrapper can not be defined in a JSON model to be directly serialized, as sent messages
|
|
|
+ // need to be serialized twice; first the signaling message, and then the wrapper as a whole. Received
|
|
|
+ // messages, on the other hand, just need to be deserialized once.
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
+ stringBuilder.append('{')
|
|
|
+ .append("\"fn\":\"")
|
|
|
+ .append(StringEscapeUtils.escapeJson(serializedNcSignalingMessage))
|
|
|
+ .append('\"')
|
|
|
+ .append(',')
|
|
|
+ .append("\"sessionId\":")
|
|
|
+ .append('\"').append(StringEscapeUtils.escapeJson(callSession)).append('\"')
|
|
|
+ .append(',')
|
|
|
+ .append("\"ev\":\"message\"")
|
|
|
+ .append('}');
|
|
|
+
|
|
|
+ List<String> strings = new ArrayList<>();
|
|
|
+ String stringToSend = stringBuilder.toString();
|
|
|
+ strings.add(stringToSend);
|
|
|
+
|
|
|
+ int apiVersion = ApiUtils.getSignalingApiVersion(conversationUser, new int[]{ApiUtils.APIv3, 2, 1});
|
|
|
+
|
|
|
+ ncApi.sendSignalingMessages(credentials, ApiUtils.getUrlForSignaling(apiVersion, baseUrl, roomToken),
|
|
|
+ strings.toString())
|
|
|
+ .retry(3)
|
|
|
+ .subscribeOn(Schedulers.io())
|
|
|
+ .subscribe(new Observer<SignalingOverall>() {
|
|
|
+ @Override
|
|
|
+ public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onNext(@io.reactivex.annotations.NonNull SignalingOverall signalingOverall) {
|
|
|
+ // When sending messages to the internal signaling server the response has been empty since
|
|
|
+ // Talk v2.9.0, so it is not really needed to process it, but there is no harm either in
|
|
|
+ // doing that, as technically messages could be returned.
|
|
|
+ receivedSignalingMessages(signalingOverall.getOcs().getSignalings());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
|
|
+ Log.e(TAG, "", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onComplete() {
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds the local participant nick to offers and answers.
|
|
|
+ *
|
|
|
+ * For legacy reasons the offers and answers sent when the internal signaling server is used are expected to
|
|
|
+ * provide the nick of the local participant.
|
|
|
+ *
|
|
|
+ * @param ncSignalingMessage the message to add the nick to
|
|
|
+ */
|
|
|
+ private void addLocalParticipantNickIfNeeded(NCSignalingMessage ncSignalingMessage) {
|
|
|
+ String type = ncSignalingMessage.getType();
|
|
|
+ if (!"offer".equals(type) && !"answer".equals(type)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ NCMessagePayload payload = ncSignalingMessage.getPayload();
|
|
|
+ if (payload == null) {
|
|
|
+ // Broken message, this should not happen
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ payload.setNick(conversationUser.getDisplayName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private class MicrophoneButtonTouchListener implements View.OnTouchListener {
|
|
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|