소스 검색

Merge pull request #1774 from nextcloud/feature/1773/update-webrtc-library

Android update WebRTC library
Tim Krueger 3 년 전
부모
커밋
89f64b392a

+ 19 - 1
app/build.gradle

@@ -4,9 +4,11 @@
  * @author Mario Danic
  * @author Andy Scherzinger
  * @author Marcel Hibbe
+ * @author Tim Krüger
  * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
+ * Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
  *
  * 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
@@ -34,6 +36,20 @@ configurations {
     ktlint
 }
 
+def urlFile = { url, fileName ->
+    File file = new File("$buildDir/download/${fileName}")
+    file.parentFile.mkdirs()
+    if (!file.exists()) {
+        new URL(url).withInputStream { downloadStream ->
+            file.withOutputStream { fileOut ->
+                fileOut << downloadStream
+            }
+        }
+    }
+    files(file.absolutePath)
+}
+
+
 android {
     compileSdkVersion 30
     buildToolsVersion '30.0.3'
@@ -134,6 +150,7 @@ android {
     }
 
     check.dependsOn 'spotbugsGplayDebugReport', 'lint', 'ktlint', 'detekt'
+    lint.dependsOn 'preBuild'
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
@@ -240,7 +257,8 @@ dependencies {
     kapt "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
     implementation 'eu.davidea:flexible-adapter:5.1.0'
     implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
-    implementation 'org.webrtc:google-webrtc:1.0.32006'
+    implementation urlFile('https://github.com/nextcloud-releases/talk-clients-webrtc/releases/download/96.4664.0-RC1/libwebrtc-96.4664.0.aar',
+        'libwebrtc-96.4664.0.aar')
     implementation 'com.yarolegovich:lovely-dialog:1.1.1'
     implementation 'com.yarolegovich:mp:1.1.6'
     implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'

+ 103 - 95
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -93,7 +93,7 @@ import com.nextcloud.talk.utils.power.PowerManagerUtils;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder;
 import com.nextcloud.talk.webrtc.MagicAudioManager;
-import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
+import com.nextcloud.talk.webrtc.PeerConnectionWrapper;
 import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
 import com.nextcloud.talk.webrtc.MagicWebSocketInstance;
 import com.nextcloud.talk.webrtc.WebSocketConnectionHelper;
@@ -213,9 +213,9 @@ public class CallActivity extends CallBaseActivity {
     private UserEntity conversationUser;
     private String conversationName;
     private String callSession;
-    private MediaStream localMediaStream;
+    private MediaStream localStream;
     private String credentials;
-    private List<MagicPeerConnectionWrapper> magicPeerConnectionWrapperList = new ArrayList<>();
+    private List<PeerConnectionWrapper> peerConnectionWrapperList = new ArrayList<>();
     private Map<String, Participant> participantMap = new HashMap<>();
 
     private boolean videoOn = false;
@@ -408,7 +408,7 @@ public class CallActivity extends CallBaseActivity {
         audioConstraints = new MediaConstraints();
         videoConstraints = new MediaConstraints();
 
-        localMediaStream = peerConnectionFactory.createLocalMediaStream("NCMS");
+        localStream = peerConnectionFactory.createLocalMediaStream("NCMS");
 
         // Create and audio manager that will take care of audio routing,
         // audio modes, audio device enumeration etc.
@@ -781,7 +781,7 @@ public class CallActivity extends CallBaseActivity {
             videoCapturer.initialize(surfaceTextureHelper, getApplicationContext(), videoSource.getCapturerObserver());
         }
         localVideoTrack = peerConnectionFactory.createVideoTrack("NCv0", videoSource);
-        localMediaStream.addTrack(localVideoTrack);
+        localStream.addTrack(localVideoTrack);
         localVideoTrack.setEnabled(false);
         localVideoTrack.addSink(binding.selfVideoRenderer);
     }
@@ -791,7 +791,7 @@ public class CallActivity extends CallBaseActivity {
         audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
         localAudioTrack = peerConnectionFactory.createAudioTrack("NCa0", audioSource);
         localAudioTrack.setEnabled(false);
-        localMediaStream.addTrack(localAudioTrack);
+        localStream.addTrack(localAudioTrack);
     }
 
     private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
@@ -963,8 +963,8 @@ public class CallActivity extends CallBaseActivity {
                 }
             }
 
-            if (localMediaStream != null && localMediaStream.videoTracks.size() > 0) {
-                localMediaStream.videoTracks.get(0).setEnabled(enable);
+            if (localStream != null && localStream.videoTracks.size() > 0) {
+                localStream.videoTracks.get(0).setEnabled(enable);
             }
             if (enable) {
                 binding.selfVideoRenderer.setVisibility(View.VISIBLE);
@@ -980,20 +980,20 @@ public class CallActivity extends CallBaseActivity {
                 binding.microphoneButton.setAlpha(0.7f);
             }
 
-            if (localMediaStream != null && localMediaStream.audioTracks.size() > 0) {
-                localMediaStream.audioTracks.get(0).setEnabled(enable);
+            if (localStream != null && localStream.audioTracks.size() > 0) {
+                localStream.audioTracks.get(0).setEnabled(enable);
             }
         }
 
-        if (isConnectionEstablished() && magicPeerConnectionWrapperList != null) {
+        if (isConnectionEstablished() && peerConnectionWrapperList != null) {
             if (!hasMCU) {
-                for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
-                    magicPeerConnectionWrapper.sendChannelData(new DataChannelMessage(message));
+                for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) {
+                    peerConnectionWrapper.sendChannelData(new DataChannelMessage(message));
                 }
             } else {
-                for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
-                    if (magicPeerConnectionWrapper.getSessionId().equals(webSocketClient.getSessionId())) {
-                        magicPeerConnectionWrapper.sendChannelData(new DataChannelMessage(message));
+                for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) {
+                    if (peerConnectionWrapper.getSessionId().equals(webSocketClient.getSessionId())) {
+                        peerConnectionWrapper.sendChannelData(new DataChannelMessage(message));
                         break;
                     }
                 }
@@ -1517,7 +1517,7 @@ public class CallActivity extends CallBaseActivity {
 
     private void processMessage(NCSignalingMessage ncSignalingMessage) {
         if (ncSignalingMessage.getRoomType().equals("video") || ncSignalingMessage.getRoomType().equals("screen")) {
-            MagicPeerConnectionWrapper magicPeerConnectionWrapper =
+            PeerConnectionWrapper peerConnectionWrapper =
                 getPeerConnectionWrapperForSessionIdAndType(ncSignalingMessage.getFrom(),
                                                             ncSignalingMessage.getRoomType(), false);
 
@@ -1535,7 +1535,7 @@ public class CallActivity extends CallBaseActivity {
                         break;
                     case "offer":
                     case "answer":
-                        magicPeerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick());
+                        peerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick());
                         SessionDescription sessionDescriptionWithPreferredCodec;
 
                         String sessionDescriptionStringWithPreferredCodec = MagicWebRTCUtils.preferCodec
@@ -1546,8 +1546,8 @@ public class CallActivity extends CallBaseActivity {
                             SessionDescription.Type.fromCanonicalForm(type),
                             sessionDescriptionStringWithPreferredCodec);
 
-                        if (magicPeerConnectionWrapper.getPeerConnection() != null) {
-                            magicPeerConnectionWrapper.getPeerConnection().setRemoteDescription(magicPeerConnectionWrapper
+                        if (peerConnectionWrapper.getPeerConnection() != null) {
+                            peerConnectionWrapper.getPeerConnection().setRemoteDescription(peerConnectionWrapper
                                                                                                     .getMagicSdpObserver(), sessionDescriptionWithPreferredCodec);
                         }
                         break;
@@ -1555,10 +1555,10 @@ public class CallActivity extends CallBaseActivity {
                         NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate();
                         IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(),
                                                                      ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate());
-                        magicPeerConnectionWrapper.addCandidate(iceCandidate);
+                        peerConnectionWrapper.addCandidate(iceCandidate);
                         break;
                     case "endOfCandidates":
-                        magicPeerConnectionWrapper.drainIceCandidates();
+                        peerConnectionWrapper.drainIceCandidates();
                         break;
                     default:
                         break;
@@ -1608,7 +1608,7 @@ public class CallActivity extends CallBaseActivity {
                 peerConnectionFactory = null;
             }
 
-            localMediaStream = null;
+
             localAudioTrack = null;
             localVideoTrack = null;
 
@@ -1618,8 +1618,16 @@ public class CallActivity extends CallBaseActivity {
             }
         }
 
-        for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) {
-            endPeerConnection(magicPeerConnectionWrapperList.get(i).getSessionId(), false);
+        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
+            endPeerConnection(peerConnectionWrapperList.get(i).getSessionId(), false);
+        }
+
+        if(localStream != null) {
+            localStream.dispose();
+            localStream = null;
+            Log.d(TAG, "Disposed localStream");
+        } else {
+            Log.d(TAG, "localStream is null");
         }
 
         hangupNetworkCalls(shutDownView);
@@ -1703,9 +1711,9 @@ public class CallActivity extends CallBaseActivity {
             }
         }
 
-        for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
-            if (!magicPeerConnectionWrapper.isMCUPublisher()) {
-                oldSessions.add(magicPeerConnectionWrapper.getSessionId());
+        for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) {
+            if (!peerConnectionWrapper.isMCUPublisher()) {
+                oldSessions.add(peerConnectionWrapper.getSessionId());
             }
         }
 
@@ -1775,86 +1783,86 @@ public class CallActivity extends CallBaseActivity {
             });
     }
 
-    private void deleteMagicPeerConnection(MagicPeerConnectionWrapper magicPeerConnectionWrapper) {
-        magicPeerConnectionWrapper.removePeerConnection();
-        magicPeerConnectionWrapperList.remove(magicPeerConnectionWrapper);
+    private void deletePeerConnection(PeerConnectionWrapper peerConnectionWrapper) {
+        peerConnectionWrapper.removePeerConnection();
+        peerConnectionWrapperList.remove(peerConnectionWrapper);
     }
 
-    private MagicPeerConnectionWrapper getPeerConnectionWrapperForSessionId(String sessionId, String type) {
-        for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) {
-            if (magicPeerConnectionWrapperList.get(i).getSessionId().equals(sessionId) && magicPeerConnectionWrapperList.get(i).getVideoStreamType().equals(type)) {
-                return magicPeerConnectionWrapperList.get(i);
+    private PeerConnectionWrapper getPeerConnectionWrapperForSessionId(String sessionId, String type) {
+        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
+            if (peerConnectionWrapperList.get(i).getSessionId().equals(sessionId) && peerConnectionWrapperList.get(i).getVideoStreamType().equals(type)) {
+                return peerConnectionWrapperList.get(i);
             }
         }
 
         return null;
     }
 
-    private MagicPeerConnectionWrapper getPeerConnectionWrapperForSessionIdAndType(String sessionId, String type, boolean publisher) {
-        MagicPeerConnectionWrapper magicPeerConnectionWrapper;
-        if ((magicPeerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId, type)) != null) {
-            return magicPeerConnectionWrapper;
+    private PeerConnectionWrapper getPeerConnectionWrapperForSessionIdAndType(String sessionId, String type, boolean publisher) {
+        PeerConnectionWrapper peerConnectionWrapper;
+        if ((peerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId, type)) != null) {
+            return peerConnectionWrapper;
         } else {
             if (hasMCU && publisher) {
-                magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
-                                                                            iceServers,
-                                                                            sdpConstraintsForMCU,
-                                                                            sessionId,
-                                                                            callSession,
-                                                                            localMediaStream,
-                                                                            true,
-                                                                            true,
-                                                                            type);
+                peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
+                                                                  iceServers,
+                                                                  sdpConstraintsForMCU,
+                                                                  sessionId,
+                                                                  callSession,
+                                                                  localStream,
+                                                                  true,
+                                                                  true,
+                                                                  type);
 
             } else if (hasMCU) {
-                magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
-                                                                            iceServers,
-                                                                            sdpConstraints,
-                                                                            sessionId,
-                                                                            callSession,
-                                                                            null,
-                                                                            false,
-                                                                            true,
-                                                                            type);
+                peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
+                                                                  iceServers,
+                                                                  sdpConstraints,
+                                                                  sessionId,
+                                                                  callSession,
+                                                                  null,
+                                                                  false,
+                                                                  true,
+                                                                  type);
             } else {
                 if (!"screen".equals(type)) {
-                    magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
-                                                                                iceServers,
-                                                                                sdpConstraints,
-                                                                                sessionId,
-                                                                                callSession,
-                                                                                localMediaStream,
-                                                                                false,
-                                                                                false,
-                                                                                type);
+                    peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
+                                                                      iceServers,
+                                                                      sdpConstraints,
+                                                                      sessionId,
+                                                                      callSession,
+                                                                      localStream,
+                                                                      false,
+                                                                      false,
+                                                                      type);
                 } else {
-                    magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
-                                                                                iceServers,
-                                                                                sdpConstraints,
-                                                                                sessionId,
-                                                                                callSession,
-                                                                                null,
-                                                                                false,
-                                                                                false,
-                                                                                type);
+                    peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
+                                                                      iceServers,
+                                                                      sdpConstraints,
+                                                                      sessionId,
+                                                                      callSession,
+                                                                      null,
+                                                                      false,
+                                                                      false,
+                                                                      type);
                 }
             }
 
-            magicPeerConnectionWrapperList.add(magicPeerConnectionWrapper);
+            peerConnectionWrapperList.add(peerConnectionWrapper);
 
             if (publisher) {
                 startSendingNick();
             }
 
-            return magicPeerConnectionWrapper;
+            return peerConnectionWrapper;
         }
     }
 
