mirror of
https://github.com/nextcloud/talk-android
synced 2025-03-07 06:39:45 +00:00
Merge pull request #1774 from nextcloud/feature/1773/update-webrtc-library
Android update WebRTC library
This commit is contained in:
commit
89f64b392a
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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 final MediaConstraints mediaConstraints;
|
||||
private DataChannel dataChannel;
|
||||
private final MagicSdpObserver magicSdpObserver;
|
||||
private MediaStream remoteStream;
|
||||
|
||||
private boolean remoteVideoOn;
|
||||
private boolean remoteAudioOn;
|
||||
private final boolean hasInitiated;
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user