-    private List<MagicPeerConnectionWrapper> getPeerConnectionWrapperListForSessionId(String sessionId) {
-        List<MagicPeerConnectionWrapper> internalList = new ArrayList<>();
-        for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
-            if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
-                internalList.add(magicPeerConnectionWrapper);
+    private List<PeerConnectionWrapper> getPeerConnectionWrapperListForSessionId(String sessionId) {
+        List<PeerConnectionWrapper> internalList = new ArrayList<>();
+        for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) {
+            if (peerConnectionWrapper.getSessionId().equals(sessionId)) {
+                internalList.add(peerConnectionWrapper);
             }
         }
 
@@ -1862,15 +1870,15 @@ public class CallActivity extends CallBaseActivity {
     }
 
     private void endPeerConnection(String sessionId, boolean justScreen) {
-        List<MagicPeerConnectionWrapper> magicPeerConnectionWrappers;
-        MagicPeerConnectionWrapper magicPeerConnectionWrapper;
-        if (!(magicPeerConnectionWrappers = getPeerConnectionWrapperListForSessionId(sessionId)).isEmpty()) {
-            for (int i = 0; i < magicPeerConnectionWrappers.size(); i++) {
-                magicPeerConnectionWrapper = magicPeerConnectionWrappers.get(i);
-                if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
-                    if (magicPeerConnectionWrapper.getVideoStreamType().equals("screen") || !justScreen) {
+        List<PeerConnectionWrapper> peerConnectionWrappers;
+        PeerConnectionWrapper peerConnectionWrapper;
+        if (!(peerConnectionWrappers = getPeerConnectionWrapperListForSessionId(sessionId)).isEmpty()) {
+            for (int i = 0; i < peerConnectionWrappers.size(); i++) {
+                peerConnectionWrapper = peerConnectionWrappers.get(i);
+                if (peerConnectionWrapper.getSessionId().equals(sessionId)) {
+                    if (peerConnectionWrapper.getVideoStreamType().equals("screen") || !justScreen) {
                         runOnUiThread(() -> removeMediaStream(sessionId));
-                        deleteMagicPeerConnection(magicPeerConnectionWrapper);
+                        deletePeerConnection(peerConnectionWrapper);
                     }
                 }
             }
@@ -1982,10 +1990,10 @@ public class CallActivity extends CallBaseActivity {
         nickChangedPayload.put("userid", conversationUser.getUserId());
         nickChangedPayload.put("name", conversationUser.getDisplayName());
         dataChannelMessage.setPayload(nickChangedPayload);
-        final MagicPeerConnectionWrapper magicPeerConnectionWrapper;
-        for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) {
-            if (magicPeerConnectionWrapperList.get(i).isMCUPublisher()) {
-                magicPeerConnectionWrapper = magicPeerConnectionWrapperList.get(i);
+        final PeerConnectionWrapper peerConnectionWrapper;
+        for (int i = 0; i < peerConnectionWrapperList.size(); i++) {
+            if (peerConnectionWrapperList.get(i).isMCUPublisher()) {
+                peerConnectionWrapper = peerConnectionWrapperList.get(i);
                 Observable
                     .interval(1, TimeUnit.SECONDS)
                     .repeatUntil(() -> (!isConnectionEstablished() || isDestroyed()))
@@ -1998,7 +2006,7 @@ public class CallActivity extends CallBaseActivity {
 
                         @Override
                         public void onNext(@io.reactivex.annotations.NonNull Long aLong) {
-                            magicPeerConnectionWrapper.sendNickChannelData(dataChannelMessage);
+                            peerConnectionWrapper.sendNickChannelData(dataChannelMessage);
                         }
 
                         @Override

+ 72 - 98
app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java → app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java

@@ -2,6 +2,8 @@
  * Nextcloud Talk application
  *
  * @author Mario Danic
+ * @author Tim Krüger
+ * Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
  * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -37,6 +39,7 @@ import com.nextcloud.talk.models.json.signaling.DataChannelMessageNick;
 import com.nextcloud.talk.models.json.signaling.NCIceCandidate;
 
 import org.greenrobot.eventbus.EventBus;
+import org.webrtc.AudioTrack;
 import org.webrtc.DataChannel;
 import org.webrtc.IceCandidate;
 import org.webrtc.MediaConstraints;
@@ -46,81 +49,87 @@ import org.webrtc.PeerConnectionFactory;
 import org.webrtc.RtpReceiver;
 import org.webrtc.SdpObserver;
 import org.webrtc.SessionDescription;
+import org.webrtc.VideoTrack;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Objects;
 
 import javax.inject.Inject;
 
 import androidx.annotation.Nullable;
 import autodagger.AutoInjector;
 
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
 @AutoInjector(NextcloudTalkApplication.class)
-public class MagicPeerConnectionWrapper {
-    private static final String TAG = "MagicPeerConWrapper";
+public class PeerConnectionWrapper {
+
+    private static final String TAG = PeerConnectionWrapper.class.getCanonicalName();
 
     private List<IceCandidate> iceCandidates = new ArrayList<>();
     private PeerConnection peerConnection;
     private String sessionId;
     private String nick;
-    private MediaConstraints sdpConstraints;
-    private DataChannel magicDataChannel;
-    private MagicSdpObserver magicSdpObserver;
-    private MediaStream remoteMediaStream;
-
-    private boolean remoteVideoOn;
-    private boolean remoteAudioOn;
+    private final MediaConstraints mediaConstraints;
+    private DataChannel dataChannel;
+    private final MagicSdpObserver magicSdpObserver;
+    private MediaStream remoteStream;
 
-    private boolean hasInitiated;
+    private final boolean hasInitiated;
 
-    private MediaStream localMediaStream;
-    private boolean isMCUPublisher;
-    private boolean hasMCU;
-    private String videoStreamType;
-
-    private int connectionAttempts = 0;
-    private PeerConnection.IceConnectionState peerIceConnectionState;
+    private final MediaStream localStream;
+    private final boolean isMCUPublisher;
+    private final String videoStreamType;
 
     @Inject
     Context context;
 
-    public MagicPeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory,
-                                      List<PeerConnection.IceServer> iceServerList,
-                                      MediaConstraints sdpConstraints,
-                                      String sessionId, String localSession, @Nullable MediaStream mediaStream,
-                                      boolean isMCUPublisher, boolean hasMCU, String videoStreamType) {
+    public PeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory,
+                                 List<PeerConnection.IceServer> iceServerList,
+                                 MediaConstraints mediaConstraints,
+                                 String sessionId, String localSession, @Nullable MediaStream localStream,
+                                 boolean isMCUPublisher, boolean hasMCU, String videoStreamType) {
 
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
+        Objects.requireNonNull(NextcloudTalkApplication.Companion.getSharedApplication()).getComponentApplication().inject(this);
 
-        this.localMediaStream = mediaStream;
+        this.localStream = localStream;
         this.videoStreamType = videoStreamType;
-        this.hasMCU = hasMCU;
 
         this.sessionId = sessionId;
-        this.sdpConstraints = sdpConstraints;
+        this.mediaConstraints = mediaConstraints;
 
         magicSdpObserver = new MagicSdpObserver();
         hasInitiated = sessionId.compareTo(localSession) < 0;
         this.isMCUPublisher = isMCUPublisher;
-        
-        peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, sdpConstraints,
-                new MagicPeerConnectionObserver());
+
+        PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServerList);
+        configuration.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
+        peerConnection = peerConnectionFactory.createPeerConnection(configuration, new MagicPeerConnectionObserver());
 
         if (peerConnection != null) {
-            if (localMediaStream != null) {
-                peerConnection.addStream(localMediaStream);
+            if (this.localStream != null) {
+                List<String> localStreamIds = Collections.singletonList(this.localStream.getId());
+                for(AudioTrack track : this.localStream.audioTracks) {
+                    peerConnection.addTrack(track, localStreamIds);
+                }
+                for(VideoTrack track : this.localStream.videoTracks) {
+                    peerConnection.addTrack(track, localStreamIds);
+                }
             }
 
             if (hasMCU || hasInitiated) {
                 DataChannel.Init init = new DataChannel.Init();
                 init.negotiated = false;
-                magicDataChannel = peerConnection.createDataChannel("status", init);
-                magicDataChannel.registerObserver(new MagicDataChannelObserver());
+                dataChannel = peerConnection.createDataChannel("status", init);
+                dataChannel.registerObserver(new MagicDataChannelObserver());
                 if (isMCUPublisher) {
-                    peerConnection.createOffer(magicSdpObserver, sdpConstraints);
+                    peerConnection.createOffer(magicSdpObserver, mediaConstraints);
                 } else if (hasMCU && this.videoStreamType.equals("video")) {
                     // If the connection type is "screen" the client sharing the screen will send an
                     // offer; offers should be requested only for videos.
@@ -128,7 +137,7 @@ public class MagicPeerConnectionWrapper {
                     hashMap.put("sessionId", sessionId);
                     EventBus.getDefault().post(new WebSocketCommunicationEvent("peerReadyForRequestingOffer", hashMap));
                 } else if (!hasMCU && hasInitiated) {
-                    peerConnection.createOffer(magicSdpObserver, sdpConstraints);
+                    peerConnection.createOffer(magicSdpObserver, mediaConstraints);
                 }
             }
         }
@@ -139,18 +148,20 @@ public class MagicPeerConnectionWrapper {
     }
 
     public void removePeerConnection() {
-        if (magicDataChannel != null) {
-            magicDataChannel.dispose();
-            magicDataChannel = null;
+        if (dataChannel != null) {
+            dataChannel.dispose();
+            dataChannel = null;
+            Log.d(TAG, "Disposed DataChannel");
+        } else {
+            Log.d(TAG, "DataChannel is null.");
         }
 
         if (peerConnection != null) {
-            if (localMediaStream != null) {
-                peerConnection.removeStream(localMediaStream);
-            }
-
             peerConnection.close();
             peerConnection = null;
+            Log.d(TAG, "Disposed PeerConnection");
+        } else {
+            Log.d(TAG, "PeerConnection is null.");
         }
     }
 
@@ -179,10 +190,10 @@ public class MagicPeerConnectionWrapper {
 
     public void sendNickChannelData(DataChannelMessageNick dataChannelMessage) {
         ByteBuffer buffer;
-        if (magicDataChannel != null) {
+        if (dataChannel != null) {
             try {
                 buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
-                magicDataChannel.send(new DataChannel.Buffer(buffer, false));
+                dataChannel.send(new DataChannel.Buffer(buffer, false));
             } catch (IOException e) {
                 Log.d(TAG, "Failed to send channel data, attempting regular " + dataChannelMessage);
             }
@@ -191,10 +202,10 @@ public class MagicPeerConnectionWrapper {
 
     public void sendChannelData(DataChannelMessage dataChannelMessage) {
         ByteBuffer buffer;
-        if (magicDataChannel != null) {
+        if (dataChannel != null) {
             try {
                 buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
-                magicDataChannel.send(new DataChannel.Buffer(buffer, false));
+                dataChannel.send(new DataChannel.Buffer(buffer, false));
             } catch (IOException e) {
                 Log.d(TAG, "Failed to send channel data, attempting regular " + dataChannelMessage);
             }
@@ -217,7 +228,7 @@ public class MagicPeerConnectionWrapper {
         if (!TextUtils.isEmpty(nick)) {
             return nick;
         } else {
-            return NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_nick_guest);
+            return Objects.requireNonNull(NextcloudTalkApplication.Companion.getSharedApplication()).getString(R.string.nc_nick_guest);
         }
     }
 
@@ -226,14 +237,14 @@ public class MagicPeerConnectionWrapper {
     }
 
     private void sendInitialMediaStatus() {
-        if (localMediaStream != null) {
-            if (localMediaStream.videoTracks.size() == 1 && localMediaStream.videoTracks.get(0).enabled()) {
+        if (localStream != null) {
+            if (localStream.videoTracks.size() == 1 && localStream.videoTracks.get(0).enabled()) {
                 sendChannelData(new DataChannelMessage("videoOn"));
             } else {
                 sendChannelData(new DataChannelMessage("videoOff"));
             }
 
-            if (localMediaStream.audioTracks.size() == 1 && localMediaStream.audioTracks.get(0).enabled()) {
+            if (localStream.audioTracks.size() == 1 && localStream.audioTracks.get(0).enabled()) {
                 sendChannelData(new DataChannelMessage("audioOn"));
             } else {
                 sendChannelData(new DataChannelMessage("audioOff"));
@@ -254,8 +265,8 @@ public class MagicPeerConnectionWrapper {
 
         @Override
         public void onStateChange() {
-            if (magicDataChannel != null && magicDataChannel.state().equals(DataChannel.State.OPEN) &&
-                    magicDataChannel.label().equals("status")) {
+            if (dataChannel != null && dataChannel.state().equals(DataChannel.State.OPEN) &&
+                    dataChannel.label().equals("status")) {
                 sendInitialMediaStatus();
             }
         }
@@ -292,23 +303,18 @@ public class MagicPeerConnectionWrapper {
                                     .NICK_CHANGE, sessionId, payloadHashMap.get("name"), null, videoStreamType));
                         }
                     }
-
                 } else if ("audioOn".equals(dataChannelMessage.getType())) {
-                    remoteAudioOn = true;
                     EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
-                            .AUDIO_CHANGE, sessionId, null, remoteAudioOn, videoStreamType));
+                            .AUDIO_CHANGE, sessionId, null, TRUE, videoStreamType));
                 } else if ("audioOff".equals(dataChannelMessage.getType())) {
-                    remoteAudioOn = false;
                     EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
-                            .AUDIO_CHANGE, sessionId, null, remoteAudioOn, videoStreamType));
+                            .AUDIO_CHANGE, sessionId, null, FALSE, videoStreamType));
                 } else if ("videoOn".equals(dataChannelMessage.getType())) {
-                    remoteVideoOn = true;
                     EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
-                            .VIDEO_CHANGE, sessionId, null, remoteVideoOn, videoStreamType));
+                            .VIDEO_CHANGE, sessionId, null, TRUE, videoStreamType));
                 } else if ("videoOff".equals(dataChannelMessage.getType())) {
-                    remoteVideoOn = false;
                     EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
-                            .VIDEO_CHANGE, sessionId, null, remoteVideoOn, videoStreamType));
+                            .VIDEO_CHANGE, sessionId, null, FALSE, videoStreamType));
                 }
             } catch (IOException e) {
                 Log.d(TAG, "Failed to parse data channel message");
@@ -316,26 +322,6 @@ public class MagicPeerConnectionWrapper {
         }
     }
 
-    private void restartIce() {
-        if (connectionAttempts <= 5) {
-            if (!hasMCU || isMCUPublisher) {
-                MediaConstraints.KeyValuePair iceRestartConstraint =
-                        new MediaConstraints.KeyValuePair("IceRestart", "true");
-
-                if (sdpConstraints.mandatory.contains(iceRestartConstraint)) {
-                    sdpConstraints.mandatory.add(iceRestartConstraint);
-                }
-
-                peerConnection.createOffer(magicSdpObserver, sdpConstraints);
-            } else {
-                // we have an MCU and this is not the publisher
-                // Do something if we have an MCU
-            }
-
-            connectionAttempts++;
-        }
-    }
-
     private class MagicPeerConnectionObserver implements PeerConnection.Observer {
 
         @Override
@@ -344,16 +330,12 @@ public class MagicPeerConnectionWrapper {
 
         @Override
         public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
-            peerIceConnectionState = iceConnectionState;
 
             Log.d("iceConnectionChangeTo: ", iceConnectionState.name() + " over " + peerConnection.hashCode() + " " + sessionId);
             if (iceConnectionState.equals(PeerConnection.IceConnectionState.CONNECTED)) {
-                connectionAttempts = 0;
-                /*EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
-                        .PEER_CONNECTED, sessionId, null, null));*/
 
                 if (!isMCUPublisher) {
-                    EventBus.getDefault().post(new MediaStreamEvent(remoteMediaStream, sessionId, videoStreamType));
+                    EventBus.getDefault().post(new MediaStreamEvent(remoteStream, sessionId, videoStreamType));
                 }
 
                 if (hasInitiated) {
@@ -363,11 +345,7 @@ public class MagicPeerConnectionWrapper {
             } else if (iceConnectionState.equals(PeerConnection.IceConnectionState.CLOSED)) {
                 EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType
                         .PEER_CLOSED, sessionId, null, null, videoStreamType));
-                connectionAttempts = 0;
             } else if (iceConnectionState.equals(PeerConnection.IceConnectionState.FAILED)) {
-                /*if (MerlinTheWizard.isConnectedToInternet() && connectionAttempts < 5) {
-                    restartIce();
-                }*/
                 if (isMCUPublisher) {
                     EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED, sessionId, null, null, null));
                 }
@@ -401,7 +379,7 @@ public class MagicPeerConnectionWrapper {
 
         @Override
         public void onAddStream(MediaStream mediaStream) {
-            remoteMediaStream = mediaStream;
+            remoteStream = mediaStream;
         }
 
         @Override
@@ -414,8 +392,8 @@ public class MagicPeerConnectionWrapper {
         @Override
         public void onDataChannel(DataChannel dataChannel) {
             if (dataChannel.label().equals("status") || dataChannel.label().equals("JanusDataChannel")) {
-                magicDataChannel = dataChannel;
-                magicDataChannel.registerObserver(new MagicDataChannelObserver());
+                PeerConnectionWrapper.this.dataChannel = dataChannel;
+                PeerConnectionWrapper.this.dataChannel.registerObserver(new MagicDataChannelObserver());
             }
         }
 
@@ -466,7 +444,7 @@ public class MagicPeerConnectionWrapper {
         public void onSetSuccess() {
             if (peerConnection != null) {
                 if (peerConnection.getLocalDescription() == null) {
-                    peerConnection.createAnswer(magicSdpObserver, sdpConstraints);
+                    peerConnection.createAnswer(magicSdpObserver, mediaConstraints);
                 }
 
                 if (peerConnection.getRemoteDescription() != null) {
@@ -475,8 +453,4 @@ public class MagicPeerConnectionWrapper {
             }
         }
     }
-
-    public PeerConnection.IceConnectionState getPeerIceConnectionState() {
-        return peerIceConnectionState;
-    }
 }

+ 2 - 2
scripts/analysis/lint-up.rb

@@ -56,12 +56,12 @@ end
 
 # run Lint
 puts "running Lint..."
-system './gradlew --console=plain clean lintGplayDebug'
+system './gradlew --console=plain lintGplayDebug'
 
 # confirm that Lint ran w/out error
 result = $?.to_i
 if result != 0
-    puts "FAIL: failed to run ./gradlew --console=plain clean lintGplayDebug"
+    puts "FAIL: failed to run ./gradlew --console=plain lintGplayDebug"
     exit 1
 end